본문 바로가기
개발/Clean Code

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

by 달사쿠 2020. 12. 1.
반응형

Intro

 

코드의 형식을 맞추는 목적이 무엇일까?

깔끔하고, 일관적이며, 꼼꼼하고, 질서정연한 코드라고 느껴지는 코드는 어떤 코드일까?

 

책에서는, 그리고 나 또한 공감하는 부분으로써

가독성이 높고, 형식을 깔끔하게 맞춰서 규칙을 착실하게 지키는 코드를 보면 '깔끔하다', '질서정연하다', '진짜 잘짰다' 싶은 생각이 드는 것 같습니다. 이건 팀으로 일할 경우에도 합의하여 규칙을 정하고, 모두가 그 규칙을 따른다면 깔끔하고 잘짰다는 인상을 줄 수 있는 것 같아요.

 

책에서 필자는 다음과 같이 얘기를 합니다.

오늘 구현한 코드의 가독성은 앞으로 바뀔 코드의 품질에 지대한 영향을 미친다.
... 코드가 많이 바뀌어도 맨 처음 잡아놓은 구현스타일과 가독성 수준은 유지보수 용이성과 확장성에 계속 영향을 미친다.

그렇기 때문에 원래의 코드는 사라질지라도 개발자의 스타일과 규율을 사라지지 않아 형식을 지키는 것이 중요하다고 합니다.

 

저또한 형식을 지키는 것의 중요성에 대해서는 인지하고 있지만, '룰'이라는 것을 100% 다 지키지는 못했던 것 같습니다. 때로는 '룰'조차도 만들지 않았던 적도 있었구요. 아직 제대로된 프로젝트를 경험하지 못해서 그렇다고 변명을 해보고 싶지만, 어찌되었든 유지보수 측면에 있어서도 가독성과 형식은 굉장히 중요하다는 것은 저또한 인지하고 있는 것 같습니다.

 

본 책에서는 '원활하게 소통을 장려하기 위해 코드의 형식을 어떻게 하는 것이 좋은가?'라는 주제로 5장을 풀어나갔습니다.

크게 다음의 3가지 방법이 소개되었고, 각각의 토픽에 대해서 상세한 방법에 대해 언급했습니다.

- 적절한 행 길이를 유지해라
- 가로형식 맞추기
- 팀 규칙

본격적으로 책에서 소개하는 형식맞추기에 대해서 포스팅해보겠습니다.

 


적절한 행 길이를 유지해라

소스코드는 얼마나 길어야 적당할까? (자바에서 파일크기는 클래스의 크기와 밀접)

=> 500줄을 넘지 않고 대부분 200줄 정도인 파일로도 커다란 시스템을 구축할 수 있다.

신문 기사처럼 작성하라

좋은 신문 기사를 떠올리면, 독자는 위에서 아래로 기사를 읽는다. 소스파일도 신문 기사와 비슷하게 작성한다.

나는 고차원 개념과 저차원함수가 정확이 어떤 것을 의미하는지는 잘 모르겠다. 다만 메인함수와 같은 중요한 코드는 상단에 배치하고, 메인함수에 구성된 부가적인 코드는 하단에 배치를 해라라는 의미인 것 같다. 개인적인 생각으로는 이런 고차원 개념(메인 함수?)을 첫 부분으로 올림으로써 최대한 구성하고 있는 함수나 변수명은 좋은 네이밍을해서 알아보기 쉽게 하는 것도 중요할 것 같다. 그래야 코드의 의도를 표현한 저차원 함수에서 이해를 더 풍부하게 해줄 수 있을 것 같다는 생각이 든다.

 

개념은 빈 행으로 분리하라

일반적으로 행 묶음은 완결된 생각를 표현한다. 코드에서도 이 생각 사이에 빈 행을 넣어 분리해야 한다.

빈 행은 새로운 개념을 시작한다는 시각적 단서이기도 하다.

즉, 함수와 함수사이, 함수 내의 코드에서 생각의 단위 사이에도 빈 행으로 표현하는 것이 좋다.

 

세로 밀집도

줄바꿈이 개념을 분리한다면 세로 밀집도는 연관성을 의미한다.

즉, 서로 밀접한 코드 행은 가까이 놓여야한다는 뜻이다.

예를 들어, 밀접한 두 코드를 중요하지 않은 주석으로 떨어뜨려 놓는 것은 코드가 한눈에 들어오는 것을 방해할 수 있다.

 

수직 거리

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

같은 파일에 속할 정도로 밀접한 두 개념은 세로 거리로 연관성을 표현한다.

여기서 연관성이란 한 개념을 이해하는 데 다른 개념이 중요한 정도다. 연관성이 깊은 두 개념이 멀리 떨어져 있으면 코드를 읽는 사람이 소스 파일과 클래스를 여기저기 뒤지게 된다.

 

시스템이 무엇을 하는지 이해하고 싶은데, 이 조각 저조각 어디에 있는지 찾고 기억하느라 시간과 노력을 소모하지 말자.

 

변수 선언

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

지역변수는 각 함수 맨 처음, 블록 상단, 루프 직전에 선언한다.

루프를 제어하는 변수는 루프문 내부에 흔히 선언한다.

 

인스턴스 변수

인스턴스 변수는 클래스 맨 처음에 선언하고, 변수간의 세로로 거리를 두지 않는다.

선언하는 위치는 아직도 논쟁이 분분하지만, 자바에서는 보통 클래스 맨 처음에 선언하고 C++에서는 가위 규칙(scissors rule)을 적용하여 클래스 마지막에 보통 선언하기도 한다.

중요한 것은 잘 알려진 위치에 인스턴스 변수를 모은다는 사실이 중요하다.

 

종속 함수

한 함수가 다른 함수를 호출한다면 두 함수는 세로로 가까이 배치한다. 또한 가능하다면 호출하는 함수를 호출되는 함수보다 먼저 배치한다.

이렇게 배치하면 호출되는 함수를 찾기 쉬워지며, 그만큼 모듈 전체의 가독성도 높아진다.

 

개념적 유사성

코드간의 개념적인 친화도가 높다면 가까이 배치한다.

친화도가 높은 요인으로는 다음과 같은 예들이 있다.

- 한 함수가 다른 함수를 호출해 생기는 직접적인 종속성
- 변수와 그 변수를 사용하는 함수
- 동작을 수행하는 일군의 함수 (ex. assertTrue, assertFalse(A a), assertFalse(A a, B b))

 

세로 순서

함수 호출 종속성은 아래 방향으로 유지한다. 즉, 호출되는 함수를 호출하는 함수보다 나중에 배치한다.

 


가로 형식 맞추기

한 행은 가로로 얼마나 길어야 적당할까?

명백한 것은 프로그래머는 짧은 행을 선호하고, 필자는 120자 정도로 행 길이를 제한하는 것을 추천했다. 

책에서 소개한 자료에 따르면, 0~60자 이하의 행은 각각이 총 행의 수 1%이상을 차지하지만, 61자 이상의 경우에는 1%도 차지하지 못하며 글자수가 길어질 수록 행 수가 급격하게 감소한다.

 

가로 공백과 밀집도

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

private void measureLine(String line) {
   lineCount++;
   int lineSize = line.length();
}

할당연산자는 앞뒤에 공백을 주어 왼쪽 요소와 오른쪽 요소가 확실히 나뉜다는 것을 강조할 수 있다.

반면, 함수 이름과 이어지는 괄호 사이에는 함수와 인수가 서로 밀접하기 때문에 공백을 넣지 않았다.

 

더불어 연산자 우선순위를 강조하기 위해서 공백을 사용하기도 한다. 

 

가로 정렬

이건 예제코드를 보는 것이 더 이해가 잘 갈 것 이다.

//refactoring 전 코드
public class FitNessExpenditer implements ResponseSender
{
   private Socket          socket;
   private InputStream     input;
   private FitNesseContext context;
}

public FitNEsseExpenditer(Socket s, FitNesseContext context) throws Exception
{
   this.context = context;
   socket       = s;
   input        = s.getInputStream();
}

이런 정렬은 코드가 엉뚱한 부분을 강조해 의도가 가려질 수 있다. 예를 들어, 변수 유형을 무시하고 변수이름부터 읽을 수 있다.

따라서 위에처럼 작성하지 않고 아래처럼 작성하도록 하자.

//refactoring 전 코드
public class FitNessExpenditer implements ResponseSender
{
   private Socket socket;
   private InputStream input;
   private FitNesseContext context;
}

public FitNEsseExpenditer(Socket s, FitNesseContext context) throws Exception
{
   this.context = context;
   socket = s;
   input = s.getInputStream();
}

 

들여쓰기

들여쓰기한 파일은 구조가 한눈에 들어온다. 하지만 들여쓰기를 하지 않은 일명 스파게티 코드는 열심히 분석하지 않는 한 이해하기가 힘들다.

들여쓰기 무시하기
때로는 간단한 if/while 문에서 들여쓰기 규칙을 무시하고 픈 유혹이 생긴다.
그러지 말고, 꼭 들여쓰기를 넣도록 하자..

 

가짜 범위

때로는 빈 while문이나 for문을 접하는데, 이럴 경우에는 빈 블록을 올바로 들여쓰고 괄호로 감싼다.

빈 블록의 반복문의 경우 잘 보이지 않으므로, ;(세미콜론)의 경우에는 새행에 적어서 눈에 띄게 해주자!

while(dis.read(buf, 0, readBufferSize) != -1)
;

팀 규칙

  1. 팀과 마주앉아 코드스타일에 대해서 논의를 하자.
    • 어디에 괄호를 넣을지
    • 들여쓰기는 몇 자로 할지
    • 클래스와 변수와 매서드 이름은 어떻게 지을지
    • ...
  2. 정한 규칙으로 IDE 코드 형식기를 설정하여 사용한다.

회고

반성을 많이 했던 챕터였다. 세로와 가로적인 측면에서 모두 가장 중요한 것은 얼마나 연관성/밀접성이 있는지에 따라 코드의 위치가 달라져야 한다는 것이 주 내용이었던 것 같다.

마음속에 가장 와닿은 말이 있는데, 이 조각 저조각 어디에 있는지 찾고 기억하느라 시간과 노력을 소모하지 말자. 라는 말을 명심하여 소스 코드를 배치하는 습관을 들여야겠다.

코드스타일의 경우, 지금 재직중인 회사에서는 정해진 규칙이 따로 있다.

사실 명심하고 있던 부분이 아니였는데, 일관적인 코드를 작성하기 위해서는 반드시 명심해야겠다.

반응형

'개발 > Clean Code' 카테고리의 다른 글

[오브젝트] 9장 유연한 설계  (0) 2021.06.03
[Clean Code] 15장. JUnit 들여다보기  (0) 2021.03.08
[Clean Code] 10장. 클래스  (2) 2021.01.03
[Clean Code] 4장. 주석(comments)  (0) 2020.11.24
Clean Code에 대하여  (0) 2020.11.23

댓글