이 글은 개발자 필독서인 클린 코드를 읽으며 습득한 내용을 정리한 글입니다. 모든 출처는 해당 저서에 있습니다.
빈 행은 새로운 개념을 시작한다는 시각적 단서를 제공한다.
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 {
StringBufer html = new TringBuffer("<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 {
StringBufer html = new TringBuffer("<b>");
html.append(childHtml()).append("</b>");
return html.toString();
}
}
세로 밀집도는 연관성을 의미한다. 서로 밀접한 코드 행은 세로로 가까이 놓도록 한다.
public class ReporterConfig {
/**
* 리포터 리스너의 클래스 이름
*/
private String m_className;
/**
* 리포터 리스너의 속성
*/
private List<Property> m_properties = new ArrayList<>();
public void addProperty(Property property) {
m_properties.add(property);
}
}
public class ReporterConfig {
private String m_className;
private List<property> m_properties = new ArrayList<>();
public void addProperty(Property property) {
m_properties.add(property);
}
}
public int countTestCases() {
int count = 0;
for (Test each : tests) {
count += each.countTestCases();
}
return count;
}
...
for( XmlTest test : m_suite.getTests()) {
TestRunner tr = m_runnerFactory.netTestRunner(this, test);
tr.addListener(m_testReporter);
m_testRunners.add(tr);
invoker = tr.getInvoker();
for (ITestNGMethod m : tr.getBeforeSuiteMethods()) {
beforeSuiteMethods.put(m.getMethod(), m);
}
for (ITestNGMethod m : tr.getAfterSuiteMethods()) {
afterSuiteMethods.put(m.getMethod(), m);
}
}
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);
}
}
...
짧은 행이 바람직하다. 20자에서 60자 사이를 권장하며, 아무리 길어도 120자는 넘지 않도록 한다.
int lineSize = line.length();
private void measureLine(String line) { ... }
recordWidestLine(lineSize);
public class Quadratic {
public static double root(double a, double b, double c) {
double determinant = determinant(a, b, c);
return (-b + Math.sqrt(determinant)) / (2*a);
}
private static double determinant(double a, double b, double c) {
return b*b - 4*a*c;
}
}
public class FitNesseExpediter implements ResponseSender {
private Socket socket;
private InputStream input;
private OutputStream output;
private FitNesseContext context;
protected long requestParsingTimeLimit;
...
public FitNesseExpediter(Socket s,
FitNesseContext context) throws Exception {
this.context = context;
socket = s;
input = s.getInputStream();
output = s.getOutputStream();
requestParsingTimeLimt = 10000;
}
}
소스 파일은 계층이 존재한다.
파일 전체 ⊃ 파일 내 개별 클래스 ⊃ 클래스 내 각 메소드 ⊃ 블록 내 블록
범위(scope)로 이루어진 계층을 표현하기 위해 코드 들여쓰기를 한다.
들여 쓰는 정도는 계층에서 코드가 자리 잡은 수준에 비례한다.
수준 | 들여쓰는 정도 | 비고 |
---|---|---|
파일 | 들여쓰지 않음 | 클래스 정의 |
클래스 내 메소드 | 클래스보다 한 수준 들여씀 | |
메소드 코드 | 메소드 선언보다 한 수준 들여씀 | |
블록 코드 | 블록을 포함하는 코드보다 한 수준 들여씀 |
왼쪽으로 코드를 맞춰 코드가 속하는 범위를 시각적으로 표현한다.
이를 통해 구조가 한 눈에 들어와 파악하기 쉬워진다.
한 행에 범위를 뭉뚱그린 코드는 피한다.
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 (dis.read(buf, 0, readBufferSize) != -1)
;
📖 참고
- 로버트 C. 마틴, 『Clean Code 클린 코드 애자일 소프트웨어 장인 정신』, 박재호·이해영 옮김, 케이앤피북스(2010), p125-146.