코드 내에서 변수 사용 일반화


11

변수를 일반화하는 것이 좋은 방법인지 알고 싶습니다 (모든 변수를 저장하기 위해 단일 변수 사용).
간단한 예를 고려하십시오

 Strings querycre,queryins,queryup,querydel; 
    querycre = 'Create table XYZ ...';
    execute querycre ;
    queryins = 'Insert into XYZ ...';
    execute queryins ;
    queryup  = 'Update  XYZ set ...';
    execute queryup;
    querydel = 'Delete from XYZ ...';
    execute querydel ;

 Strings query; 
    query= 'Create table XYZ ... ';
    execute query ;
    query= 'Insert into XYZ ...';
    execute query ;
    query= 'Update  XYZ set ...';
    execute query ;
    query= 'Delete from XYZ ...';
    execute query ;

첫 번째 경우에는 접미사에 언급 된 작업을 수행하기 위해 각각 데이터를 저장하는 4 개의 문자열을 사용합니다.
두 번째 경우에는 모든 종류의 데이터를 저장하는 변수가 1입니다.
다른 변수를 사용하면 다른 사람이 더 쉽게 읽고 이해할 수 있습니다. 그러나 너무 많으면 관리하기가 어렵습니다.

또한 변수가 너무 많으면 성능이 저하됩니까?

추신 : 예를 들어 코드를 wrt에 대답하지 마십시오. 실제로 의미하는 것을 전달하는 것이 었습니다.


물론 함수에서 변수를 정의했기 때문에 동일한 변수를 재사용 할 수 있습니다. 그것이 바로 기능입니다.
zzzzBov

답변:


26

자신 에게이 질문을하는 것은 당신이 DRY를 따르지 않는 아주 강한 냄새입니다 (반복하지 마십시오). 가상의 중괄호 언어로 이것을 가지고 있다고 가정하십시오.

function doFoo() {
    query = "SELECT a, b, c FROM foobar WHERE baz = 23";
    result = runQuery(query);
    print(result);

    query = "SELECT foo, bar FROM quux WHERE x IS NULL";
    result = runQuery(query);
    print(result);

    query = "SELECT a.foo, b.bar FROM quux a INNER JOIN quuux b ON b.quux_id = a.id ORDER BY date_added LIMIT 10";
    result = runQuery(query);
    print(result);
}

그것을 다음과 같이 리팩터링하십시오.

function runAndPrint(query) {
    result = runQuery(query);
    print(result);
}

function doFoo() {
    runAndPrint("SELECT a, b, c FROM foobar WHERE baz = 23");
    runAndPrint("SELECT foo, bar FROM quux WHERE x IS NULL");
    runAndPrint("SELECT a.foo, b.bar FROM quux a INNER JOIN quuux b ON b.quux_id = a.id ORDER BY date_added LIMIT 10");
}

다른 변수를 사용할지 여부를 결정해야하는 필요성이 사라지고, 동일한 수정을 세 번 적용하지 않고 쿼리를 실행하고 결과를 한 곳에서 인쇄하기위한 논리를 변경하는 방법에 주목하십시오. 예를 들어 쿼리 결과를 바로 인쇄하지 않고 템플릿 시스템을 통해 펌핑하기로 결정할 수 있습니다.


2
나는 단지 DRY 원칙을 좋아한다 :)
artjom

1
@tdammers는 함수 안에 두 줄의 코드를 갖는 것이 좋습니까?이 함수를 가지고 있다면 고려하십시오 doFoo () {print (runQuery ( "Selct a, b, c from XYZ"));}
Shirish11

1
아니오, 호출 스택은 증가하지 않습니다. 호출 할 runAndPrint때 마다 하나의 스택 프레임 을 푸시 한 다음 함수가 종료되면 다시 호출합니다. 세 번 호출하면 세 번의 푸시 / 팝 쌍을 수행하지만 스택은 한 번에 두 프레임 이상 증가하지 않습니다. 재귀 함수로 호출 스택 깊이에 대해서만 걱정할 필요가 있습니다.
tdammers 2016 년

3
두 줄의 코드 만있는 함수는 완벽합니다. 두 줄이 논리 단위를 만들면 두 줄입니다. 나는 약간의 정보를 격리하고 한 곳에 보관하기 위해 많은 한 줄짜리 함수를 작성했습니다.
tdammers 2016 년

1
@JamesAnderson : 다소 고안된 예이지만 요점을 설명해줍니다. 얼마나 많은 코드 줄이 있는지에 관한 것이 아닙니다. 같은 사실을 몇 번이나 말합니까. 그것이 바로 진실의 단일 근원 원칙, 복사 할 수없는 붙여 넣기 규칙 등과 같은 DRY에 관한 것입니다.
tdammers

14

일반적으로 이것은 나쁜 습관입니다.

변수를 재사용하면 이런 방식으로 이해하기 어려운 코드를 만들 수 있습니다.

코드를 읽는 사람들은 그런 식으로 변수를 재사용 할 것으로 기대하지 않으며 시작시에 설정된 값이 함수의 끝에서 다른 값을 갖는 이유를 알지 못할 것입니다.

게시 한 예제는 매우 간단하고 실제로이 문제로 고통받지는 않지만 변수를 재사용하는 일부 코드를 대표하지는 않습니다 (시작 부분에서 설정되고 보이지 않는 곳에서 재사용됩니다).

당신이 제공 한 예제는 함수를 캡슐화하여 쿼리를 전달하고 실행할 수 있도록합니다.


시스템 성능은 어떤 영향을 받습니까?
Shirish11

@ Shirish11-그렇습니다. 컴파일러, 언어, 환경 및 기타 변수에 따라 다릅니다.
Oded

일반적으로 컴파일러는이를 최적화하는 데 능숙합니다. 그러나 항상 컴파일러 / 플랫폼 / 특정 사례 / 구성에 따라 다릅니다.
deadalnix

7

자체 문서화 된 코드로 더 쉽게 읽고 유지 관리

최소 놀랍게도원칙코드 그대로 의 교훈을 따르십시오 하나의 목표에 하나의 변수 만 사용하면 이해하기 쉽고 설명없이 코드를 쉽게 읽을 수 있습니다.

올바르게 구조화 된 코드는 사용하기 쉬워지고 (더 저렴합니다)

또한 여기에서는 query명령문을 실행하기 전에 항상 준비하는 데 사용되는 것으로 보입니다 . 아마도이 코드의 일부를 하나 이상의 도우미 메서드리팩터링 하여 쿼리를 준비하고 실행하기위한 것입니다 ( DRY 원칙 준수 ).

이렇게하면 효과적으로 다음을 수행 할 수 있습니다.

  • 헬퍼 메소드에서 하나의 변수 만 사용하여 현재 컨텍스트의 쿼리를 식별하십시오.
  • 검색어를 다시 실행할 때마다 더 적은 코드를 입력해야합니다.
  • 다른 사람이 코드를 더 읽기 쉽게 만듭니다.

예 :

리팩토링 된 버전이 분명히 더 나은 예제에서 가져온 것을 고려하십시오. 물론 스 니펫은이 질문의 목적을위한 예시 일 뿐이지 만이 개념은 여전히 ​​사실이며 규모를 유지합니다.

예 1 :

Strings querycre,queryins,queryup,querydel; 
    querycre = 'Create table XYZ ...';
    execute querycre ;
    queryins = 'Insert into XYZ ...';
    execute queryins ;
    queryup  = 'Update  XYZ set ...';
    execute queryup;
    querydel = 'Delete from XYZ ...';
    execute querydel ;

예 2 :

 Strings query; 
    query= 'Create table XYZ ...';
    execute query ;
    query= 'Insert into XYZ ...';
    execute query ;
    query= 'Update  XYZ set ...';
    execute query ;
    query= 'Delete from XYZ ...';
    execute query ;

예 3 (리팩토링 된 의사 코드) :

def executeQuery(query, parameters...)
    statement = prepareStatement(query, parameters);
    execute statement;
end

// call point:
executeQuery('Create table XYZ ... ');
executeQuery('Insert into XYZ ...');
executeQuery('Update  XYZ set ...');
executeQuery('Delete from XYZ ...');

혜택은 정기적 인 재사용으로 나타납니다.

개인 일화

원래는 제한된 화면 부동산으로 작업하는 C 프로그래머로 시작했기 때문에 변수를 재사용하면 컴파일 된 코드 (이전)와 더 많은 코드를 한 번에 읽을 수있게했습니다.

그러나 고급 언어로 넘어 가고 함수형 프로그래밍을 다듬어 부작용을 제한하기 위해 불변 변수와 불변 참조를 사용하는 습관을 들었습니다.

나를 위해 무엇이 들어 있습니까?

모든 함수의 입력을 변경할 수없는 습관을 가지고 새로운 수학 결과와 같이 새로운 결과를 반환하는 경우 상점을 복제하지 않는 습관을 들이게됩니다.

확장하면 다음과 같습니다.

  • 짧은 기능을 쓰고
  • 잘 정의 된 목표로
  • 이해하기 쉬워요
  • 재사용하기 위해
  • 확장 (OO 상속 또는 기능 체인에 의한 여부)
  • 그리고 문서 (이미 자체 문서화).

나는 여기서 변경 가능한 상태에 이점이 없다고 말하는 것이 아니라, 습관이 당신에게 어떻게 자랄 수 있고 그것이 코드 가독성에 어떻게 영향을 미치는지 지적하고 있습니다.


2

코드 디자인 측면에서

일반적으로 변수를 재사용하여 다른 값을 저장하는 것이 좋습니다. 결국 값이 같은 유형일뿐만 아니라 동일한 것을 의미하는 한 변수에 저장된 값이 다양하기 때문에 변수라고하는 이유가 있습니다 . 예를 들어 currentQuery여기서 변수 를 재사용해도됩니다 .

for currentQuery in queries:
    execute query;

당연히 루프가 있으므로 변수를 재사용 해야 하지만 루프가 없었더라도 괜찮을 것입니다. 값이 같은 의미 가 아닌 경우 별도의 변수를 사용하십시오.

그러나 구체적 으로 설명하는 코드는보기에 좋지 않습니다. . . 루프 또는 도우미 메서드 호출 (또는 둘 다)을 사용하는 것이 훨씬 좋습니다. 개인적으로 나는 첫 번째 또는 두 번째 버전처럼 보이는 프로덕션 코드를 거의 보지 못했지만, 가지고있는 경우 두 번째 버전 (가변 재사용)이 더 일반적이라고 생각합니다.

성능면에서

사용되는 언어, 컴파일러 및 런타임 시스템에 따라 다르지만 일반적으로 차이는 없어야합니다 . 특히 스택 기반 레지스터 시스템 (일반적인 x86 / x86-64 등)의 컴파일러는 어쨌든 동일한 변수를 원하는지 여부를 완전히 무시하고 사용 가능한 스택 메모리 또는 레지스터를 할당 대상으로 등록하십시오.

예를 들어, gcc -O2정확히 같은 바이너리를 생성하고 내가 아는 유일한 성능 차이는 컴파일하는 동안 심볼 테이블의 크기뿐입니다. 60 년대로 돌아 가지 않으면 완전히 무시할 수 있습니다.

Java 컴파일러는 첫 번째 버전을 위해 더 많은 스토리지가 필요한 바이트 코드를 생성하지만 JVM의 지터는이를 제거하므로 다시 최적화하면 코드가 최적화되어 있어도 눈에 띄는 성능 영향이 없을 것입니다.


0

나는 변수를 재사용하는 것이 대부분 좋다고 생각합니다.

나를 위해 쿼리 변수를 대부분 재사용합니다. 거의 항상 쿼리를 실행합니다. 쿼리를 즉시 실행하지 않으면 일반적으로 다른 변수 이름을 사용합니다.


-1

컴파일러가 특히 바보 인 경우 스택 사용량을 늘릴 수 있습니다. 개인적으로 각 쿼리마다 별도의 변수를 갖는 것이 가독성을 높이는 것으로 생각하지 않지만 실제로는 쿼리 문자열을보고 실제로 무엇을하는지 알아야합니다.


독자들이 내가 원하는 것을 더 쉽게 이해할 수 있도록 간단한 예를 제공했습니다. 내 코드는 이것보다 훨씬 복잡합니다.
Shirish11

-2

이 예에서는 두 번째 예를 살펴 보겠습니다. 독자와 옵티 마이저 모두 자신이하고있는 일이 분명합니다. 첫 번째 예제는 조금 더 적절하고 다소 복잡한 코드로 사용하지만 다음과 같이하십시오.

{
    String query = 'Create table XYZ ...';
    execute query;
}
{
    String query = 'Insert table XYZ ...';
    execute query;
}
And so on...

(이 시점에서, 나는 tdammers의 솔루션을 고려할 수 있습니다 .)

첫 번째 예의 문제점 querycre은 전체 블록에 대한 범위이며 광범위 할 수 있다는 것입니다. 코드를 읽는 사람을 혼동시킬 수 있습니다. 또한 옵티 마이저를 혼동하여 불필요한 메모리 쓰기가 남을 querycre수 있으므로 필요할 경우 나중에 사용할 수 있습니다 (그렇지 않은 경우). 모든 중괄호와 함께 query레지스터에만 저장됩니다.

"Create table"및 "execute"와 같은 문구를 사용하면 여기에 여분의 메모리 쓰기가 표시되는 것처럼 보이지 않으므로 독자를 혼란스럽게하는 코드 만 잘못 판단합니다. 그러나 속도 중요한 곳에서 코드를 작성하는 경우이 점을 알고 있으면 편리합니다 .


동의하지 않습니다. 명확성을 위해 두 번째 예제를 선호하려면 도우미 메소드에 대한 연속 호출로 리팩토링해야합니다. 더 큰 의미를 전달하며 코드가 덜 필요합니다.
haylem

@haylem : 이와 같은 간단한 경우에는 코드를 읽는 사람이 찾아야하는 도우미 메서드를 추가하고 있습니다. (그리고 누군가는 도우미 메소드에 문제가있을 수 있으며 호출 된 모든 장소를 찾아야합니다.) 같은 양의 코드에 대해서는 명확성이 떨어집니다. 더 복잡한 경우에는 솔루션과 함께 tdammer 와 함께 갈 것입니다 . 나는이 질문에 주로 사용 된 변수가 인간과 옵티 마이저 모두에게 제기되는 (거의 모호하지만 흥미로운) 문제를 지적하기 위해 대답했다.
RalphChapin

@ haylem : 당신과 tdammer는 모두 올바른 해결책을 제시합니다. 어떤 경우에는 과잉 일 수 있다고 생각합니다.
RalphChapin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.