프롤로그
사무실 구석에 놓여있던 클린 코드 책이 갑자기 눈에 들어와 가져와 읽기 시작했다. 몇 개월전에 선배가 읽어보라고 추천해줬던 기억이 있는데, 이제서야 읽게 되었다.
2. 의미있는 이름
프로그래머는 매 순간 이름을 짓는다.
의도를 분명히 밝혀라
- 의도가 분명한 이름은 짓는 것은 정말로 중요하다.
그릇된 정보를 피하라
- list가 아닌 것에는 list를 붙이지 마라(타입을 뒤에 붙이지 않는 것을 추천)
의미있게 구분하라
- zork라는 이름을 쓰고 있다고 새 변수를 thezork라고 지으면 안된다.
발음하기 쉬운 이름을 사용하라
- genymdhms 이런 변수는 쓰지마라
검색하기 쉬운 이름을 사용하라
- WORK_DAYS_PER_WEEK와 같은 단어는 찾기 쉽지만, 5같은 숫자는 찾기 어렵다.
인코딩을 피하라
자신의 기억력을 자랑하지 마라
- 루프의 반복변수(i,j) 정도 외에 한글자로 이름짓지 말라
- 명료함이 최고다
클래스이름은 명사구로 지어라
메서드이름은 동사구가 적합하다
기발한 이름은 피하라
- kill()대신 whack()라고 짓지 마라
한 개념에 한 단어를 사용하라
- 똑같은 메서드를 클래스마다 fetch, get, retrieve라고 짓는 일은 하지 말라
말장난을 하지마라
- 전부 add를 쓰고 있다고 다른 동작을 하는 새 메서드에 add라고 붙여선 안된다. 그것을 말장난이다.
해법 영역에서 가져온 이름을 사용하라
- 코드를 읽는 사람도 프로그래머이므로, 전산 용어, 알고리즘 용어 등을 사용해도 괜찮다.
문제 영역에서 가져온 이름을 사용하라
의미있는 맥락을 추가하라
- firstName, state, housdeNumber 같은 변수를 사용한다면, 변수에 Addr 접두어를 붙이거나, Address클래스를 만들어 맥락을 표현하는 것이 좋다.
불필요한 맥락을 없애라
- GSD라는 이름의 애플리케이션을 만든다고, 모든 모듈이나 클래스에 GSD 접두어를 붙이지 마라.
3. 함수
어떤 프로그램이든 가장 기본적인 단위는 함수이다.
작게 만들어라!
- 함수는 작게 만들어야한다.
한 가지만 해라!
- 함수는 한 가지를 해야 한다. 그 한 가지를 잘해야 한다. 그 한 가지만을 해야 한다.
함수 당 추상화 수준은 하나로!
- 함수가 한 가지를 하기 위해서는 추상화 수준이 동일해야 한다.
- getHTML()과 append(“\n”)은 추상화 수준이 다르다.
- 내려가기 규칙 : 위에서 아래로 내려갈 수록 추상화 수준이 낮아지도록 작성
서술적인 이름을 사용하라!
- 이름이 길어도 괜찮다. 길고 서술적인 이름이 짧고 어려운 이름보다 좋다.
함수 인수
- 함수에서 이상적인 인수의 개수는 0개 이고, 3개 이상은 피하는 게 좋다.
- 인수가 많아질수록 이해하기 어렵다.
- 플래그 인수는 추하다.
부수효과를 일으키지 마라!
- 함수 내부에서 남몰래 전역 변수를 수정하거나 하는 등의 일은 하면 안된다.
명령과 조회를 분리하라!
- 함수는 뭔가를 수행하거나 뭔가에 답하거나 둘 중 하나만 해야한다.
오류코드 보다 예외를 사용하라!
- 오류코드를 리턴하는 방식은 이후 if문을 만들어낸다.
- try/catch블록은 원래 추하다. 따라서 try/catch 블록만 따로 함수로 뽑아내는 것이 좋다.
반복하지 마라!
- 중복은 소프트웨어에서 만악의 근원이다.
함수를 어떻게 짜죠?
- 소프트웨어를 짜는 행위는 글짓기와 비슷하다.
- 어설픈 초안을 만들고, 테스트 케이스를 짠 뒤, 함수를 다듬는다.
4. 주석
우리는 의도를 코드로 표현하지 못해, 그러니까 실패를 만해하기 위해 주석을 사용한다. 진실은 한 곳에만 존재한다. 바로 코드다.
주석은 나쁜 코드를 보완하지 못한다
- 자신이 저지른 난장판을 주석으로 설명하려 애쓰는 대신, 그 난장판을 깨끗이 치우는 데 시간을 써라
5. 형식 맞추기
코드 형식은 중요하다! 프로그래머라면 형식을 깔끔하게 맞춰 코드를 짜야한다.
적절한 행 길이를 유지하라
- 200줄 정도의 파일들로도 커다란 시스템을 구축할 수 있다. 일반적으로 큰 파일 보다 작은 파일이 이해하기 쉽다.
개념은 빈 행으로 분리하라
세로 밀집도
- 서로 밀접한 코드 행은 세로로 놓여야 한다.
수직 거리
- 변수 선언 : 변수는 사용하는 위치에 최대한 가까이 선언한다.
- 인스턴스 변수 : 인스턴스 변수는 클래스 맨 처음에 선언한다. 위치에 대한 이견이 있지만, 맨 처음이던 맨 뒤던, 모은다는 것이 중요하다.
- 종속 함수 : 한 함수가 다른 함수를 호출한다면, 두 함수는 세로로 가까이 배치한다.
- 개념적 유사성 : 같은 변수를 사용하거나, 하는 동작이 비슷한 함수는 가까이 배치한다.
세로 순서
- 함수 호출의 종속성은 아래 방향으로 유지한다. 호출되는 함수를 호출하는 함수보다 나중에 배치한다.
가로 공백과 밀집도
- 가로로는 공백을 사용해 밀접한 개념과 느슨한 개념을 표현한다. 할당문에 공백을 주어 왼쪽/오른쪽 요소를 확실히 나눌 수 있고, 함수이름과 괄호는 밀접하기에 공백을 넣지 않는다.
들여 쓰기
- 간단한 if문, 함수에서 들여쓰기를 무시하고 싶은 충동을 이겨내라.
팀 규칙
- 팀은 한 가지 규칙에 합의해야 한다. 그리고 모든 팀원이 그 규칙을 따라야 한다. 소프트웨어의 스타일은 일관적이고 매끄러워야 한다.
6. 객체와 자료구조
자료 추상화
- 변수 사이에 함수라는 계층을 넣는다고 구현이 저절로 감춰지지는 않는다. 구현을 감추려면 추상화가 필요하다!
- 의식적으로 getter setter 만들었다고 땡 치는 게 아니다.
객체와 자료구조
- 객체는 추상화 뒤로 자료를 숨기고 자료를 다루는 함수를 제공
- 자료구조는 자료를 그대로 공개하고, 함수를 제공하지 않음
객체지향 코드와 절차적인 코드
- 절차적인 코드는 함수를 추가하기 쉽지만, 새로운 자료구조를 추가하기 어렵다.
- 객체지향 코드는 새 클래스를 추가하기 쉽지만, 함수를 추가하기 어렵다.
자료 전달 객체(DTO)
- 자료 전달 객체(DTO)는 자료구조체의 전형적인 형태로, 공개 변수만 있고 함수가 없는 클래스다.
- Save나 find같은 탐색 함수를 넣기도 한다.
7. 오류 처리
난잡한 오류 처리 때문에 실제 코드가 하는 일을 파악 못함!
오류 코드보다 예외를 사용하라
- 오류코드를 리턴 하는 방식은 이후 if문을 만들어낸다.
- If(deletePage(page) == E_OK)
미확인 예외를 사용하라
- 피호출 함수에 오류를 추가하면 호출함수로 돌아가 함수 선언부에 throws 절을 추가해야 한다.
- RuntimeException 사용하라
호출자를 고려해 예외 클래스를 정의하라
- 오류를 정의할 때, 가장 중요한 관심사는 오류를 잡아내는 방법이다.
- 외부 API를 쓰는 코드를 감싸게 되면 의존성이 크게 줄어듦
Null을 반환하지 마라
- Null 체크는 빼먹기 쉽다. 애초에 null을 반환하지 않도록 짜라!
- 대신 특수사례 객체를 만들어 return하라
Null을 전달하지 마라
- 메서드로 null을 전달하는 방식은 매우 나쁘다!
- NullPointerException 터져나오게됨
8. 경계
개발 중 다양한 외부 라이브러리나 오픈 소스를 이용한다.
외부 코드 사용하기
- 외부에서 가져온 인터페이스를 여기저기 넘기지 마라.
- 이를 이용하는 클래스 밖으로 노출되지 않도록 주의한다.
학습 테스트
- 외부 코드는 익히기 어렵다.
- 바로 외부 코드를 호출하는 대신 간단한 테스트 케이스를 작성
- 가성비가 좋다
- 버전 올리기에도 좋다. TC가 있으므로
9. 단위 테스트
TDD시, 방대한 테스트 코드가 생성됨. 관리 문제를 유발
깨끗한 테스트 코드 유지하기
- 테스트 코드가 깨끗하지 않으면, 케이스 추가 어렵게되고, 실패율이 올라간다.
- 테스트 코드는 실제 코드 못지 않게 중요하다!
깨끗한 테스트 코드
- 가독성, 가독성, 가독성
- 테스트에서만 사용하는 특수 API를 만든다
- 실제 코드만큼 효율적일 필요는 없다
- 앞선 규칙들을 약간 위반하더라도 가독성을 최우선으로 하라!
F.I.R.S.T
- Fast : 테스트는 빨라야 한다.
- Independent : 각 테스트는 서로 의존하면 안 된다.
- Repeatable : 어떤 환경에서도 반복 가능해야 한다.
- Self-Validating : 테스트는 Bool값으로 결과를 내야 한다.
- Timely : 단위 테스트는 실제 코드 구현 직전에 작성한다.
10. 클래스
클래스 체계
- 자바 관례에서 가장 먼저 변수 목록이 나온다
- Static public -> Static private -> Private 인스턴스 순서
- 변수목록 다음 Public 함수
- Private 함수는 자기 호출한 Public 함수 직후
클래스는 작아야 한다!
- 작아야 한다. 작아야 한다.
- 클래스 이름은 클래스 책임을 기술
- 이름이 안 떠오른다? 책임이 너무 많은 것
단일 책임 원칙(SRP)
- 클래스나 모듈을 변경할 이유가 단 하나뿐이어야 한다.
- 돌아가는 프로그램만 생각하면 SRP가 잘 깨진다.
응집도
- 몇몇 함수가 몇몇 변수만 사용한다면 쪼개라
11. 시스템
도시를 세운다면?
- 혼자서 도시를 관리할 수 있는 가? 없다!
- 그럼에도 잘 돌아간다
- 수도 관리 팀, 전력 관리 팀 등 각 분야의 관리 팀이 있기에…
- 도시가 잘 돌아가는 이유는 적절한 추상화와 모듈화 때문이다.
시스템
- 시스템을 개발할 때 비슷한 수준의 관심사를 분리해 모듈화해야 깨끗한 시스템을 유지할 수 있다
생성과 사용을 분리하라
- 소프트웨어 시스템은
- 객체를 생성하고 의존성을 서로 연결하는 준비과정과
- 준비 과정 이후에 이어지는 런타임 로직을 분리해야 한다.
의존 주입(DI)
- 객체는 의존성을 인스턴스로 만드는 책임을 지지 않음
- 전담 매커니즘(main / 특수 컨테이너)에 책임을 넘김
- 클래스는 완전히 수동적
- Spring Framework
확장
- 처음부터 올바르게 시스템을 만들 수 있다는 믿음은 미신
- 관심사를 적절히 분리해 관리한다면, 소프트웨어 아키텍처는 점진적으로 발전할 수 있다!
관심사를 적절히 분리하기 위한 노력
- EJB1/EJB2
- AOP : 횡단 관심사를 분리하여 모듈성을 증가
- 횡단 관심사 : Logging, Security, Transaction과 같이 객체 경계를 넘나드는 관심사
- Spring, Jboss AOP, AspectJ
POJO
- Plain Old Java Object : 단순한 자바 객체
- POJO는 프레임워크에 의존하지 않는다. 즉, 코드 수준에서 아키텍처 관심사가 분리되어 있다.
- 애플리케이션 도메인 논리를 POJO로 구현한다.
- 무엇을 얻는가?
- 쉬운 테스트 주도 기법 적용
- 빠른 개발
- 코드의 단순성
12. 창발성
착실하게 따르기만 하면 우수한 설계가 나오는 간단한 규칙이 있다.
규칙1. 모든 테스트를 실행하라
- 테스트가 가능한 시스템을 만들려고 애쓰면 설계 품질이 높아진다.
규칙2. 리팩토링:중복을 없애라
- 우수한 설계에서 중복은 커다란 적이다.
규칙3. 리팩토링:표현하라
- 코드는 개발자의 의도를 분명히 표현해야 한다.
- 표현력을 높이는 최고의 방법은 노력이다. 자신의 작품을 좀 더 사랑하라.
규칙4. 리팩토링:클래스와 메서드 수를 최소로 줄여라
- 4가지 규칙 중 우선순위가 제일 낮다.
- 규칙2,3이 극단으로 가면 클래스와 메서드가 수없이 많아진다.
13. 동시성
동시성과 깔끔한 코드는 양립하기 매우 어렵다.
난관
- 동시성을 구현하는 것은 어렵다.
동시성 방어 원칙
- 동시성 관련 코드는 다른 코드와 분리하라.
- 자료를 캡슐화하라. 공유 자료를 최대한 줄여라.
- 스레드는 독립적으로 구현하라. 다른 스레드와 자료를 공유하지 않도록.
라이브러리를 이해하라
- 언어에서 제공하는 동시성 관련 클래스를 익히고 사용하라.
공유 객체 하나에는 메서드 하나만 사용하라
동기화하는 부분을 최대한 작게 만들어라
올바른 종료 코드는 구현하기 어렵다
- 깔끔하게 종료하는 코드는 올바로 구현하기 어렵다.
- 종료 코드를 개발 초기부터 고민하라.
스레드 코드 테스트하기
- 시스템 설정과 부하를 바꿔 자주 테스트하라.
시스템 실패를 ‘일회성’이라 치부하지 마라
순차 코드부터 제대로 돌게 만들어라
- 스레드 환경 밖에서 코드가 제대로 도는지 반드시 확인한다.
프로세스 수 보다 많은 스레드를 돌려보라
다른 플랫폼에서 돌려보라
14. 점진적인 개선
단순히 돌아가는 코드에 만족하는 프로그래머는 전문가 정신이 부족하다. 코드는 언제나 최대한 깔끔하게 정리하라.
15. JUnit 들여다보기
16. SerialDate 리팩토링
17. 냄새와 휴리스틱
이 목록은 완벽하지 않다. 다만 가치 체계를 피력할 뿐이다. 이러한 규칙을 따른다고 깨끗한 코드가 얻어지지 않는다. 휴리스틱 목록을 익힌다고 소프트웨어 장인이 되지는 못한다. 전문가 정신과 장인 정신은 가치에서 나온다. 그 가치에 기반한 규율과 절제가 필요하다.
소감
두꺼운 책이었고, 읽는 데 꽤 많은 시간이 소요되었다. 전체적으로 잘 읽히는 책이라고 느꼈다. 재밌게 읽었다. 전체 내용이 모두 유익했지만, 앞 부분이 더 좋았다. 특히, 클린 코드란 무엇인가에 대해 이야기하는 서두 부분이 아주 기억에 남는다. 조금 오래되어 옛날 기술 기준으로 적혔다거나, 이젠 이미 당연히 받아들이는 내용을 설명한 부분이 있다. 이런 부분은 알아서 가볍게 읽고 지나가면 좋을 것 같다.
당연히 이 책의 규칙들이 정답은 아니겠지만, 개발 꼬꼬마로서 지침은 충분히 될 수 있을 것 같다. 책에서 말한 것 처럼, 클린 코드를 알아 볼 수 있다고, 그 코드를 작성할 수 있는 건 아니므로… 열심히 코딩해보고, 뜯어보는 노력이 제일 필요할 것 같다.