우리가 어떤 글을 볼 때, 가독성이 좋다고 느끼는 경우가 있다. 그런 경우 대부분 글의 형식이 잘 갖춰져 있다는 전제가 성립된 채로 글이 작성되었기 때문이다.
소스 코드도 마찬가지로 일종의 글이기 때문에 형식을 잘 갖춰서 작성한다면 깨끗한 코드를 작성하는데 탄탄한 기반이 될 수 있을 것이다.
오늘 구현한 기능이 다음 버전에서 바뀔 확률은 아주 높다. 그런데 오늘 구현한 코드의 가독성은 앞으로 바뀔 코드의 품질에 지대한 영향을 미친다.
"사과를 너는 건내라 나에게" ❌
"나에게 사과를 주세요" ⭕️
오랜 시간이 지나 원래 코드의 흔적을 더 이상 찾아보기 어려울 정도로 코드가 바뀌어도 맨 처음 잡아놓은 구현 스타일과 가독성 수준은 유지보수 용이성과 확장성에 계속 영향을 미친다.
200줄 정도인 파일로도 커다란 시스템을 구축할 수 있다. 일반적으로 큰 파일보다 작은 파일이 이해하기 쉽다.
(예전에 야곰 리뷰어가 추천한 파일 길이는 기본 200줄 이내, 최대 250줄 이내)
크게 요약된 내용에서 점차 상세 내용이 나오도록 작성하라
개념 사이는 빈 행을 넣어 분리하라
줄바꿈이 개념을 분리한다면 세로 밀집도는 연관성을 의미한다. 서로 밀접한 코드 행은 세로로 가까이 놓여야 한다.
🚫 Bad - (쓸데없는) 주석으로 밀접한 개념을 떨어뜨려놓은 코드
public class ReporterConfig {
/*
* 리포터 리스너의 클래스 이름
*/
private var className = String()
/*
* 리포터 리스너의 속성
*/
private var properties: [Property] = [Property]()
public func addProperty(property: Property) {
properties.append(property)
}
}
👍 Correct
public class ReporterConfig {
private var className = String()
private var properties: [Property] = [Property]()
public func addProperty(property: Property) {
properties.append(property)
}
}
서로 밀접한 개념은 한 파일에 두고 세로 거리로 연관성을 표시한다.
함수의 동작 방식과 연관 관계를 살피다보면 소스 코드를 위아래로 뒤지게 된다. 이 작업은 꽤 많은 시간과 노력을 들이게 만든다. 이런 경우를 피하기 위해 밀접한 개념은 한 파일에 두는 것이 좋다.
또 그 중에서 서로 연관성이 깊은 함수끼리는 세로 거리를 가까이 두는게 좋다. 그렇지 않다면 함수를 찾기위해 코드를 위아래로 뒤져보아야하기 때문이다.
변수는 사용하는 위치에 최대한 가까이 두어야한다. 단, 함수가 짧을 경우 지역 변수는 함수 맨 위에 선언하도록 한다. 단 루프 변수(i, j, k)는 일반적으로 루프문 내부에서 선언하고 사용한다.
func A() {
B()
}
func B() { ... }
짧은 가로 길이를 사용하면서 역시 좋은 프로젝트들을 만들 수 있음
7개 프로젝트의 평균을 분석해보니 약 40% 정도가 20~60글자 사이를 갖고있다.
(저자는) 120자 정도의 행 길이를 제한한다.
야곰에서 다 배움(컨벤션)
var lineSize = line.count
recordWidestLine(lineSize)
lineWidthHistogram.addLine(lineSize, lineCount)
b*b - 4*a*c
어셈블리어 같은 가로 정렬은 엉뚱한 부분을 강조해서, 진짜 의도를 가릴 수가 있다.
public class FitNesseExpediter: ResponseSender {
private var socket: Socket
private var input: InputStream
private var output: OutputStream
private var requestProgress: Double
public func FitNesseExpediter(s: Socket,
context: FitNesseContext) throws {
socket = s
input = s.getInputStream()
output = s.getOutputStream()
requestProgress = 10000
}
}
위와 같은 정렬은 별로 유용하지 못하다.
선언문과 할당문은 별도로 정렬하지 않는다.
🚫 Bad
public class CommentWidget: TextWidget {
public func render() -> String { return "" }
}
👍 Correct
public class CommentWidget: TextWidget {
public func render() -> String {
return ""
}
}
온갖 스타일을 섞으면 나중에 골치가 아파진다. 팀에 속한 팀원들은 반드시 팀에서 정한 규칙에 따라 소스 코드를 작성해야한다.
목적
코드 형식은 의사소통의 일환임. ‘돌아가는 코드'를 짜는 것이 우리의 목적이 아님. 다음 버전에서 기능은 바뀔 가능성이 매우 높지만, 스타일과 가독성 수준은 계속 영향을 미친다.