프로그래머는 자신의 코드를 "문서화"하기 위해 부울 변수를 사용해야합니까?
저는 McConell의 Code Complete를 읽고 있으며 그는 부울 변수를 사용하여 코드를 문서화하는 방법에 대해 설명합니다. 예를 들어 다음 대신 :
if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) ||
(elementIndex == lastElementIndex)){
...
}
그는 다음과 같이 제안합니다.
finished = ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
repeatedEntry = (elementIndex == lastElementIndex);
if(finished || repeatedEntry){
...
}
이것은 저에게 논리적이고 좋은 관행이며 매우 자기 문서화라는 인상을줍니다. 그러나 나는 거의 본 적이 없기 때문에이 기술을 정기적으로 사용하는 것을 주저합니다. 희귀하다는 이유로 혼란 스러울 수도 있습니다. 그러나 내 경험은 아직 그다지 방대하지 않기 때문에이 기술에 대한 프로그래머의 의견을 듣고 싶습니다. 누군가이 기술을 정기적으로 사용하는지 아니면 코드를 읽을 때 자주 본 적이 있는지 알고 싶습니다. 이것이 채택 할 가치있는 컨벤션 / 스타일 / 기술입니까? 다른 프로그래머가 이해하고 감사할까요, 아니면 이상하다고 생각할까요?
너무 중첩되고 복잡한 표현식을 지역 변수에 할당 된 더 간단한 하위 표현식으로 분할 한 다음 다시 결합하는 것은 매우 일반적이고 널리 사용되는 기술입니다. 하위 표현식 및 / 또는 전체 표현식이 부울인지 여부와는 무관하게 다른 유형에 대해. 잘 선택된 이름을 사용하면 이런 종류의 세련된 분해가 가독성을 높일 수 있으며, 좋은 컴파일러는 원래의 복잡한 표현과 동등한 코드를 생성하는 데 문제가 없어야합니다.
Haskell과 같이 그 자체로 "할당"이라는 개념이없는 일부 언어는 "부 표현식에 이름 제공"기법 ( where
하스켈 의 절) 을 사용할 수 있도록 특수 구조를 도입 하기도합니다. 문제의 기술에 대한 인기!-)
일반적으로 부울 논리를 재사용 가능한 메서드로 래핑하지만 (여러 위치에서 호출되는 경우) 사용했습니다.
가독성을 높이고 논리가 변경되면 한 곳에서만 변경하면됩니다.
다른 사람들은 그것을 이해하고 이상하게 생각하지 않을 것입니다 (즉, 천 개의 줄 함수 만 작성하는 사람들을 제외하고).
가능한 한 그렇게하려고합니다. 물론, 코드의 "추가 라인"을 사용하고 있지만 동시에 두 값을 비교하는 이유를 설명하고 있습니다.
귀하의 예에서 저는 코드를보고 "좋아요 왜 값을 보는 사람이 0 미만입니까?"라고 자문합니다. 두 번째에서 당신은 이것이 발생했을 때 일부 프로세스가 완료되었음을 분명히 말하고 있습니다. 두 번째 질문에서는 당신의 의도가 무엇인지 추측하지 마십시오.
저에게 가장 큰 것은 다음과 같은 방법을 볼 때 DoSomeMethod(true);
입니다. 자동으로 true로 설정되는 이유는 무엇입니까? 다음과 같이 훨씬 더 읽기 쉽습니다.
bool deleteOnCompletion = true;
DoSomeMethod(deleteOnCompletion);
제공된 샘플 :
finished = ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
repeatedEntry = (elementIndex == lastElementIndex);
if(finished || repeatedEntry){
...
}
가독성을 높이고 부울 논리를 보존하는 메서드를 사용하도록 다시 작성할 수도 있습니다 (Konrad가 지적했듯이).
if (IsFinished(elementIndex) || IsRepeatedEntry(elementIndex, lastElementIndex)){
...
}
...
private bool IsFinished(int elementIndex) {
return ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
}
private bool IsRepeatedEntry(int elementIndex, int lastElementIndex) {
return (elementIndex == lastElementIndex);
}
물론 두 가지 추가 방법 인 대가가 따릅니다. 이 작업을 많이 수행하면 코드를 더 읽기 쉽게 만들 수 있지만 클래스의 투명성은 떨어집니다. 그러나 다시 추가 메서드를 도우미 클래스로 이동할 수도 있습니다.
이것이 잘못되는 것을 볼 수있는 유일한 방법은 부울 조각에 의미가있는 이름이없고 어쨌든 이름이 선택되는 경우입니다.
//No clue what the parts might mean.
if(price>0 && (customer.IsAlive || IsDay(Thursday)))
=>
first_condition = price>0
second_condition =customer.IsAlive || IsDay(Thursday)
//I'm still not enlightened.
if(first_condition && second_condition)
"모든 코드에 주석 달기", "3 개 이상의 부분이있는 모든 if- 기준에 명명 된 부울 사용"과 같은 규칙을 만드는 것이 일반적이기 때문에 다음과 같은 종류의 의미 상 비어있는 주석 만 가져 오는 것이 일반적이기 때문입니다.
i++; //increment i by adding 1 to i's previous value
이렇게함으로써
finished = ((elementIndex < 0) || (MAX_ELEMENTS < elementIndex));
repeatedEntry = (elementIndex == lastElementIndex);
if(finished || repeatedEntry){
...
}
뇌 에서 논리 를 제거하고 코드에 넣습니다. 이제 프로그램 은 당신이 의미하는 바를 알고 있습니다. 이름을
지을 때마다 물리적 표현 을 제공합니다 . 존재합니다. 조작하고 재사용 할 수 있습니다.
전체 블록을 술어로 정의 할 수도 있습니다.
bool ElementBlahBlah? (elementIndex, lastElementIndex);
그 기능에서 (나중에) 더 많은 일을합니다.
표현식이 복잡하면 bool
예 를 반환하는 다른 함수로 옮기 isAnEveningInThePubAGoodIdea(dayOfWeek, sizeOfWorkLoad, amountOfSpareCash)
거나 복잡한 표현식이 필요하지 않도록 코드를 재고합니다.
임시 변수 대신 함수 / 메소드를 만드는 것이 더 낫다고 생각합니다. 이렇게하면 메서드가 짧아지기 때문에 가독성이 높아집니다. Martin Fowler의 저서 Refactoring에는 코드 품질을 개선하는 데 좋은 조언이 있습니다. 특정 예제와 관련된 리팩토링을 "Replace Temp with Query"및 "Extract Method"라고합니다.
개인적으로 이것은 좋은 습관이라고 생각합니다. 코드 실행에 미치는 영향은 미미하지만 적절하게 사용하면 제공 할 수있는 명확성은 나중에 코드를 유지 관리 할 때 매우 중요합니다.
이런 식으로 필요 이상으로 계산한다는 것을 기억하십시오. 코드에서 조건을 제거하기 때문에 항상 두 조건을 모두 계산합니다 (단락 없음).
그래서:
if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) ||
(elementIndex == lastElementIndex)){
...
}
변형 후 :
if((elementIndex < 0) || (MAX_ELEMENTS < elementIndex) |
(elementIndex == lastElementIndex)){
...
}
대부분의 경우 문제는 아니지만 일부에서는 성능 저하 또는 기타 문제를 의미 할 수 있습니다 (예 : 두 번째 표현에서 첫 번째 표현이 실패했다고 가정 할 때).
메서드에 성공 알림이 필요한 경우 : (C #의 예)
bool success = false;
시작합니다. 코드를 다음과 같이 변경할 때까지 오류가 발생합니다.
success = true;
그런 다음 끝 :
return success;
당신 / 당신의 팀이 선호하는 스타일에 달려 있다고 생각합니다. "변수 소개"리팩토링이 유용 할 수 있지만 때로는 그렇지 않습니다. :)
And I should disagree with Kevin in his previous post. His example, I suppose, usable in case, when introduced variable can be changed, but introducing it only for one static boolean is useless, because we have parameter name in a method declaration, so why duplicate it in code?
for example:
void DoSomeMethod(boolean needDelete) { ... }
// useful
boolean deleteOnCompletion = true;
if ( someCondition ) {
deleteOnCompletion = false;
}
DoSomeMethod(deleteOnCompletion);
// useless
boolean shouldNotDelete = false;
DoSomeMethod(shouldNotDelete);
In my experience, I've often returned to some old scripts and wondered 'what the hell was I thinking back then?'. For example:
Math.p = function Math_p(a) {
var r = 1, b = [], m = Math;
a = m.js.copy(arguments);
while (a.length) {
b = b.concat(a.shift());
}
while (b.length) {
r *= b.shift();
}
return r;
};
which isn't as intuitive as:
/**
* An extension to the Math object that accepts Arrays or Numbers
* as an argument and returns the product of all numbers.
* @param(Array) a A Number or an Array of numbers.
* @return(Number) Returns the product of all numbers.
*/
Math.product = function Math_product(a) {
var product = 1, numbers = [];
a = argumentsToArray(arguments);
while (a.length) {
numbers = numbers.concat(a.shift());
}
while (numbers.length) {
product *= numbers.shift();
}
return product;
};
I rarely create separate variables. What I do when the tests get complicated is nest the IFs and add comments. Like
boolean processElement=false;
if (elementIndex < 0) // Do we have a valid element?
{
processElement=true;
}
else if (elementIndex==lastElementIndex) // Is it the one we want?
{
processElement=true;
}
if (processElement)
...
The admitted flaw to this technique is that the next programmer who comes along may change the logic but not bother to update the comments. I guess that's a general problem, but I've had plenty of times I've seen a comment that says "validate customer id" and the next line is examining the part number or some such and I'm left to wonder where the customer id comes in.
'Development Tip' 카테고리의 다른 글
Snappy를 사용한 Parquet vs ORC vs ORC (0) | 2020.10.12 |
---|---|
Visual C ++에 리팩터링 기능이없는 이유는 무엇입니까? (0) | 2020.10.12 |
Angular 2에서 EventEmitter.next ()와 EventEmitter.emit ()의 차이점 (0) | 2020.10.12 |
Microsoft 내부 PriorityQueue의 버그 (0) | 2020.10.12 |
매개 변수 유형의 객체 인스턴스화 (0) | 2020.10.12 |