스타일링 화합물 AND / OR if 문


13

가독성을 극대화하기 위해 복잡한 복합 AND / OR if 문을 어떻게 스타일링합니까? 줄 바꿈은 어떻게 들여 쓰기하고 어디에 배치합니까? 내 특별한 상황은 다음과 같습니다. 모든 것을 한 줄로 분쇄하는 것보다 낫지 만 여전히 지저분 해 보입니다.

if (
    (
        x == y
        && a != b
        && p.isGood() 
        && (
            i + u == b
            || q >= a
        )
    )
    || k.isSomething()
    || m > n
) {
    doSomething();
}

1
구피 들여 쓰기 및 괄호 / 괄호 구조는 의도적이거나 스타일의 일부입니까?
Ed S.

이상한. 나는 일주일 전에 SO에 대해이 같은 질문을했고 닫혔습니다. 이 질문이 어딘가에 살아있는 것을 보게되어 기쁘다!
Eric Belair

답변:


6

각 작은 단계마다 부울 변수를 만듭니다.

bool step1 = i + u == b || q >= a;
bool step2 = a != b && p.isGood() && group1;
bool step3 = group2 || k.isSomething() || m > n;
if (step3) { doSomething(); }

이것은 각 단계마다 다른 이름을 제외하고는 Lacrymology의 답변과 비슷합니다.

당신이 이름을 경우 step1, step2그리고 step3좋은 개념 이해가 가지 방법으로, 이것은 지금까지 가장 읽기가되어야한다. p.isGood()그리고 k.isSomething()당신은 매우 빡빡 루프에서이 코드를 실행하는 경우 때로는 이러한 기능이 비싼 경우이 옵션이 될 수없는 것, 그래서 그것은 당신의 원본 코드에 없을 것 같은 상황에서 호출하거나 할 수있다.

반면에 새 변수를 만들 때 발생할 수있는 성능 저하에 대해 걱정할 필요가 없습니다. 좋은 컴파일러는 최적화 할 것입니다.

사각형 충돌 감지의 예 (위에서 언급 한 성능 저하로 인해 사용하지 않을 수 있음) :

if((a.x + a.width >= b.x || b.x + b.width >= a.x)
 && (a.y + a.height >= b.y || b.y + b.width >= a.y)
)
{ collision(); }

다음이 될 수 있습니다.

bool horizMatch = a.x + a.width >= b.x || b.x + b.width >= a.x;
bool vertMatch = a.y + a.height >= b.y || b.y + b.width >= a.y;
if(horizMatch && vertMatch) { collision(); }

또한 코드를 그대로 두려면 완전히 괜찮을 것이라고 생각합니다. 솔직히 귀하의 코드는 읽기 쉽다고 생각합니다. 분명히 나는 ​​정확히 무엇인지 a b x y i u p k m n모르지만 구조가 진행되는 한 나에게 좋아 보인다.


8

조건이 복잡해지면 일반적으로 코드를 더 모듈화되도록 리팩터링합니다.


나는이 상황에서 굴절을 피할 것입니다. 이러한 작은 함수를 격리하여 테스트하는 것은 어리석은 일이며 함수 외부에 매달려있는 정의를 사용하면 코드가 덜 자명합니다.
Rei Miyasaka

그것은 당신이 얼마나 잘 리팩토링하는지에 달려 있습니다. 코드에서 대수학 교과서처럼 보이는 조건부 문자열 대신 의미있는 함수 이름을 갖는 것이 코드를 훨씬 더 자명하게 만든다고 주장합니다.
JohnFx

시각적으로, 함수가 외부에 매달려 있고 함수가 정확히 무엇을하는지 명확하지 않을 것입니다. 위로 스크롤 할 때까지 순간적으로 블랙 박스입니다. 함수에서 함수를 허용하는 언어가 아닌 한, 굴절률이 얼마나 좋은지에 관계없이 독자 나 작가 모두에게 매우 편리하다고 생각하지 않습니다. 그리고 함수에서 함수를 허용하는 언어를 사용한다면 구문이나 변수를 대신 선언하는 것과 구문이 거의 다르지 않을 가능성이 있습니다 (예 : let x = a > b또는) let f a b = a > b.
Rei Miyasaka

변수는 똑같이 잘 작동합니다. 나는 그 리팩토링도 고려할 것입니다.
JohnFx

아, 알았어요
Rei Miyasaka

8

복잡성 수준에서 이와 같은 일을하겠습니다

bool doIt = x == y && a != b && p.isGood();
doIt &= ( i + u == b || q >= a);
doIt |= k.isSomething() || m > n;

if(doIt)
{
    doSomething();
}

그것은 추악하지만 읽을 수 있으며 컴파일러가 리팩토링하는 방법을 알고있을 것이라고 확신합니다.

반면에 IF 문을 작성하는 상황에서 자신을 본다면 솔루션을 다시 생각할 수 있습니다. 왜냐하면 CERTAIN이기 때문에 더 간단하게 처리하거나 적어도 그 조건 중 일부를 추상화하는 방법이 있기 때문입니다 (예 : 아마도 x == y && a != b && p.isGood()정말 의미 this->isPolygon()하고 나는 그 방법을 만들 수 있습니다;


4

시간이 지남에 따라 수직 정렬에 덜 집착하지만 멀티 라인 표현식의 일반적인 형태는 ...

if (   (   (expr1 == expr2)
        || (expr3 == expr4)
        || (expr5 == expr6)
       )
    && (   (expr7 == expr8)
        || (expr9 == expra)
       )
   )
{
  blah;
}

키 포인트...

  • 괄호와 마찬가지로 닫힌 괄호는 열린 괄호와 수직으로 정렬됩니다.
  • 한 줄에 맞는 하위 표현식은 한 줄 안에 있으며 왼쪽에 세로로 정렬됩니다. 가독성을 높이는 데 도움이되는 경우 해당 단일 라인 파트 내의 삽입 연산자도 수직으로 정렬됩니다.
  • 닫는 괄호는 자연스럽게 거의 빈 줄을 만들어 시각적으로 물건을 그룹화합니다.

때때로, 나는 포맷 것이다 +*또는 다른 사업자도이 좋아한다. 상당히 복잡한 표현은 제품 합계 또는 제품 합계 형태 (부울 "합계"및 "제품"을 지칭 할 수 있음)를 취하므로 일관된 스타일이 가치가있을 정도로 일반적 일 수 있습니다.

그래도 조심하십시오. 들여 쓰기를 사용하여 오버 컴플렉스 표현식을 더 읽기 쉽게 만드는 것보다 리팩토링 (표현식의 일부를 함수로 이동하거나 중간 부분을 변수로 계산 및 저장)하는 것이 좋습니다.

가까운 쪽을 오른쪽에 쌓는 것을 선호한다면 싫어 하지는 않지만 그렇게 나쁘지는 않습니다. 너무 멀어지면 실수로 들여 쓰기가 괄호가하는 일을 잘못 표시 할 수있는 위험이 있습니다.

if (   (   (expr1 == expr2)
        || (expr3 == expr4)
        || (expr5 == expr6))

    && (   (expr7 == expr8)
        || (expr9 == expra)))
{
  blah;
}

+1 스타일이 마음에 듭니다. 그것은 내 질문에 직접 대답했지만 Rei Miyasaka는 문제의 근본 원인이라고 생각합니다. 레이의 방법을 수행하기 위해 게으 르면 스타일링을 사용하겠습니다.
JoJo

와우 이거 정말 맛있어요.
Rei Miyasaka

1

http://www.codinghorror.com/blog/2006/01/flattening-arrow-code.html

나는 Lafymology의 JohnFx의 답변과 하나에 동의합니다. 나는 작은 목표를 달성하고 현명한 방법으로 그것들을 구축하는 많은 기능 (바람직하게는 정적)을 구축 할 것입니다.

그래서 이런 식으로 어떻습니까? 이것은 완벽한 솔루션은 아니지만 작동합니다. 이를 더 정리할 수있는 방법이 있지만보다 구체적인 정보가 필요합니다. 참고 :이 코드는 컴파일러가 똑똑하기 때문에 빨리 실행되어야합니다.

// Currently based on members or global vars
// (which is often a bad idea too)
function doSomethingCondirionally()
{
  if (k.isSomething() || m > n)
  {
    doSomething();
    return;
  }

  // Else ... 
  if (x != y) return;
  if (a == b) return;
  if (!p.isGood()) return;

  // Final, positive check
  if (i + u == b || q >= a)
  {
    doSomething();
  }
}

함수에서 하나의 종료점 만 갖는 것이 가치있는 것이라면 (예를 들어, 기능적 언어 인 경우), 이것이 최선의 선택이 아니거나 심지어 사용 가능한 것이 아닐 수도 있습니다. 그렇습니다. 이것이 제가 자주하는 일입니다.
Rei Miyasaka

Javascript와 같은 해석 언어 인 경우 어떻게합니까?
JoJo

@ Rey Miyasaka, 언어에 따라 얼마나 가치가 있는지. LISP 언어 군을 좋아하지만 직장에서 언어를 사용할 필요는 없습니다. 다른 사람의 기능을 리팩터링해야하지만 다른 코드 (종종 현실)를 만지지 않으면 위와 같은 작업을 수행합니다. 이 논리를 처음부터 작성 / 재 작성할 수 있으면 접근 방식이 달라 지지만 저자가 여기서하려는 작업에 대한 구체적인 예가 없으면 그러한 코드를 작성할 수 없습니다.
Job

1
@Rei Miyasaka, 그 사람은 천재이거나 쓰레기로 가득 차있을 것입니다. 나는 모든 것을 알지 못하지만 그 사람이 단일 출구 지점을 방어한다는 것을 알고 궁금합니다. 여기와 그에 대한 논의가 있으며, 제가 얻은 인상은 80 년대 학자들 에게이 접근법이 인기가 있었지만 더 이상 중요하지 않으며 실제로 가독성을 방해 할 수 있다는 인상이었습니다. 물론 LINQ 기능 스타일로 모든 작업을 수행하면이 문제가 발생하지 않습니다.
Job

2
@Job @Steve 명시적인 할당 해제가 필요한 언어에서 더 중요한 지침이라고 생각합니다. 분명히 모든 기능에 해당되는 것은 아니지만 초보자 프로그래머가 리소스를 확보하는 것을 잊어 버리지 않도록 습관을들이는 습관 일 것입니다.
Rei Miyasaka

1

가치있는 것에 대해, 나는 당신의 예제가 내가 작성한 복잡한 술어와 매우 비슷하다는 것을 알게되어 놀랐습니다. 복잡한 술어가 유지 관리 성 또는 가독성에 가장 크지는 않지만 다른 경우에는 동의합니다.

이 부분을 올바르게 수행했음을 강조하겠습니다. && a != b 논리적 커넥터를 줄 끝에 두지 마십시오. 시각적으로 놓치기가 너무 쉽습니다. 행 끝에 연산자를 두지 말아야 할 또 다른 위치는 문자열 연산자로, 해당 연산자가있는 언어로되어 있습니다.

이 작업을 수행:

String a = b
   + "something"
   + c
   ;

이 작업을 수행하지 마십시오 :

String a = b +
   "something" +
   c;

논리 커넥터에 대한 어설 션을 지원하는 논리 나 연구가 있습니까? 아니면 단순히 선호도가 사실이라고 표시되어 있습니까? 나는 여러 곳에서 이것을 많이 들었고 그것을 이해하지 못했다.
Caleb Huitt-cjhuitt 2018 년

@Caleb-수학은 수세기 동안 그러한 방식으로 조판되었습니다. 코드를 감추는 경우 각 줄의 왼쪽에 중점을 둡니다. 연산자로 시작하는 행은 분명히 이전 행의 연속이며 잘못 들여 쓰기 된 새 명령문이 아닙니다.
케빈 클라인

나는 또한 수학 연산자의 접두사를 좋아합니다. 나는 내 프로그래밍 경력에서 늦게까지 깨달았다 :)
JoJo

0

조건부가 그렇게 복잡한 경우 일반적으로 여러 부분으로 나뉘어 야 함을 나타냅니다. 아마도 하나의 절이 중간 변수에 할당 될 수 있습니다. 아마도 하나의 절이 도우미 메소드로 바뀔 수 있습니다. 나는 일반적으로 한 줄에 너무 많은 ands와 ors를 갖지 않는 것을 선호합니다.


0

코드를 여러 문장으로 나누면 이해하기 쉽습니다. 그러나 진짜 닌자는 이런 식으로 할 것입니다. :-)

if
(
    (
        x == y
    &&
        a != b
    &&
        p.isGood()
    &&
        (
            i + u == b
        ||
            q >= a
        )
    )
||
    k.isSomething()
||
    m > n
)
{
    doSomething();
}

5
나는 공백의 팬이지만 내 취향을 위해 거의 빈 줄로 채워져 있습니다.
Steve314
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.