[Clean Code] 5장. 형식 맞추기

Rose·2024년 2월 3일

CleanCode

목록 보기
4/8
post-thumbnail

TIL(Today I Learned)


내용 3줄 정리 💁🏻‍♀️

  • 프로그램은 짧고 간결한 것이 좋다.
  • 오늘 구현한 코드의 가독성은 앞으로 바뀔 코드의 품질에 지대한 영향을 미친다.
  • 코드의 형식은 중요하다. '돌아가는 코드'만 짠다고 해서 코드를 다 짠 것이 아니다.

기억하고 싶은 내용 📝

  • 프로그래머라면 형식을 깔끔하게 맞춰 코드를 짜야 한다. 코드 형식을 맞추기 위한 간단한 규칙을 정하고 그 규칙을 착실히 따라야 한다. (96p)

  • 어쩌면 '돌아가는 코드'가 전문 개발자의 일차적인 의무라 여길지도 모르겠다. 하지만 이 책을 읽으면서 생각이 바뀌었기 바란다. (96p)

  • 오늘 구현한 기능이 다음 버전에서 바뀔 확률은 아주 높다. 그런데 오늘 구현한 코드의 가독성은 앞으로 바뀔 코드의 품질에 지대한 영향을 미친다. (96p)

  • 일반적으로 큰 파일보다 작은 파일이 이해하기 쉽다. (97p)

  • 소스 파일 첫 부분은 고차원 개념과 알고리즘을 설명한다. 아래로 내려갈수록 의도를 세세하게 묘사한다. 마지막에는 가장 저차원 함수와 세부 내역이 나온다.(신문 기사처럼 작성하라) (98p)

  • 패키지 선언부, import문, 각 함수 사이에 빈 행이 들어간다. 빈 행은 새로운 개념을 시작한다는 시각적 단서다.(개념은 빈 행으로 분리하라) (98p)

  • 줄바꿈이 개념을 분리한다면 세로 밀집도는 연관성을 의미한다. 즉, 서로 밀집한 코드 행은 세로로 가까이 놓여야 한다는 뜻이다.(세로 밀집도) (100p)

  • 같은 파일에 속할 정도로 밀접한 두 개념은 세로 거리로 연관성을 표현한다. 여기서 연관성이란 한 개념을 이해하는 데 다른 개념이 중요한 정도다. 연관성이 깊은 두 개념이 멀리 떨어져 있으면 코드를 읽는 사람이 소스 파일과 클래스를 여기저기 뒤지게 된다. (101p)

  • 변수 선언. 변수는 사용하는 위치에 최대한 가까이 선언한다. (101p)

  • 인스턴스 변수는 클래스 맨 처음에 선언한다. 변수 간에 세로로 거리를 두지 않는다. (103p)

    인스턴스 변수를 선언하는 위치에 대한 논쟁이 분분하고, 프로그래밍 언어마다 선호되는 위치가 다르기도 하다. 결론은 "잘 알려진 위치에 인스턴스 변수를 모은다"는 사실이 중요하다. 변수 선언을 어디서 찾을지 모두가 알고 있어야 한다.

  • 종속 함수. 한 함수가 다른 함수를 호출한다면 두 함수는 세로로 가까이 배치한다. 또한 가능하다면 호출하는 함수를 호출되는 함수보다 먼저 배치한다. 규칙을 일관적으로 적용한다면 독자는 방금 호출한 함수가 잠시 후에 정의되리라는 사실을 예측한다. (104p)

  • 개념적 유사성. 친화도가 높을수록 코드를 가까이 배치한다. (106p)

    친화도가 높은 요인
    1. 한 함수가 다른 함수를 호출해 생기는 직접적인 종속성
    2. 변수와 그 변수를 사용하는 함수
    3. 비슷한 동작을 수행하는 일군의 함수

  • 일반적으로 함수 호출 종속성은 아래 방향으로 유지한다. 다시 말해, 호출되는 함수를 호출하는 함수보다 나중에 배치한다. 그러면 소스 코드 모듈이 고차원에서 저차원으로 자연스럽게 내려간다. (107p)

  • 프로그래머는 명백하게 짧은 행을 선호한다. (107p)

  • 가로로는 공백을 사용해 밀접한 개념과 느슨한 개념을 표현한다. (108p)

  • 프로그래머는 이런 들여쓰기 체계에 크게 의존한다. 왼쪽으로 코드를 맞춰 코드가 속하는 범위를 시각적으로 표현한다. 그러면 이 범위에서 저 범위로 재빨리 이동하기 쉬워진다. (111p)

  • 팀은 한 가지 규칙에 합의해야 한다. 그리고 모든 팀원은 그 규칙을 따라야 한다. (113p)

  • 좋은 소프트웨어 시스템은 읽기 쉬운 문서로 이뤄진다는 사실을 기억하기바란다. (114p)

코드로 알아보기 💻

1. 세로 밀집도

줄바꿈이 개념을 분리한다면 세로 밀집도는 연관성을 의미한다. 즉, 서로 밀집한 코드 행은 세로로 가까이 놓여야 한다는 뜻이다.

public class ReporterConfig {
/**
 * 리포터 리스너의 클래스 이름
 */
 private String m_className;
 
 /**
  * 리포터 리스너의 속성
  */
  private List<Property> m_properties = new ArrayList<Property>();
  public void addProperty(Property property) {
  	m_properties.add(property);
  }
}

위의 코드는 의미 없는 주석으로 두 인스턴스 변수를 떨어뜨려 놓아서 코드가 한눈에 들어오지 않는다. 따라서 불필요한 주석은 삭제하는 것이 좋다. 연관성이 깊은 두 개념이 멀리 떨어져 있으면 코드를 읽는 사람이 소스 파일과 클래스를 여기저기 뒤지게 된다.


2. 개념적 유사성

어떤 코드는 서로 끌어당긴다. 개념적인 친화도가 높기 때문이다. 친화도가 높을수록 코드를 가까이 배치한다.

public class Assert {
	static public void assertTrue(String message, boolean condition) {
    	if (!condition)
        	fail(message);
    }
}

static public void assertTrue(boolean condition) {
	assertTrue(null, !condition);
}

static public void assertFalse(String message, boolean condition) {
	assertTrue(message, !condition);
}

static public void assertFalse(boolean condition) {
	assertFalse(null, condition);
}
...

위 함수들은 개념적인 친화도가 매우 높다. 명명법이 똑같고 기본 기능이 유사하고 간단하다. 서로를 호출하는 관계는 부차적인 요인이다. 종속적인 관계가 없더라도 가까이 배치할 함수들이다.

3. 가로 공백과 밀집도

가로로는 공백을 사용해 밀접한 개념과 느슨한 개념을 표현한다.

private void measureLine(String line) {
	lineCount++;
    int lineSize = line.length();
    totalChars += lineSize;
    lineWidthHistogram.addLine(lineSize, lineCount);
    recordWidestLine(lineSize);
}
  • 할당 연산자를 강조하기 위해 앞뒤에 공백을 주었다.
  • 함수 이름과 이어지는 괄호 사이에는 공백을 넣지 않았다. 함수와 인수는 서로 밀접하기 때문이다.
  • 함수를 호출하는 코드에서 괄호 안 인수는 공백으로 분리했다. 쉼표를 강조해 인수가 별개라는 사실을 보여주기 위해서다.
  • 이외에도 연산자 우선순위를 강조하기 위해서도 공백을 사용한다.

생각 및 느낀점

  • 호출하는 함수를 호출되는 함수보다 뒤에 배치하여 코드를 뒤적이며 시간을 낭비한 적이 있다. 한 함수가 다른 함수를 호출한다면 세로로 가까이 배치하고 호출하는 함수를 가장 먼저 배치한다면 프로그램이 자연스럽게 읽히게 된다는 것을 코드 예제를 보며 깨달았다. 규칙을 일관적으로 적용해서 코드의 가독성을 높이자!
  • 코드를 짠 이후 에러를 해결하기 위해 코드를 이리저리 살펴보았을 때, 분명히 내가 짠 코드인데 너무 복잡하게 느껴졌다. 이것은 일관된 규칙을 무시하고 작성하여 뒤죽박죽 되었기 때문이다. 친화도가 높은 코드들은 주변에 배치해야겠다.
  • 결국 프로그래머는 짧은 행, 간결하면서 명확한 코드를 선호한다.

참고자료

  • [Clean Code] 클린 코드 #Day 7 / 형식 맞추기 (chillihc님의 velog)
  • profile
    신입 백엔드 개발자의 성장 기록

    0개의 댓글