본문 바로가기

책읽기/클린코드

형식 맞추기

형식이 맞춰진 코드는 깔끔하고, 일관적이고, 꼼꼼하다고 느껴진다.

질서정연한 코드는 이해하기 좋고 편하게 읽을 수 있다.

 

오늘 작성한 코드는 내일 바뀔 확률이 매우 높다.

복잡하고 난잡한 코드를 짠다면 시간이 지날수록 거대해지고, 보기 힘들어 질 것이다.

하지만 코드스타일과 규율은 변하지 않는다.

형식을 맞추고 스타일을 맞추면 코드가 커져도 일정한 형태를 띄고, 편하게 읽을 수 있다.

 

 

1. 적절한 행 길이를 유지하라.

fitensse는 테스트 자동화 도구로 총 라인이 5만줄인 큰 프로젝트이다.

하지만 이 프로젝트의 1/3의 파일당 평균 행 길이는 40 ~ 100줄이다. 가장 행이 많은 파일은 400줄이다.

아무리 큰 프로젝트라도 적은 줄로 구현이 가능하다.

 

 

1-1. 산문 기사처럼 작성하라.

좋은 기사는 위에서 아래로 읽는다. 표제 - 주제(요약) - 그림(사진) - 세부내용 - 결론 이런 형태를 띄고 있을 것이다.

코드도 똑같다.

 

 

이름을 간단하면서 명료하고 설명가능하게 작성한다. 이름만 보고도 어떤 일을 하는 부분인지 알 수 있게.

소스파일의 첫 부분에는 고차원 개념과 알고리즘을 설명한다.

아래로 내려가면서 의도를 세세하게 묘사한다.

마지막에는 가장 저차원적인 함수 구현이 나오게 된다.

그를 작성하면서 중간의 내용들은 크기가 작은 함수들로 구성되게 한다.

 

 

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

공백라인은 의미적으로 다른 부분이 나올 때 사용하면 보기가 좋다.

또한 Google Style Guide나 여타 가이드에 나오는 컨벤션 규칙처럼 (예를들면, import문과 클래스 선언문 사이의 공백줄)

사이사이의 공백줄은 가독성을 좋게 만든다.

 

 

1-3. 세로 밀집도

서로 밀접한 코드 행은 세로로 가까이 놓여야 한다.

아래의 예시는 의미없는 주석으로 두 인스턴스 변수가 세로로 멀어진 경우이다.

public class Car{
    /**
     * 차의 이름
     */
    private String name;
    /**
     * 차의 속력
     */
    private int speed;
    
    public Car() {
    }
}

 

 

 

 

 

2. 수직 거리

서로 밀접한 개념은 세로로 가까이 있어야 한다.

함수가 정의된 코드를 찾느라 이 코드 저 코드를 뒤지는 것은 시간과 노력을 허비하는 상황이다.

 

 

2-1. 변수 선언(지역 변수)

변수는 사용하는 위치에 최대한 가까이 선언한다.

그리고 우리가 작성하려는 함수는 짧은 함수이다.

따라서 변수는 함수의 맨 처음에 선언한다.

 

 

2-2. 인스턴스 변수

인스턴스 변수는 클래스의 맨 처음에 선언한다.

인스턴스 변수간에는 공백을 두지 않는다.

 

중요한 것은 클래스의 마지막이든 처음이든 기억하기 쉬운 곳에 모여있어서 언제든 찾을 수 있어야 한다는 점이다.

 

 

2-3. 종속 함수

한 함수 안에서 다른 함수를 호출한다면, 두 함수는 세로로 가까이 배치한다.

또한, 호출하는 함수가 호출받는 함수보다 먼저 배치한다.

프로그램을 위에서 아래로 자연스럽게 읽을 수 있게.

 

책의 목록 5-5에서는  "FrontPage" 라는 상수를 getPageNameOrDefault() 에서 사용한다.

이 메소드는 상위 메소드인 makeResponse() 에서 사용한다.

하지만 이 상수는 makeResponse() 에서 정의하고, 매개변수로 넘겨준다.

makeResponse() 라는 최상단 메소드에서 요청이 없을 때, 어떤 이름으로 페이지를 만들지 알아야 하기에, 상위 클래스에서 정의하고 하위 클래스로 전달해주는 방법을 사용한 것이다.

 

 

2-4. 개념적 유사성

함수간에 종속성이 없다 하더라도, 개념적으로 비슷하다 싶으면 세로로 가까이 배치한다.

public class Assert {
    static public void assertTrue(String message, boolean condition) {
    ...
    }
    
    static public void assertFalse(boolean condition) {
    ...
    }
    
   	static public void assertFalse(String message, boolean condition) {
    ...
    }
    
    static public void assertTrue(boolean condition) {
    ...
    }
}

위 함수는 JUnit 4의 코드다.

개념적으로 유사하고, 명명법이 같고, 기능도 유사하다.

내부적으로는 서로 종속적인 구조긴 하지만, 종속성을 배제하고도 개념적인 이유 때문에 가까이 있어야 한다.

 

 

 

 

 

3. 가로 형식 맞추기

가로도 짧을 수록 좋다,

한 화면에 다 들어갈 수 있도록 조절한다.

저자는 120자 정도의 제한을 둔다고 한다.

 

3-1. 가로 공백과 밀집도

가로 공백은 밀접한 개념과 느슨한 개념을 구분한다.

 

int lineSize = line.length();
totalSize += lineSize;

위의 연산자들은 공백으로 앞과 뒤를 나눴다.

공백으로 왼쪽 요소와 오른쪽 요소를 명확히 구분할 수 있다.

 

 하지만 length() 를 보면 메소드와 괄호는 공백이 없다.

안에 들어갈 매개변수는 함수와 밀접한 관련이 있으므로 공백을 주지 않는다.

 

return (-b + Math.sqrt(determinant)) / (2*b);

연산자의 우선순위를 구분하기 위해서도 가로공백을 이용할 수 있다.

공백이 없는 부분이 먼저, 공백이 있는 부분은 나중에 수행되는 연산이다. 읽기가 편하다.

 

 

3-2. 가로 정렬

인스턴스 변수가 너무 많아서 보기가 힘들어 (접근제어자 변수형 변수이름)으로 구성되는 가로행을 일정한 공간을 차지하도록 정렬하는 것은 좋지 않다.

 

인스턴스 변수가 많다는 것은 클래스를 나눌 여지가 있다는 것이다.

정렬로 해결하지 말고 클래스를 나눠서 해결하도록 한다.

 

 

3-3. 들여쓰기

클래스 안의 인스턴스 변수와 메소드들,

메소드 안의 구현부들, 

if / while / for / try / catch 등 블록안의 구현부들에는 들여쓰기를 적용한다.

 

if(isValidNumber(number)) return result;

위처럼 아주 간단한 함수라도, 들여쓰기를 넣는 것이 보기 편하다.

if(isValidNumber(number)) {
    return result;
}

 

 

 

4. 팀 규칙

팀에 속하여 코드를 작성한다면, 그 팀의 컨벤션을 따른다.

프로젝트를 시작할 때,

괄호를 어디 넣을지, 들여쓰기는 몇 자로 할지, 클래스와 변수와 메서드 이름을 어떻게 지을지 등을 정하고

팀의 규칙에 따라 코드를 작성해야 팀끼리의 소통이 원활히 될 수 있다.

'책읽기 > 클린코드' 카테고리의 다른 글

오류 처리  (0) 2021.01.04
객체와 자료 구조  (0) 2021.01.04
주석  (0) 2020.12.31
Clean한 함수  (0) 2020.12.29
의미있는 이름 짓기  (0) 2020.12.27