오랜만에 클린코드 다시 읽는다.
그동안 공부를 안한 건 아니지만 습관이 역시 끊기면 이렇게 된다 ㅠㅠ
5장부터 다시 스타트.
5. 형식 맞추기
형식을 맞추는 목적
- 코드 형식은 의사소통의 일환이다. 의사소통은 전문 개발자의 일차적인 의무다.
적절한 행 길이를 유지하라
- JUnit, FitNess, Time and Money, testNG, JDepend, Ant, Tomcat 프로젝트들을 서로 비교해보면 코드 줄이 적어도 커다란 시스템을 구축할 수 있다는 사실을 알 수 있다. 반드시 그럴 필요는 없지만 줄여보도록 노력하자.
신문 기사처럼 작성하라
- 이름은 간단하면서도 설명이 가능하게 짓는다. 이름만 보고도 올바른 모듈을 살펴보고 있는지 아닌지를 판단할 정도로 신경 써서 짓는다. 소스 파일 첫 부분은 고차원 개념과 알고리즘을 설명한다. 아래로 내려갈수록 의도를 세세하게 묘사한다. 마지막에는 가장 저차원 함수와 세부 내역이 나온다.
개념은 빈 행으로 분리하라
- 예제 코드와 함께 보자. 행이 없으면 코드 가독성이 현저하게 떨어진다.
package fitnesse.wikitext.widgets;
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 fitnesse.wikitext.widgets;
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();
}
}
세로 밀집도
- 줄바꿈이 개념을 분리한다면 세로 밀집도는 연관성을 의미한다. 즉, 서로 밀집한 코드 행은 세로로 가까이 놓여야 한다는 뜻이다.
public 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 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) {
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);
}
...생략
위 함수들은 개념적인 친화도가 매우 높다. 명명법이 똑같고 기본 기능이 유사하고 간단하다. 서로가 서로를 호출하는 관계는 부차적인 요인이다. 종속적인 관계가 없더라도 가까이 배치할 함수들이다.
가로 형식 맞추기
- 가로도 짧은 행이 바람직하다. 100~120자 정도면 적당하다고 책에서는 말하고 있다. (비록 모니터가 크더라도...)
가로 공백과 밀집도
- 가로로는 공백을 사용해 밀접한 개념과 느슨한 개념을 표현한다. 아래 함수를 보자.
private void measureLine(String line) {
lineCount++;
int lineSize = line.length();
totalChars += lineSize;
lineWidthHistogram.addLine(lineSize, lineCount);
recordWidestLine(lineSize):
}
할당 연산자를 강조하려고 앞뒤에 공백을 줬다. 할당문은 왼쪽 요소와 오른쪽 요소가 분명히 나뉜다. 공백을 넣으면 두 가지 요소가 확실히 나뉜다는 사실이 더욱 분명해진다.
반면, 함수 이름과 이어지는 괄호 사이에는 공백을 넣지 않았다. 함수와 인수는 서로 밀접하기 때문이다.
연산자 우선순위를 강조하기 위해서도 공백을 사용한다.
가로 정렬
- 코드를 먼저 보도록 하자.
public class FitNessExpediter implements ResponseSender
{
private Socket socket;
private InputStream input;
private OutputStream output;
private Request request;
...
}
이런 코드는 유용하지 못하다. 코드가 엉뚱한 부분을 강조해 진짜 의도가 가려지기 때문이다. 예를 들어, 위 선언부를 읽다 보면 변수 유형은 무시하고 변수 이름부터 읽게 된다.
들여쓰기 무시하기
- 때로는 들여쓰기를 안하고 싶기도 하다. 하지만 한 행에 다 작성하기 보다는 펼치는 것이 났다.
public class CommentWidget extends TextWidget
{
public static final String REGEXP = "^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";
public CommentWidget(ParentWidget parent, String text){super(parent, text);}
public String render() throws Exception {return ""; }
}
// 들여쓰기를 적용하자.
public class CommentWidget extends TextWidget {
public static final String REGEXP = "^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";
public CommentWidget(ParentWidget parent, String text) {
super(parent, text);
}
public String render() throws Exception {
return "";
}
}
가짜 범위
- 때로는 빈 while 문이나 for 문을 접한다. 이런 경우 빈 블록을 올바로 들여쓰고 괄호로 감싼다. 그리고 세미콜론은 세 행에다 제대로 들여써서 넣어준다.
while (dis.read(buf, 0, readBufferSize) != -1)
;
팀 규칙
- 팀은 한 가지 규칙에 합의해야 한다. 그리고 모든 팀원은 그 규칙을 따라야 한다.
'IT 공부 > Clean Code' 카테고리의 다른 글
Clean Code 요약해보기 (6) (0) | 2022.05.18 |
---|---|
Clean Code 요약해보기 (5) (0) | 2022.05.11 |
Clean Code 요약해보기 (3) (0) | 2022.03.16 |
Clean Code 요약해보기 (2) (0) | 2022.03.14 |
Clean Code 요약해보기 (1) (0) | 2022.03.08 |
댓글