5장. 형식 맞추기
5장 형식 맞추기는 규칙과 형식에 맞게 코드를 작성해야 하는 이유와 유형에 대해 설명한다.
형식을 맞추는 목적
코드 형식은 매우 중요하다는 주장과 이에 대해 설명을 시작하기 위한 서론 내용이다.
세로 형식 맞추기
적절한 행의 길이를 유지하라.
일반적으로 큰 파일보다 작은 파일이 이해하기 쉽고 작은 파일들 만으로도 Jnut, Tomcat 등을 만들 수 있다는 것을 보여준다.
(책에선 Junit, FitNesse, testNG, Time and Money, JDepend, Ant, Tomcat의 파일 길이를 조사해 평균을 냈다.)
신문 기사처럼 작성하라.
최상단에 제목, 첫 문단엔 요약, 세세한 사실은 아래 적는 기사와 같이 소스 파일도 이러한 형식을 따라야 한다고 주장한다.
소스 파일 첫 부분은 고차원 개념과 알고리즘 설명을, 내려갈수록 의도를 세세히 묘사하고 마지막엔 가장 저 차원 함수와 세부 내역이 나와야 한다는 것이다.
개념은 빈 행으로 분리하라.
코드는 왼쪽에서 오른쪽, 위에서 아래로 읽히므로 각 행은 수식이나 절을, 일련의 행 묶음은 하나의 생각을 표현한다고 주장한다. 따라서 빈 행을 이용해 생각을 구분해야 한다는 것이다.
아래는 책에서 이를 주장하는 근거이다.
생각을 빈 행으로 분리한 코드
package oncall.controller;
import java.util.regex.*;
public class BoldWidget extends ParentWidget {
public static final String REGEXP = "''";
private static final Pattern pattern = Pattern.compile("'''(.+?)'''",
Pattern.MULTILINE + Pattern.DOTALL);
public BoldWidget(ParentWidget parent, String text) throws Exception {
super(parent);
Matcher match = pattern.matcher(text);
match.find();
addChildWidgets(match.group(1));
}
public String render() throws Exception {
StringBuffer html = new StringBuffer("<b>");
html.append(childHtml()).append("</b>");
return html.toString();
}
}
빈 행으로 분리하지 않은 코드
package oncall.controller;
import java.util.regex.*;
public class BoldWidget extends ParentWidget {
public static final String REGEXP = "''";
private static final Pattern pattern = Pattern.compile("'''(.+?)'''",
Pattern.MULTILINE + Pattern.DOTALL);
public BoldWidget(ParentWidget parent, String text) throws Exception {
super(parent);
Matcher match = pattern.matcher(text);
match.find();
addChildWidgets(match.group(1));}
public String render() throws Exception {
StringBuffer html = new StringBuffer("<b>");
html.append(childHtml()).append("</b>");
return html.toString();
}
}
분리하지 않은 경우 가독성이 떨어짐을 확인할 수 있다.
세로 밀집도
줄 바꿈이 개념을 분리한다면 세로 밀집도는 연관성을 의미하며 따라서 밀집한 코드 행은 세로로 가까이 놓아야 함을 주장한다.
아래는 책에서 설명하는 이유이다.
주석으로 세로 밀집도를 떨어뜨린 코드
class ReporterConfig {
/**
* 리포터 리스너의 클래스 이름
*/
private String m_className;
/**
* 리포터 리스너의 속성
*/
private List<Property> m_properties = new ArrayList<Property>();
public void addProperty(Property property) {
m_properties.add(property);
}
}
세로로 밀집된 코드
class ReporterConfig {
private String m_className;
private List<Property> m_properties = new ArrayList<Property>();
public void addProperty(Property property) {
m_properties.add(property);
}
}
연관성이 있는 코드끼리 세로로 밀집되어 있기에 한눈에 들어온다.
수직 거리
밀접한 코드는 수직으로 거리가 가까워야 한다는 주장과 그 경우에 대해 설명한다.
변수.
변수는 사용하는 위치에 최대한 가까이 선언한다.
인스턴스 변수.
인스턴스 변수는 클래스 맨 처음에 선언한다.
- 변수 간에 세로로 거리를 두지 않는다.(잘 구현한 클래스는 많은 메서드가 인스턴스 변수를 사용하므로)
- 메서드 사이에 선언하면 변수를 '발견'한다.
종속 함수.
종속 함수는 세로로 가까이에 배치한다. 호출하는 함수를 호출되는 함수 위에 배치한다.
- 독자는 호출한 함수가 잠시 후에 정의될 것이라는 사실을 예측한다.
- 가독성이 높아진다.
개념적 유사성.
친화도가 높을수록 코드를 가까이에 배치한다.
- 한 함수가 다른 함수를 호출하는 등 종속성이 있는 경우
- 변수와 그 변수를 사용하는 함수의 경우
- 비슷한 동작을 하는 일군의 함수
아래는 비슷한 동작을 하는 일군의 함수를 모아놓은 코드이다.
메서드 이름, 형식이 비슷하기에 눈에 잘 들어오는 것을 확인할 수 있다.
public class Assert {
static public void assertTrue(String message, boolean condition) {
...
}
static public void assertTrue(boolean condition) {
...
}
static public void assertFalse(String message, boolean condition) {
...
}
static public void assertFalse(boolean condition) {
...
}
}
가로 형식 맞추기
한 행의 가로길이는 개인적으로 120자 아래가 좋다는 주장이다.
(이는 저자의 생각이므로 개인적으로 판단해야 하는 문제로 보인다.)
가로 공백과 밀집도
가로 공백을 넣거나 넣지 않는 것으로 느슨하거나 밀접한 관계를 표현할 수 있다고 주장한다.
예로
- 함수 이름과 이어지는 괄호 사이에는 공백을 넣지 않는다.
- 할당 연산자를 강조하기 위해 앞뒤에 공백을 넣는다.
- 쉼표를 강조하기 위해 뒤에 공백을 넣는다.
- 연산자 우선순위를 강조하기 위해 공백을 넣는다.
와 같은 경우가 있다.
가로 정렬
아래는 가로 정렬을 한 코드이다.
public class FitNesseExpediter implements ResponseSender {
private Socket socket;
private InputStream input;
private OutputStream output;
private Request request;
private Response response;
private FitNesseContext context;
private long requestProgress;
...
public FitNesseExpediter(Socket s, ...) {
this.context = context;
socket = s;
input = s.getInputStream();
...
}
}
위와 같은 코드는 코드가 엉뚱한 부분을 강조해 유용하지 못하다는 주장이다.
(선언부를 읽다 보면 변수 유형은 무시하고 변수 이름부터 읽게 된다거나 연산자보다 오른쪽 피연산자에 눈이 가는 등)
따라서 가로 정렬은 하지 않는 것이 좋으며 정렬이 필요하다고 느껴진다면 문제는 정렬 부족이 아니라 목록 길이라는 설명이다.
들여 쓰기
범위로 계층을 표현하기 위해 들여 쓰기가 사용되며 범위를 이동하거나 내용을 이해하기에 매우 중요하다는 주장이다.
저자는 때때로 간단한 if문이나 while문에서 들여 쓰기를 무시하고 싶은 유혹이 생기는데, 원점으로 돌아가 들여 쓰기를 넣는다고 한다.
가짜 범위
빈 while문이나 빈 for문으로 인해 골탕 먹지 않기 위해 아래와 같이 작성해야 한다는 설명이다.
while (dis.red(buf, 0, readBufferSize) != -1)
;
팀 규칙
팀에 속한다면 자신이 선호해야 할 규칙은 팀 규칙이라는 주장이다.
느낀 점
형식을 맞추는 것은 협업을 함에 있어서 팀원에게 피해를 끼치지 않기 위한 가장 기본적인 요소라고 생각한다.
그런 점에서 유용한 장이었으며 특히 세로 형식 맞추기의 내용이 지키기 쉬우면서도 중요한 부분으로 보인다.
'OOP & CleanCode' 카테고리의 다른 글
CleanCode - 6. 객체와 자료 구조 (1) | 2024.11.30 |
---|---|
CleanCode - 4. 주석 (1) | 2024.01.02 |
CleanCode - 3. 함수 (1) | 2023.12.23 |
CleanCode - 1. 깨끗한 코드, 2. 의미 있는 이름 (2) | 2023.10.21 |