형식을 맞추는 목적
- 코드 형식은 의사소통의 일환이다. 의사소통은 전문 개발자의 일차적인 의무다.
- 오랜 시간이 지나 원래 코드의 흔적을 더 이상 찾아보기 어려울 정도로 코드가 바뀌어도
맨 처음 잡아놓은 구현 스타일과 가독성 수준을 유지보수 용이성과 확장성에 계속 영향을 미친다.
적절한 행 길이를 유지하라
- 500줄을 넘지 않고 대부분 200줄 정도인 파일로도 커다란 시스템을 구축할 수 있다.
- 반드시 지킬 엄격한 규칙은 아니지만 바람직한 규칙으로 삼으면 좋겠다.
- 일반적으로 큰 파일보다 작은 파일이 이해하기 쉽다.
- 이름은 간단하면서도 설명이 가능하게 짓는다.
- 소스 파일 첫 부분은 고차원 개념과 알고리즘을 설명한다.
- 아래로 내려갈수록 의도를 세세하게 묘사한다.
- 마지막에는 가장 저차원 함수와 세부 내역이 나온다.
- 각 행은 수식이나 절을 나타내고, 일련의 행 묶음은 완결된 생각 하나를 표현한다.
- 생각 사이는 빈 행을 넣어 분리해야 마땅하다.
- 빈 행은 새로운 개념을 시작한다는 시각적 단서다.
- 줄바꿈이 개념을 분리한다면 세로 밀집도는 연관성을 의미한다. 즉, 서로 밀접한 코드 행은 세로로 가까이 놓여야 한다.
// bad
public class ReporterConfig {
/**
* 리포터 리스너의 클래스 이름
*/
private String m_className;
/**
* 리포터 리스너의 속성
*/
private List<Property> m_properties = new ArrayList<Property>();
public void addProperty(Property property) {
m_properties.add(property);
}
}
// good
// 변수 2개에 메서드 1개인 클래스
public class ReporterConfig {
private String m_className;
private List<Property> m_properties = new ArrayList<Property>();
public void addProperty(Property property) {
m_properties.add(property);
}
}
- 서로 밀접한 개념은 세로로 가까이 둬야 한다. 같은 파일에 속할 정도로 밀접한 두 개념은 세로 거리로 연관성을 표현한다.
연관성이란 한 개념을 이해하는 데 다른 개념이 중요한 정도다.
- 연관성이 깊은 두 개념이 멀리 떨어져 있으면 코드를 읽는 사람이 소스 파일과 클래스를 여기저기 뒤지게 된다.
- 변수는 사용하는 위치에 최대한 가까이 선언한다. 루프를 제어하는 변수는 흔히 루프 문 내부에 선언한다.
아주 드물지만 가소 긴 함수에서 블록 상단이나 루프 직전에 변수를 선언하는 사례도 있다.
- 인스턴스 변수는 클래스 맨 처음에 선언한다. 변수 간에 세로로 거리를 두지 않는다.
- 한 함수가 다른 함수를 호출하는 종속 함수의 두 함수는 세로로 가까이 배치한다.
또한 가능하다면 호출하는 함수를 호출되는 함수보다 먼저 배치한다. 그러면 프로그램이 자연스럽게 읽힌다.
- 개념적 친화도가 높아 서로 끌어당기는 코드는 가까이 배치한다.
// good
// 한 함수가 다른 함수를 호출해 생기는 직접적인 종속성
// 변수와 그 변수를 사용하는 함수
// 비슷한 동작을 수행하는 일군의 함수
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 meassage, boolean condition) {
assertTrue(message, !condition);
}
static public void assertFalse(boolean condition) {
assertFalse(null, condition);
}
...
}
가로 형식 맞추기
- 80자 이후부터 행 수는 분포는 급격하게 감소한다. 프로그래머는 명백하게 짧은 행을 선호한다.
- 100자나 120자에 달해도 나쁘지 않다. 하지만 그 이상은 솔직히 주의부족이다.
개인적으로는 120자 정도로 행 길이를 제한한다.
- 가로로는 공백을 사용해 밀접한 개념과 느슨한 개념을 표현한다.
// good
private void measureLine(String line) { // 함수와 인수는 서로 밀접하므로 공백을 넣지 않음
lineCount++;
int lineSize = line.length(); // 할당 연산자를 강조하기 위한 공백을 통해 왼쪽 요소와 오른쪽 요소를 나눔
lineWidthHistogram.addLine(lineSize, lineCount); // 공백와 쉼표를 이용해 인수를 분리해 별개라고 강조
}
public class Quadratic {
public static double root1(double a, double b, double c) {
double determinant = determinant(a, b, c);
// 곱셈은 우선순위가 가장 높기 때문에 승수 사이는 공백이 없음
// 덧셈과 뺄셈은 우선순위가 곱셈보다 낮기 때문에 항 사이에는 공백이 들어감
return (-b + Math.sqrt(determinant)) / (2*a);
}
}
// bad
private Socket socket;
private InputStream input;
private OutputStream output;
// good
private Socket socket;
private InputStream input;
private OutputStream output;
- 파일 전체에 적용되는 정보가 있고, 파일 내 개별 클래스에 적용되는 정보가 있고,
클래스 내 각 메서드에 적용되는 정보가 있고, 블록 내 블록에 재귀적으로 적용되는 정보가 있다.
이렇듯 범위로 이뤄진 계층을 표현하기 위해 코드를 들여쓴다.
- 간단한 if 문, 짧은 while 문, 짧은 함수에서 한 행에 범위를 뭉뚱그린 코드를 피하고 들여쓰기를 넣는다.
- 빈 while 문이나 for 문의 경우 빈 블록을 올바로 들여쓰고 괄호로 감싼다.
팀 규칙
- 팀은 한 가지 규칙에 합의해야 한다. 그리고 모든 팀원을 그 규칙을 따라야 한다.
- 한 소스 파일에서 봤던 형식이 다른 소스 파일에도 쓰이리라는 신뢰감을 독자에게 줘야 한다.
- 온갖 스타일을 뒤섞어 소스 코드를 필요 이상으로 복잡하게 만드는 실수는 반드시 피한다.