2P by neo 4일전 | ★ favorite | 댓글 1개
  • 최근 코드베이스를 검토하면서 코드의 품질에도 불구하고 정신적으로 피로해지는 경험을 함
    • 이는 코드의 복잡성보다는 가독성과 관련이 있었음
  • 코드의 가독성을 높이기 위한 8가지 패턴을 도출

코드 가독성 메트릭 및 대체 복잡성 메트릭

  • 코드 가독성을 측정하는 보편적이고 널리 사용되는 메트릭은 존재하지 않음
  • 현실에서 사용되지 않는 학술 논문이나 개인적인 의견만 존재함
  • 새로운 메트릭을 만들기보다는 누구나 쉽게 논의할 수 있는 시각적 패턴에 집중
  • 복잡성 메트릭에서 중요한 조건:
    • 소스 코드 스니펫이나 개별 함수에서 작동해야 함
    • 알고리즘 복잡성 대신 코드 작성 방식에 초점
    • 스타일 요소(변수명, 공백, 들여쓰기 등)에는 초점 두지 않음

Halstead 복잡성 메트릭

  • 1970년대 Maurice Halstead가 개발한 코드 복잡성 메트릭
  • 언어와 플랫폼에 상관없이 코드 작성 방식을 수치화 가능
  • 연산자와 피연산자 수를 기반으로 프로그램의 길이, 볼륨, 난이도를 계산
  • 주요 측정값:
    • 고유 연산자 수 (n1)
    • 고유 피연산자 수 (n2)
    • 전체 연산자 수 (N1)
    • 전체 피연산자 수 (N2)
  • 더 많은 연산자와 피연산자가 사용될수록 코드의 복잡성 증가
  • 모든 언어에서 연산자 및 피연산자의 정의가 명확하지 않아 일관된 도구 사용이 중요

Halstead 복잡성에서 얻은 인사이트

  • 짧고 변수 수가 적은 함수가 가독성이 높음
  • 언어별 연산자나 구문 설탕(syntactic sugar) 사용은 최소화
  • 함수형 프로그래밍의 체인 사용(map/reduce/filter 등)은 너무 길어지면 가독성이 떨어짐

인지 복잡성 (Cognitive Complexity)

  • SonarSource에서 개발한 복잡성 메트릭
  • 코드 읽기 어려움을 보다 정확하게 측정하기 위한 시도
  • 세 가지 주요 원칙:
    1. 단축 구문(shorthand constructs)이 읽기 난이도를 줄임
    2. 비선형 흐름의 단절이 난이도를 증가시킴
    3. 중첩된 제어 흐름이 난이도를 증가시킴

인지 복잡성에서 얻은 인사이트

  • 단축 구문은 간결하지만 잠재적 버그 위험 존재
  • 조건문 및 논리 연산자는 과도하게 사용하면 가독성이 떨어짐
  • 예외 처리는 코드 복잡성을 높이는 주요 원인
  • goto는 일반적으로 피해야 하지만 특정 상황에서는 유용할 수 있음
  • 중첩된 제어 구조는 가능하면 줄이는 것이 좋음

함수의 모양, 패턴 및 변수

  • 함수의 시각적 "모양"은 코드 가독성에 중요한 역할 수행
  • 가독성을 높이는 세 가지 원칙:
    1. 명확하고 구체적인 변수명 사용
    • 변수 중복(Shadowing) 피하기
    • 시각적으로 구별 가능한 이름 사용 (i, j와 같은 유사 이름 피하기)
    1. 변수의 수명(liveness) 단축
    • 변수의 사용 범위는 짧을수록 좋음
    • 함수 경계를 넘어서 오래 유지되는 변수는 복잡성 증가
    1. 익숙한 코드 패턴 재사용
    • 일관된 코드 패턴을 유지하면 가독성 향상
    • 새로운 접근 방식보다 기존에 익숙한 패턴을 우선 사용

코드 가독성을 향상시키는 8가지 패턴

  1. 라인/연산자/피연산자 수 감소 – 작은 함수와 적은 변수 사용이 가독성 향상
  2. 새로운 접근 방식 회피 – 코드베이스에서 익숙한 패턴을 유지
  3. 그룹화 – 긴 함수 체인, 반복자 등은 보조 함수로 분리
  4. 조건문의 단순화 – 조건문은 짧게 유지하고 논리 연산자 혼합 최소화
  5. goto 최소화 – 필요할 경우 에러 처리에서만 제한적으로 사용
  6. 중첩 최소화 – 중첩된 로직은 줄이고, 필요하면 함수로 분리
  7. 명확한 변수 이름 사용 – 구체적이고 중복되지 않는 변수명 사용
  8. 변수의 수명 단축 – 함수 내에서 짧게 유지하고 함수 경계를 넘지 않도록 함

결론

  • 코드 가독성은 코드 품질에 중요한 요소
  • Halstead 및 Cognitive Complexity는 가독성 문제를 수치화하고 개선 방향 제시 가능
  • 간결하고 명확한 코드를 작성하면 코드 유지 보수가 쉬워지고 버그 발생 가능성 감소
  • 최적의 코드 작성은 단순함, 일관성, 명확성을 우선시하는 것임
Hacker News 의견
  • map, reduce, filter와 같은 함수형 프로그래밍 구조를 연결하는 것은 간결하지만, 긴 체인은 가독성을 해치는 경향이 있음

    • 이는 기사에서 암시된 바가 아님
    • 익숙하지 않아서 나쁘다고 생각하는 일반적인 불평처럼 느껴짐
    • 조금만 익숙해지면 다른 방법보다 읽고 쓰기 쉬움
    • 함수형 프로그래밍의 기본을 배우는 것이 중요함
    • Monad를 설명할 필요는 없지만, map과 filter를 무작위로 비난하지 않을 정도로 익숙해져야 함
  • 좋은 코드의 중요한 측면은 질적이고 문학적임

    • 수학적 사고방식을 가진 프로그래머와 학자들에게는 불편할 수 있음
    • 도스토옙스키와 우드하우스를 좋아하지만, 그들의 글은 매우 다름
    • 코드베이스의 스타일을 이해하는 데 시간이 걸림
  • 코드 읽을 때 가장 피로한 문제는 가변성임

    • 변수를 한 번만 "고정"할 수 있는 능력은 큰 선물임
    • 메서드를 이해하는 과정은 0%에서 100%로 단조롭게 증가해야 함
    • GOTOs가 해로운 이유는 가변 변수의 상태를 알기 어려워서임
  • 작은 함수와 적은 변수는 일반적으로 읽기 쉬움

    • "가독성"에 대한 초점이 미세 가독성에 치우쳐 있음
    • 이는 코드가 지나치게 분열되게 만듦
    • APL 계열 언어는 반대 극단에 있음
  • TypeScript는 코드 읽기 어렵게 만듦

    • 데이터 모델이 "원자적"으로 유지되면 괜찮음
    • 타입 유추에 의존하면 필드를 원래 위치로 추적하기 어려움
  • getOddness4 함수는 비대칭성을 줌

    • getOddness2 함수는 대칭적 선택을 제공함
  • 기사는 흥미롭지만 만족스럽지 않음

    • 언어 특정 연산자나 구문 설탕 사용을 피하라는 의견에 동의하지 않음
    • map, reduce, filter 같은 구조는 잘 사용하면 다른 연산자를 대체하고 "볼륨"을 줄임
  • 가독성을 정의하려는 시도는 칭찬할 만함

    • 많은 사람들에게 테스트를 통해 가독성의 실제 차원을 찾을 수 있을 것임
  • 코드 복잡성은 구문 트리의 크기로 표현됨

    • 지역적 복잡성 감소가 전체 복잡성에 큰 영향을 주지 않음
  • 긴 함수 체인이나 콜백은 작은 그룹으로 나누고 잘 명명된 변수를 사용하는 것이 좋음

    • 두 버전 모두 효율성 면에서 동일함
    • 차이는 컴파일러에 있음