이번 주말에는 로버트 마틴의 클린 코드를 읽어보았습니다. 워낙 유명한 책이어서 한 번 읽어보고 싶다는 생각은 했지만, 원래 독서를 잘 하는 편은 아니어서(…) 귀찮다는 이유로 미루고 있었습니다.
그러다가 최근에 다른 분이 이 책을 읽고 남겨주신 코멘트를 봤는데, 재미없는데 유익하다 라는 말이 어떤 의미인지 궁금해지더군요. 그래서 이번 기회에 한 번 읽어보았습니다. 책은 회사에 있는 사내도서관 제도를 활용해서 빌렸습니다.
책 소개
이 책은 로버트 마틴이 오브젝트 멘토(Object Mentor)라는 회사의 동료들과 저술한 책으로, 클린 코드를 만드는 애자일 기법들을 정제해 담았습니다. 책의 서문에서는 이 책을 Java 프로그래밍 언어를 사용해 프로그램을 작성할 때 자기도 만족스럽고 남도 만족스럽도록 깨끗한 코드를 작성하는 방법을 소개한다고 이야기합니다.
책은 크게 세 부분으로 나눠져 있습니다. 처음 몇 장은 클린 코드를 작성하는 원칙, 패턴, 실천을 설명합니다. 둘째 부분은 사례 연구 몇 가지를 소개하는데, 점점 더 복잡해집니다. 각 사례 연구는 코드를 깨끗하게 고치는, 즉 문제가 있는 코드를 좀 더 튼튼하고 효율적인 코드로 바꾸는 연습입니다. 셋째 부분은 결말입니다. 사례 연구를 만들면서 수집한 냄새와 휴리스틱(smells and heuristic)을 열거합니다. 그 결과로 코드를 읽고, 짜고 정리하는 과정에서 우리가 생각하는 방식을 묘사한 지식 기반을 얻을 수 있습니다.
이 책에서 다루는 내용은 다음과 같습니다.
- 좋은 코드와 나쁜 코드를 구별하는 방법
- 좋은 코드를 작성하는 방법과 나쁜 코드를 좋은 코드로 바꾸는 방법
- 좋은 이름, 좋은 함수, 좋은 객체, 좋은 클래스를 작성하는 방법
- 가독성이 높아지도록 코드 형식을 맞추는 방법
- 코드 논리를 흩뜨리지 않고서 오류 처리를 완벽하게 구현하는 방법
- 단위 테스트와 테스트 주도 개발을 적용하는 방법
인상 깊었던 부분들
사실 이번 책에서는 인상 깊었던 부분들이 초반부에 치우쳐져 있습니다. 중반부에는 사례 연구 위주 파트, 후반부에는 각 휴리스틱들을 열거해놓은 파트라서 그런 듯 하네요.
르블랑의 법칙
자신이 짠 쓰레기 코드를 쳐다보며 나중에 손보겠다고 생각한 경험이 있다. (…) 나중은 결코 오지 않는다.
- 4p
소프트웨어 개발에서 흔히 사용되는 르블랑의 법칙을 소개한 파트입니다. 사실 저는 이런 말이 있는지도 잘 몰랐었는데, 이런 말이 있나보더군요.
“모 게임” 유저라면 잠시 흠칫하실 수 있겠지만, 이 말은 데이브 르블랑(Dave LeBlanc)이라는 아저씨가 한 말이니 오해 없으시길 바랍니다. 원문은 Later equals never 라고 하네요.
저도 일단은 되게만 고쳐놓고, 나중에 리팩토링 해야지~ 라는 마음을 쉽게 가진 적이 많았기 때문에 이 부분을 읽으면서 좀 찔렸네요.
태도
자신이 의사라 가정하자. 어느 환자가 수술 전에 손을 씻지 말라고 요구한다. (…) 하지만 의사는 단호하게 거부한다. 왜? 질병과 감염의 위험은 환자보다 의사가 더 잘 아니까. 환자 말을 그대로 따르는 행동은 전문가답지 못하니까.
프로그래머도 마찬가지다. 나쁜 코드의 위험을 이해하지 못하는 관리자 말을 그대로 따르는 행동은 전문가답지 못하다.
- 6p
프로페셔널한 태도를 의사에 비유한 부분이 인상 깊었습니다. 프로젝트 매니저(PM)는 일정을 잡으며 우리의 도움을 필요로 하고, 마케터는 약속과 공약을 걸며 우리에게 정보를 구하고, 사용자는 요구사항을 내놓으며 우리에게 현실성을 자문합니다. 우리도 프로젝트의 계획에 깊게 관여하고 있기 때문에, 개발자 역시 프로젝트의 흥망에 큰 책임이 있다고 이야기합니다. 그리고 그것이 전문가다운 것 이라고 이야기하죠.
제가 예전에 책 『소프트웨어 장인(Software Craftsmanship)』에서 읽었던 부분이랑 일맥상통하는 부분이 있네요.
보이스카우트 규칙
캠프장은 처음 왔을 때보다 더 깨끗하게 해놓고 떠나라.
- 18p
보이스카우트 규칙이 소프트웨어 개발자에게도 유용하다고 소개하는 부분입니다. 체크아웃할 때보다 좀 더 깨끗한 코드를 체크인한다면 코드가 더 나빠지지 않을거고, 한꺼번에 많은 시간과 노력을 투자해 코드를 정리할 필요가 없다고 소개합니다.
르블랑의 법칙과는 좀 비슷한데, 점점 나아지는 코드를 만드는 것이 낫고 그것이 더 전문가스럽다는 의미로 소개한 듯 합니다.
하나의 함수는 하나의 기능만을
함수는 한 가지를 해야 한다. 그 한 가지를 잘 해야 한다. 그 한 가지만을 해야 한다.
- 44p
이 책에서 가장 강조하는 문구입니다. 여기에서 의미하는 하나 는, 추상화 수준이 같음 을 의미합니다. 하나의 함수에서 다른 의미있는 이름으로 다른 작업을 하는 함수를 추출해낼 수 있다면, 그 함수는 여러 작업을 하는 함수라는 의미죠.
이 부분을 읽으면서 추상화에 대해 다시 생각해보게 되었습니다. 고차원적인 로직과 저차원적인 로직을 하나의 함수 내에서 분리하지 않고 섞어 썼던 경험이 떠올라서 좀 부끄러웠습니다.
길고 서술적인 이름이 더 낫다
이름이 길어도 괜찮다. 겁 먹을 필요 없다. 길고 서술적인 이름이 짧고 어려운 이름보다 좋다.
- 49p
사실 꽤 오래 전에는 긴 네이밍이 가독성이 좋지 않다고 생각해서 줄여썼었는데, 최근에는 서술적인 네이밍을 지향하는 것으로 옮겨온 입장에서 동의하는 편입니다.
주석은 신중하게
우리는 코드를 의도로 표현하지 못해, 그러니까 실패를 만회하기 위해 주석을 사용한다. (…) 주석은 언제나 실패를 의미한다.
- 68p
주석에 대한 경계심을 드러내는 부분입니다. 저자는 그 이유를 코드가 변화함에 따라 주석이 거짓말을 하기 때문 이라고 이야기합니다. 사실 주석을 즐겨쓰는 편은 아니지만, 코드 그 자체를 이용해서 의도를 표현하는 것이 더 낫다는 의견에는 동의하는 편입니다.
객체와 자료구조
어떤 시스템을 구현할 때, 새로운 자료 타입을 추가하는 유연성이 필요하면 객체가 더 적합하다. 다른 경우로 새로운 동작을 추가하는 유연성이 필요하면 자료 구조와 절차적인 코드가 더 적합하다.
- 128p
예전에는 클래스나 객체를 만들 때 그냥 직관(?)에 따라서 만들었었는데… 데이터의 변화 가능성에 중점을 두고 설계하는 입장에서는 이런 식으로 만들구나 라는 것을 느꼈습니다.
경계
경계에 위치하는 코드는 깔끔하게 분리한다.
- 152p
라이브러리 등으로 인해 외부 코드를 사용해야 하는 경우에는 래퍼(Wrapper) 클래스로 라이브러리를 감싸서 비즈니스 로직과 라이브러리 로직이 최대한 직접 접촉하지 않게 하라는 조언입니다.
단위 테스트
테스트는 유연성, 유지보수성, 재사용성을 제공한다. 테스트 케이스가 있으면 변경이 쉬워지기 때문이다.
- 157p
어딜 가나 항상 중요시하게 얘기하는 테스트입니다. 책에서는 TDD를 이야기하지만 아직 그 정도로 테스트가 몸에 익지는 않았네요… 그래도 유닛 테스트와 e2e 테스트가 있다면 변경이 쉬워진다는 의견에는 동의하는 편입니다. 그래서 최근에는 시간 날 때 마다 테스트 코드를 작성하려 노력하는 편입니다.
클래스
도구 상자를 어떻게 관리하고 싶은가? 작은 서랍을 많이 두고 기능과 이름이 명확한 컴포넌트를 나눠 담고 싶은가? 아니면 큰 서랍 몇 개를 두고 모두를 던져 넣고 싶은가?
- 177p
큰 클래스 몇 개 보다는 작은 클래스 여럿으로 이뤄진 시스템이 더 바람직하다는 이야기입니다. 작은 클래스는 단일 책임 원칙(Single Responsibility Principle)을 준수하고, 따라서 변경이 필요하다면 그 이유가 하나이며, 다른 작은 클래스와 협력해서 시스템에 필요한 동작을 수행해야 한다는 의견에 동의합니다.
후기
솔직하게 느낀 점을 얘기하자면, 재미로 읽기에는 쉽지 않은 책이었습니다(…) 초반 부에는 몇 가지 원칙들을 간단한 예제와 함께 소개해서 재미있게 읽을 수 있었지만, 글의 중반부에서는 네다섯 페이지에 걸쳐 소개되는 소스코드를 일일이 따라가면서 읽기가 쉽지 않았습니다.
하지만 후반부에 나오는 냄새와 휴리스틱 장을 읽는 것만으로도, 이 책은 확실하게 유익했습니다. 그리고 실용적이었습니다. 내가 여태껏 코드를 짜면서 의도치않게 얼마나 많이 디테일한 부분을 놓치고 있었는지를 깨달을 수 있었습니다.
그런 점에서 책의 서문에서 이야기한 것과 비슷하게 한 번 읽고 넘기는 책보다는 백과사전처럼 필요할 때 마다 찾아서 보는 책 이라는 소개가 딱 맞다고 느껴졌습니다. 최근에는 클린 코드의 원칙을 각 언어(TypeScript, JavaScript) 별 특성에 잘 적용시켜 놓은 문서들도 많더라구요. 저는 Java보다는 TypeScript와 JavaScript가 더 익숙하기 때문에, 이런 문서들을 통해 다른 언어에서는 이런 패턴으로 활용하면 된다 라는 것을 배울 수 있어서 요런 것들을 찾아 보는 것도 꽤 유익했습니다.
대부분의 경우 클린 코드의 원칙은 지향하는 것이 좋지만, 『잘 가, 클린 코드』라는 글처럼 최근에는 클린 코드에 너무 얽매일 필요는 없다는 시각도 있는 듯 하군요. 결론적으로는 클린 코드를 지향하되, 합리적인 이유가 있다면 필요에 따라 취사선택 하는 것이 가장 현실적인 결론인 듯 합니다.