변수를 재사용해야합니까?


59

변수를 재사용해야합니까?

나는 많은 모범 사례가 그렇게해서는 안된다는 것을 알고 있지만 나중에 다른 개발자가 코드를 디버깅하고 유사하게 보이는 3 개의 변수를 가질 때 유일한 차이점은 코드의 다른 위치에서 생성된다는 것입니다. 혼란스러운. 단위 테스트는 이에 대한 좋은 예입니다.

그러나, 나는 모범 사례가에 대한 대부분의 시간을 것을 알고있다. 예를 들어, 메소드 매개 변수를 "재정의"하지 말라고합니다.

모범 사례는 이전 변수를 무효화하는 것입니다 (Java에는 null변수에 할당 할 때 경고를 표시하는 Sonar가 있으며 Java 6 이후 가비지 수집기를 호출 할 필요가 없음) 항상 제어 할 수는 없습니다 어떤 경고가 꺼 졌는지, 대부분의 경우 기본값이 켜져 있습니다.)


11
Java 6부터? Java의 모든 버전에서 변수에 널을 지정할 필요가 없습니다. 변수가 범위를 벗어나면 해당 객체에 대한 참조가 해제됩니다.
케빈 판코

35
변수의-사용하고하면 해당 코드 난독 사용하는 첫 번째 일은 중 하나입니다
를르슈 람 페르 지

7
변수 재사용은 변수의 적절한 식별자 선택과 충돌합니다. 현대 언어에서는 변수 재사용에있어 좋은 식별자를 갖는 것의 이점보다 더 큰 이점은 실제로 없습니다.
Joren

4
또한 모든 재사용이 재사용이 아니라는 점에 유의하십시오. 기존 FORTRAN 프로그래머, 다른 언어로 표류 한 프로그래머조차도 모든 DO- 루프에 대해 I, J, K, L, M, N (또는 i, j, k, l, m, n)을 일상적으로 사용합니다 루프) 카운터. 우리는 SUM = SUM + A (I, K) * B (K, J) 또는 sum + = a [i] [k] * b [k] [j];와 같은 것을 보는 데 익숙합니다.
John R. Strohm

1
매우 제한된 리소스 (몇 킬로바이트의 RAM)로 마이크로 컨트롤러를 프로그래밍 할 때 변수 재사용이 정당화 될 수 있습니다.
m.Alin

답변:


130

문제는 방법이 길고 여러 작업을 순서대로 수행하는 경우에만 나타납니다. 이로 인해 코드 자체를 이해하기 어려워집니다. 변수를 재사용하면 위험 요소가 추가되어 코드를 따르기가 더 어려워지고 오류가 발생하기 쉽습니다.

IMO 모범 사례는 한 가지만 수행 할 수있는 짧은 방법을 사용하여 전체 문제를 해결하는 것입니다.


단위 테스트는 어떻습니까? 예를 들어 메소드를 두 번째로 실행 한 후에도 여전히 예상대로 작동하는지 테스트해야합니다.
IAdapter

20
@IAdapter, 단위 테스트 코드는 생산 코드보다 표준이 완화되는 다른 문제입니다. 그러나 읽기 쉽고 유지 관리하기 쉬운 것이 최우선 과제입니다. 당신은 (그리고해야) 할 수 방법을 추출 할 뿐만 아니라, 단위 테스트에서를 짧고 읽기 (변수를 재사용 할 필요성을 제거하기) 쉬운을 유지.
Péter Török

3
@IAdapter, 당신이 설명한 시나리오 에서 변수를 재사용 하지 않을 것입니다. 적절한 것은 result1 = foo(); result2 = foo(); Assert.AreEqual(result1, result2);내가이 경우 변수를 재사용해야 할 곳이 많이 보이지 않는 것과 같은 것입니다 .
JSB ձոգչ

1
@IAdapter for (int i = 0; i <2; i ++) {result = foo (); assertEquals (expectedResult, result);}
Bill K

2
+1-더 작은 방법을 만들 때 좋은 코드 냄새입니다.

49

메소드의 변수 재사용은 리팩토링 / 분할해야한다는 강력한 신호입니다.

내 대답은 재사용하지 않아야한다는 것입니다. 그렇다면 나중에 리팩터링하는 것이 훨씬 어려울 것입니다.


19

따라 다릅니다.

일부 변수는 특정 유형의 데이터를 보유하기 위해 정확하게 작성 될 수 있으며, 함수 실행 중에 변경 될 수 있습니다. 예를 들어 리턴 코드는 다음과 같습니다.

void my_function() {
    HRESULT errorcode;
    errorcode = ::SomeWindowsApiFunction();
    if (FAILED(errorcode)) { /* handle error */ }
    errorcode = ::AnotherWindowsApiFunction();
    if (FAILED(errorcode)) { /* handle error */ }
}

변수 이름을 사용하면이 변수가 무엇을 저장하려고하는지 명확하게 알 수 있습니다. 나는 이것과 같은 다른 유스 케이스가 가능하다고 생각합니다. 변수는 개념적으로 함수 과정에서 매우 유사한 것들의 다른 인스턴스에 의해 논리적으로 사용되는 컨테이너입니다.

그러나 일반적으로 이는 가능한 코드 독자에게 분명한 상황에서만 수행해야합니다. 코드 가독성에 관계없이 극단적 인 최적화를 제외하고는 유형이 적합하기 때문에 변수를 재사용해야합니다.

이 모든 것은 기본적으로 변수 명명의 우수 사례에서 비롯됩니다. 이름은 스스로 말해야합니다. 모든 재사용에 대한 정확한 목적을 짧은 이름으로 작성하기 어려운 경우, 고유 한 변수를 사용하는 것이 가장 좋습니다.


15

변수를 재사용하지 않는 가장 큰 이유는 (특히 단위 테스트에서) 테스트 및 디버그하기 어려운 불필요한 코드 경로를 도입하기 때문입니다. 좋은 단위 테스트는 다른 테스트와 독립적이어야하며 단위 테스트 픽스처에서 클래스 (인스턴스) 레벨 변수를 재사용 할 때 각 테스트 전에 해당 상태를 확인해야합니다. 우수한 단위 테스트는 결함을 분리하기 때문에 이론적으로 각 테스트 케이스 (방법)는 테스트중인 시스템에 대해 1 개의 동작 만 가정해야합니다. 테스트 메소드가 이와 같이 작성되면 메소드 레벨 변수를 재사용 할 필요가 거의 없습니다. 마지막으로 클로저 및 비동기 처리를 지원하는 언어에서는 메서드 전체에서 변수를 재사용하는 경우 대체 무슨 일이 일어나고 있는지 추론하기가 어렵습니다.


그래서 -testSomething과 같은 테스트 메소드를 작성하고 단일 메소드 호출에 대한 assert -testSomethingTwoInvocations와 두 번째 호출에 대해서만 assert?
IAdapter

2
예. 실패한 첫 번째 또는 두 번째 반복인지 정확하게 찾아 낼 수 있습니다. mspec이 이것을 도울 수 있습니다. 상속 트리는 매우 유용합니다.
Bryan Boettcher

"class variable"또는 "instance variable"을 의미 할 때 "variable"을 사용하는 경우보다 명확하게 표현해야합니다.
gnasher729

13

다른 변수를 사용해야합니다. 동료가 혼란스러워 질 까봐 걱정되는 경우, 자신의 역할을 명확하게 설명하는 이름을 지정하십시오.
변수 재사용은 향후 혼란의 원인이 될 수 있습니다. 지금 정리하는 것이 좋습니다.
경우에 따라 동일한 변수 이름을 재사용 할 수 있습니다. 예를 들어 i간단한 계산 루프에서. 이러한 경우 변수가 자체 범위 내에 있는지 확인해야합니다.

편집 : 변수 재사용은 때로는 단일 책임 원칙 을 위반했다는 신호입니다. 재사용 된 변수가 동일한 역할에서 사용되는지 확인하십시오. 그렇다면 전혀 재사용되지 않을 수도 있습니다 (그러나 두 변수를 갖는 것이 바람직하지만, 상기 변수의 범위를 제한하는 것이 바람직합니다). 다른 역할로 사용되는 경우 SRP 위반이 발생합니다.


4

컴파일러가 도움을 필요로 할 때 다른 답변에서 제공 한 훌륭한 조언에 관계없이 변수를 재사용 할 수있는 상황이 있습니다.

경우에 따라 컴파일러는 특정 레지스터 할당 변수가 코드의 다음 부분에서 더 이상 사용되지 않는다는 것을 인식하기에 영리하지 않을 수 있습니다. 따라서 이론적으로 다음 변수에 대한 프리 레지스터를 재사용하지 않으며 생성 된 코드가 차선책 일 수 있습니다.

이 상황을 올바르게 포착하지 못하는 현재의 주류 컴파일러는 알지 못하므로 컴파일러가 최적의 코드를 생성하지 않는다는 사실을 모르면 절대로 그렇게하지 마십시오. 사용자 정의 컴파일러를 사용하여 특수 임베디드 시스템을 컴파일하는 경우 여전히이 문제가 발생할 수 있습니다.


17
실제로 이런 상황이 발생하고 변수를 재사용하면 상당한 차이가 나는 실제 상황을 가리킬 수 없으면 -1입니다. 이것은 이론적 문제에 대한 이론적 해결책이며 그에 대한 좋은 해결책은 아닙니다. 컴파일러가 변수를 넣기로 결정한 곳은 컴파일러의 관심사입니다. 컴파일러에서 잘못된 코드를 생성하고 실제로 차이가 발생하면 컴파일러를 수정하거나 교체하십시오.
Caleb

3
@Caleb-개발중인 플랫폼, 특히 전용 임베디드 플랫폼의 컴파일러 소스 코드에 항상 액세스 할 수있는 것은 아닙니다. 또한 DID 내가 어떤 현재 주류 컴파일러 알고있는 (또는 사실 통역 / VM을) 정확하게 내가 검토 한 모든 경우에이 생동감 분석을 수행하지하지 않는 내 대답에 말한다. 그러나, 나는 매우 과거에 빈약 한 (10 년 전 정도)이었다 정의 컴파일러로 전용 임베디드 시스템에서 일했다. 시스템은 기능이 매우 제한되어 있었고 컴파일러도 마찬가지 였으므로 이런 상황이 발생했습니다.
Joris Timmermans

2
+1 과거 프로젝트 (ANSI C로 작성된 매우 최적화 된 미디어 코드)에서 정확하게 재사용했습니다. 제가 기억하는 한, 차이점은 어셈블리에서 쉽게 볼 수 있었고 벤치 마크에서 측정 할 수있었습니다. 결코 그렇게하지 않았 으면 좋겠다. Java에서 재사용 할 필요는 없다.
gnat

@Caleb 컴파일러를 수정하거나 교체하는 것은 여러 가지 이유로 옵션이 아닐 수 있으며 단순히 가지고있는 것과 관련이 있어야합니다.

@ ThorbjørnRavnAndersen는인가 생각할 수있는 하나는 형편없는 컴파일러를 사용하도록 강요 할 수도 있고, 또한 성능이 당신이 두 번째 컴파일러를 추측하고 레지스터를 재사용하기 위해 코드를 조작해야하는만큼 중요 할 수 있음? 예. 그럴 가능성이 있습니까? MadKeithV는 실제 사례를 제시 할 수 없다는 데 동의합니다. 그것은인가 가장 좋은 방법은 ? 그것은가 좋은 스타일 ? 코드 품질 의 지표 입니까? 기필코 아니다. 이것은 쓰여진 질문에 유용한 답입니까? MadKeithV를 존중하지만, 나는 그렇게 생각하지 않습니다.
Caleb

2

나는 아니오라고 말할 것입니다.

이 시나리오에 대해 생각해보십시오. 프로그램이 중단되었으며 코어 덤프를 검사하여 발생한 문제를 해결해야합니다. 차이점을 알 수 있습니까? ;-)


코어 덤프가 최적화 된 빌드 인 경우 변수가 메모리를 공유 할 수 있습니다. 따라서 도움이 덜 될 것입니다.
Winston Ewert

물론 최적화 된 빌드는 디버깅에 그다지 유용하지 않습니다! 그러나 어쨌든 디버그 빌드를 사용할 수있는 옵션이 있습니다 ... 디버거가 연결되어 있으면 함수 시작 부분에서 단계별로 이동할 필요가 없습니다. 변수가 어떻게 변경되는지 확인하십시오. 하지마! :-D
fortran

2

아니요, 기계가 실행중인 코드 (... 어셈블리 코드)를 개선하지 않습니다. 컴파일러가 변수에 컴파일러에 사용하는 모든 메모리를 재사용하십시오. 종종 레지스터가 될 것이고 재사용하면 아무것도 얻지 못했습니다. 코드를 읽기 쉽게 만드는 데 집중하십시오.


0

따라 다릅니다. 변수가 아닌 값에 유형이있는 동적 언어에서, 예를 들어 문자열과 같은 함수에 대한 잘 알려진 인수가있는 경우. 나는 알고리즘의 변화가 정수로 해석 된 후에 항상 사용되었다는 것을 의미했으며, 첫 번째 초안으로

scrote = int (스크 로트)

그러나 결국 함수에 전송 된 유형을 변경하고 매개 변수 유형의 변경 사항을 확인하려고합니다.


1
긴 코드 배치 중간에 "scrote = int (scrote)"와 같은 줄을 추가하면 유지 보수 프로그래머를 미치게하는 좋은 방법입니다.
jhocking

언급 한 "긴 코드 묶음"문제 일 가능성이 높습니다.
Paddy3118

허용 된 답변 노트뿐만 아니라 변수 재사용은 실제로 긴 코드 배치의 문제 일뿐입니다. 기본적으로 "scrote = int (scrote)"와 같은 것을 쓰는 상황에서는 int (scrote)를 새 변수에 넣거나 int (scrote)를 새 함수에 전달하는 것이 좋습니다.
jhocking

0

먼저 개발 환경을 살펴보십시오. 동일한 이름을 가진 서로 다른 범위에 5 개의 변수가있어 디버깅에 문제가 있고 디버거가 이러한 변수 중 필요한 변수를 표시하지 않으면 같은 이름을 가진 5 개의 변수를 사용하지 마십시오. 이를 달성하는 두 가지 방법이 있습니다. 하나의 변수를 사용하거나 다섯 개의 다른 이름을 사용하십시오.

디버거는 또한 많은 변수를 가진 함수를 디버깅하는 것을 어렵게 만들 수 있습니다. 변수가 20 개인 함수가 변수가 16 개인 함수보다 디버깅하기 어려운 경우 5 개의 변수를 하나로 대체하는 것을 고려할 수 있습니다. ( "고려해야 할 수도있다"는 "항상해야한다"와는 다릅니다.

변수의 목적이 항상 동일한 한 여러 위치에서 하나의 변수를 사용하는 것이 좋습니다. 예를 들어, 10 개의 함수 호출이 각 호출에 대해 즉시 처리되는 오류 코드를 리턴하면 10이 아닌 하나의 변수를 사용하십시오. 그러나 완전히 다른 것에는 동일한 변수를 사용하지 마십시오. 고객 이름으로 "name"을 사용하고 나중에 회사 이름으로 동일한 변수를 사용하는 10 줄을 사용하는 것처럼 나쁘고 문제가 발생할 수 있습니다. 더 나쁜 것은 고객 이름으로 "customerName"을 사용하고 회사 이름으로 동일한 변수 "customerName"을 사용하는 10 행 후에 사용하는 것입니다.

중요한 것은 철 규칙이 아닙니다. 모든 것이 장단점이 있습니다. "모범 사례"가 한 가지를 제안하고 특정 상황에서 나쁜 생각이라고 말할 이유가 있다면 그렇게하지 마십시오.


0

먼저 개발 환경을 살펴보십시오. 동일한 이름을 가진 서로 다른 범위에 5 개의 변수가있어 디버깅에 문제가 있고 디버거가 이러한 변수 중 필요한 변수를 표시하지 않으면 같은 이름을 가진 5 개의 변수를 사용하지 마십시오. 이를 달성하는 두 가지 방법이 있습니다. 하나의 변수를 사용하거나 다섯 개의 다른 이름을 사용하십시오.

디버거는 또한 많은 변수를 가진 함수를 디버깅하는 것을 어렵게 만들 수 있습니다. 변수가 20 개인 함수가 변수가 16 개인 함수보다 디버깅하기 어려운 경우 5 개의 변수를 하나로 대체하는 것을 고려할 수 있습니다. ( "고려해야 할 수도있다"는 "항상해야한다"와는 다릅니다.

변수의 목적이 항상 동일한 한 여러 위치에서 하나의 변수를 사용하는 것이 좋습니다. 예를 들어, 10 개의 함수 호출이 각 호출에 대해 즉시 처리되는 오류 코드를 리턴하면 10이 아닌 하나의 변수를 사용하십시오. 이것에는 한 가지 문제점이 있습니다. 일반적으로 컴파일러는 초기화되지 않은 변수를 사용할 때 알려줍니다. 그러나 여기에서 호출 6 후에 오류 코드를 읽었지만 호출 5 후에 변수가 실제로 변경되지 않은 경우 컴파일러에서 경고하지 않고 쓸모없는 데이터를 얻습니다. 변수가 초기화되었으므로 이제는 쓸모없는 데이터가 사용됩니다.

중요한 것은 철 규칙이 아닙니다. 모든 것이 장단점이 있습니다. "모범 사례"가 한 가지를 제안하고 특정 상황에서 나쁜 생각이라고 말할 이유가 있다면 그렇게하지 마십시오.


-2

상태를 유지하거나 상수를 저장해야 할 경우 전역 변수를 사용하십시오. 변수를 재사용하면 메모리의 위치를 ​​가리키는 이름 만 재사용합니다. 초기화에 대한 설명적인 이름은 명확성을 얻을 수 있습니다 (Java를 가정하고 기본 OCD를 가정하지 않음).

직접 코드를 난독 처리하거나 다른 개발자를 자극하지 않는 한.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.