Clean Code & Refactoring

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

유자맛바나나 2022. 7. 10. 04:20

[Clean Code 시리즈 포스팅]

[Clean Code] 1장. 깨끗한 코드: Clean Code

[Clean Code] 2장. 의미 있는 이름 : Meaningful Names

[Clean Code] 3장. 함수 : Functions

[Clean Code] 4장. 주석 : Comments

[Clean Code] 5장. 형식 맞추기 : Formatting (Now)

[Clean Code] 6장. 객체와 자료구조 : Objects and Data Structures

[Clean Code] 9장. 단위 테스트 : Unit Tests

 

 

 

 

5장 형식 맞추기는 현업 개발자라면 당연하다고 생각할 내용들이 많다. 예를 들어 들여쓰기 같은 것들이 있다.

본 포스팅에서는 다시 한 번 기억해야할 것들 위주로 요약했다.

 

❑ 형식을 맞추는 목적

  • 한 가지 분명히 짚고 가자. 코드 형식은 중요하다! 너무 중요해서 무시하기 어렵다.
  • 코드 형식은 의사소통의 일환이다
  • 오늘 구현한 코드의 가독성은 앞으로 바뀔 코드의 품질에 지대한 영향을 미친다. 오랜 시간이 지나 원래 코드의 흔적을 더 이상 찾아보기 어려울 정도로 코드가 바뀌어도 맨 처음 잡아놓은 구현 스타일과 가독성 수준은 유지보수 용이성과 확장성에 계속 영향을 미친다. 원래 코드는 사라질지라도 개발자의 스타일과 규율은 사라지지 않는다.

 

❑ 적당한 행 길이를 유지하라

1. 적당한 행 길이(소스 코드의 Line 수)의 기준

  • 저자는 적절한 소스 코드 길이의 기준에 대해 설명하기 위해 JUnit, Tomcat, Ant, FitNesse 등 유명한 프로젝트에서 작성된 각 파일들의 행 길이 분포를 제시했다.
  • Tomcat과 Ant는 절반 이상이 200줄을 넘고 수천 줄이 넘어가는 파일도 있었다.
  • 하지만 JUnit, FitNesse는 500줄을 넘어가는 파일이 없으며, 대다수가 200줄이다. 저자는 이 사실로부터 대부분 200줄 정도인 파일들로도 큰 시스템을 구축할 수 있다는 사실을 언급한다.
  • 일반적으로 큰 파일보다 작은 파일이 이해하기 쉬우므로 행 길이를 작게 유지하려고 노력하는 편이 좋다고 말한다.

 

2. 개념은 빈 행으로 분리하라

  • 빈 행(Empty line)은 새로운 개념을 시작하는 시각적 단서다. 즉, 새로운 개념이 시작할 때 빈 행으로 구분하라는 뜻과 같다.
  • 어떻게 보면 당연한 말이지만, 코드를 작성할 때 어떤 기준으로 빈 행을 넣을지 고민이 될 때가 있다. 빈 행을 너무 많이 쓰고있진 않은지 고민한 적도 있다. 앞으로는 개념적으로 구분이 될 때 빈 행을 넣는다고 생각하면 깔끔하다.

Example Code: Bad Case

public static int add(int a, int b) {
    return a + b;
}
public static int minus(int a, int b) {
    return a - b;
}
public static int multiple(int a, int b) {
    return a*b;
}

Example Code: Good Case

  • add, minus, multiple은 개념적으로 구분되기 때문에 빈 행(Empty line)을 넣었다
public static int add(int a, int b) {
    return a + b;
}

public static int minus(int a, int b) {
    return a - b;
}

public static int multiple(int a, int b) {
    return a*b;
}

 

3. 세로 밀집도

  • 세로 밀집도는 연관성을 의미한다. 서로 관련있는(밀접한) 코드 행은 최대한 가까이 놓아야 한다는 뜻이다. 

Example Code

  • handle과 acceleratorPedal, breakPedal은 서로 관련있는 코드다. 하지만 sheetColor, sheetCount에 의해 서로 멀리 떨어져 있다. 따라서 handle을 sheetCount 다음에 위치시키는게 적절하다.
private Handle handle;
private String sheetColor;
private String sheetCount;
private Accelerator acceleratorPedal;
private Break breakPedal;

 

4. 수직 거리

  • 앞서 설명한 세로 밀집도와 거의 동일한 내용이다. 하지만 수직 거리 부분에서 저자가 설명하는 것은 유사성이 있는 함수와 함수간의 거리, 변수 선언 위치 등을 추가적으로 설명하고 있다.
  • 연관성이 깊은 두 개념이 멀리 떨어져 있으면 코드를 읽는 사람이 소스 파일과 클래스를 여기저기 뒤지게 된다. 함수 연관 관계와 동작 방식을 이해하려고 이 함수에서 저 함수로 오가며 뺑뺑이를 돌게 된다.
  • 지역변수의 선언 위치
    변수는 사용하는 위치에 최대한 가까이 선언한다. 우리가 만드는 함수는 매우 짧으므로 지역 변수는 각 함수 맨 처음에 선언한다.

Example Code

public String[] findTop10Items(String category) {
    String[] top10 = new String[10]; // 지역 변수는 맨 처음에 선언한다.
    
    wishlists = itemService.findWishlists();
    ...
}
  • 인스턴스 변수의 선언 위치
    인스턴스 변수는 클래스 맨 처음에 선언한다. 인스턴스 변수를 맨 처음이 아닌, 함수와 함수 중간에 선언하는 등의 방식은 좋지 않다. 클래스 내 다양한 메서드가 인스턴스 변수를 사용할 것이기 때문에 잘 알려진 위치에 인스턴스 변수를 모으는 것이 바람직하기 때문이다.

Example Code

public class Car {
    private Engine engine; // 인스턴스 변수는 클래스 최상단에 선언한다.
    private Body body;
    private String carColor;
    
    ...
}
  • 종속 함수의 선언 위치
    한 함수가 다른 함수를 호출한다면 두 함수는 세로로 가까이 배치한다. 

 

5. 세로 순서

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

 

❑ 가로 형식 맞추기

1. 적당한 한 행의 길이의 기준

  • 소스 코드의 적절한 길이를 설명할 때와 마찬가지로 저자는 JUnit, Tomcat, Ant, FitNesse 등 프로젝트에서 작성된 한 행의 길이 분포에 대해 분석했다.
  • 10자 미만은 30% 정도이며, 20자에서 60자 사이가 작성된 모든 행 중 40%에 달한다. 80자 이후부터 비율은 급격히 감소한다.
  • 프로그래머는 명백히 짧은 행을 선호한다. 그러므로 한 행을 작성할 때 짧게 작성하는것이 바람직하다. 저자 개인적으로는 120자 정도로 행 길이를 제한한다.

 

2. 가로 공백과 밀집도

  • 현업에서 개발중이라면 대부분 자연스럽게 받아들일 내용들이다. 예를 들어 '=' 앞 뒤로 공백(Space)를 넣기, 함수 Parameter 들을 구분할 때 공백 넣기(예: param1,(공백)param2) 등이다.
  • 한 가지 도움이 될 만한 내용이라면, 사칙연산 기호를 사용할 때 사용할만한 원칙이다.
    1. +, -가 양수, 음수의 부호로 사용될 땐 숫자와 기호 사이에 공백을 넣지 않는다
    2. +, -가 사칙 연산의 기호로 사용될 땐 앞 뒤에 공백을 넣는다(예: 5 + 3)
    3. 나눗셈(/)은 앞 뒤에 공백을 넣는다.
    4. 곱셈은 앞 뒤에 공백을 넣지 않는다.