코드
https://github.com/rkwhr0010/clean_code/tree/main/src
변경 사항은 git history 참고
코든 코드가 깔끔하고, 일관적이며, 꼼꼼해야 한다.
누군가 이 코드를 봤을 때 전문가가 짰다는 인상을 줘야 한다.
프로그래머라면 조직에 코딩 컨벤션에 따라 코드를 작성해야 한다.
코딩 스타일을 맞추기 위해 툴을 사용할 수 있다면, 사용해야 한다. (예시_ESLint)
형식을 맞추는 목적
코드 형식은 의사소통의 일환
의사소통의 중요성은 말할 필요가 없다.
'돌아만 가능 코드'는 변경에 취약하다.
깨진 창문 효과로 시간이 지남에 따라 더욱 더러워 질 것이다.
그 결과 의사소통이 되지 않는 코드가 된다.
형식을 엄격하게 맞춰 놓는다면, 시간이 지나도 유지보수 용이성이 그대로 유지된다.
개발자는 사라져도 개발자의 스타일과 규율은 사라지지 않는다.
적절한 행 길이를 유지하라
소스 파일 세로 길이
톰캣 같은 경우 500 줄이 넘는 경우도 많다.
Fitnesse 의 경우 대부분 약 30 ~ 100 줄 사이에 위치한다.
Fitnesse 전체 코드 양은 약 5만 줄이다.
이를 보면서 알 수 있는 것은, 200 줄 미만은 작은 파일로도 커다란 시스템을 구축할 수 있다는 것이다.
코드가 작으면, 이해하기 쉽다.
신문 기사처럼 작성하라
기사는 기본적으로 위에서 아래로 읽게 된다.
그리고 하나의 기사가 한 면을 다 차지하는 경우는 거의 없다.
적절한 크기를 가진다.
첫 문단은 표제다. 독자는 표제를 읽고, 더 읽을지 말지를 결정한다.
표제는 자세한 세부사항을 숨기고 커다란 그림을 보여준다.
위에서 아래로 읽을 수록 세부사항이 조금씩 드러난다.
이를 코드에 대입하면,
소스 파일 첫 부분에는 고차원 개념과 알고리즘을 설명한다.
아래로 갈 수록 세부적인 로직이 설명되며,
마지막엔 가장 저차원 함수가 나온다.
개념은 빈 행으로 분리하라
패키지 선언부, import 문, 각 함수 사이 등에서 빈 행으로 구분하는 것을 의미한다.
빈 행으로 구분 안하고, 따닥따닥 붙어있다면, 코드 가독성이 현저히 떨어진다.
세로 밀집도
줄 바꿈은 개념을 분리한다.
세로 밀집도는 연관성을 의미한다.
연관된 코드를 세로로 가까이 있어야 한다.
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); } } |
첫 번째보다 두 번째가 더 한 눈에 들어온다.
스크롤 할 필요가 없다.
수직 거리
함수 연관 관계와 동작 방식을 이해하려고,
스크롤 질 하거나, 더 나아가 조각난 다른 파일로 왔다갔다 뺑뺑이를 돈 적 있다면,
그것이 끔찍한 경험이라는 것을 알 것이다.
이 행위가 전부 시간과 노력을 소모한다.
서로 미접한 개념은 세로로 가까이 둬야 한다.
특별한 이유가 없다면, 밀접한 개념은 같은 파일에 위치해야 한다.
위와 같은 이유로 protected 접근자를 사용을 피해야 한다.
같은 파일 내에 코드는 연관성이 높을 수록 서로 붙어 있어야 한다.
아니면, 소스를 찾느라 스크롤을 많이 해야 한다.
변수 선언
변수 선언은 사용하는 위치에 최대한 가까이 선언해야 한다.
클린 코드 룰을 따르면, 함수는 매우 작아 지게 되므로,
함수 맨 앞에 선언하게 된다.
void something() { for (final Object obj : lists) { //좋은 예 final Object someThing = createInstance(); } } |
인스턴스 변수
보통 클래스 맨 처음에 선언한다.
변수 간 세로 거리는 두지 않는다.
메서드와 메서드 사이에 변수를 선언하면, 가독성이 떨어진다.
종속 함수
함수가 다른 함수를 호출하는 경우를 말한다.
이 경우 종속 함수는 바로 호출하는 함수 아래에 위치해야 한다.
개념적 유사성
종속 함수 같이 직접적인 유사성을 제외하고도
같은 변수를 사용하는 메서드들이나, 비슷한 동작을 수행하는 함수를 말한다.
Junit 좋은 예시
개념적 유사성이 매우 높다.
새로 순서
고차원 함수가 저차원 함수를 호출한다.
즉, 가장 고차원 함수가 가장 앞에, 가장 저차원 함수가 가장 아래 위치해야 한다.
가로 형식 맞추기
대부분 20 ~ 60 사이에 위치한다.
80 행 부턴 급격히 적어진다.
이 자료는 옛날 모니터가 안 좋았던 시절.
현재는 120자 이내로 유지하는 것을 권장한다.
가로 공백과 밀집도
할당 연산자를 구분하기 위해 띄어쓰기
메서드 인수 구분을 위해 콤마 뒤 띄어쓰기
연산자 우선순위 강조를 위한 공백
package chap05.ex04; 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); } public static double root2(int a, int b, int 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; } } |
곱셈이 우선순위가 높아 붙이고, 뺄샘은 띄웠다.
IDE 자동 정렬 기능을 사용하면, 모든 연산자에 동일한 간격을 띄워 위와 같은 포멧이 나오진 않는다.
현실적으로 우선순위가 맞더라도 소괄호를 치는 것이 좋아보인다.
가로 정렬
이렇게 코드를 정렬하면, 좋지 않다.
이렇게 되면, 진짜 목적인 변수 타입을 먼저 읽지 않고, 시선이 변수명으로 먼저 간다.
들여쓰기
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);} public static double root2(int a, int b, int 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; }} |
위 코드는 기계는 정확히 동작하지만, 결국 사람이 볼 때는 하나도 눈에 안들어 온다.
들여쓰기는 코드 구조를 한 눈에 들어오도록 도움을 준다.
기본 들여쓰기 룰은 지키는 것이 좋다.
팀 규칙
중요한 규칙이다. 개인이 선호하는 규칙이 있겠지만, 팀 규칙이 반드시 지켜야 한다.
그래야 소프트웨어가 일관적인 스타일을 유지하게 된다.
'IT책, 강의 > 클린코드(Clean Code)' 카테고리의 다른 글
7장 오류 처리 (0) | 2023.12.25 |
---|---|
6장 객체와 자료 구조 (1) | 2023.12.18 |
4장 주석 (1) | 2023.12.04 |
3장 함수 (1) | 2023.11.27 |
2장 의미 있는 이름 (1) | 2023.11.20 |