목차
1. 코드가 존재하리라
2. 나쁜 코드
3. 나쁜 코드로 치르는 대가
• 원대한 재설계의 꿈
• 태도
• 원초적 난제
• 깨끗한 코드라는 예술?
• 깨끗한 코드란?
4. 우리들 생각
5. 우리는 저자다
6. 보이스카우트 규칙
7. 프리퀄과 원칙
8. 결론
1. 코드가 존재하리라
명세를 기준으로 프로그램을 자동으로 생성하는 시대가 다가온다는 말은 틀렸다.
- 어느 수준에 이르면 코드의 도움 없이 요구사항을 상세하게 표현하고, 추상화를 하는 것이 불가능하다.
- 언어의 추상화 레벨(고급/저급 언어 관점)이 올라가고, 특정 응용 분야에 적합한 프로그래밍 언어(domain-specific language) 수가 점차 많아지더라도 코드는 사라지지 않는다.
기계가 실행할 정도로 상세하게 요구사항을 명시하는 작업, 바로 이것이 프로그래밍이며, 이렇게 명시한 결과가 코드다.
요구사항에 더욱 가까운 언어를 만들고, 요구사항에서 정형 구조를 뽑아내는 도구를 만들 수도 있다.
하지만 어느 순간에는 정밀한 표현이 필요하다. 그 일을 완벽하게 수행하는 기계를 만들어내는 것은 불가능하다.
그러므로 코드도 항상 존재하리라.
2. 나쁜 코드
Killer app 하나로 대박났던 회사가 제품 출시 기간이 점차 늘어지고, 이전 버전의 버그가 다음 버전에도 그대로 남아 있더니 프로그램이 죽는 횟수도 늘어났다.
결국 머지 않아 망했는데, 그 원인이 바로 나쁜 코드 탓이었다.
일정에 맞추기 위해 자신이 짠 쓰레기 코드를 나중에 손보겠다고 다짐하지만, 나중은 결코 오지 않는다. (Later equals never - LeBlanc's Law)
3. 나쁜 코드로 치르는 대가
나쁜 코드는 개발 속도를 크게 떨어뜨린다.
초기에는 번개처럼 진행되던 프로젝트가 1~2년 만에 굼뱅이처럼 기어가는 팀도 많다.
나쁜 코드가 쌓일 수록 그 팀의 생산성은 떨어지고 이윽고 0에 수렴한다.
- 관리팀은 인력을 추가로 투입해서 문제를 해결하려 한다. (The Mythical Man-Month과도 연관 있는 내용같다.)
- 하지만 새 팀원은 구조를 이해하지 못하고, 생산성을 높여야 한다는 압박감에 시달린다.
- 결국 나쁜 코드를 더 많이 양산하고 생산성은 0이 된다.
1️⃣ 원대한 재설계의 꿈
💡 깨끗한 코드를 만드는 노력이 비용을 절감하는 방법일 뿐만 아니라 전문가로서 살아남는 길이다.
- 팀은 재디자인을 요구하고, 관리층은 달갑지는 않지만 생산성이 바닥을 기는 것을 알고 있으므로 허가하게 된다.
- 새 타이거 팀이 구성되고 기존 프로덕트의 기능 + 변경 사항을 모두 제공하는 새 시스템을 구축해야 한다.
- 다른 팀원들은 기존 프로덕트를 유지보수하며, 두 팀은 오래동안 경쟁한다.
- 타이거 팀이 기존 프로젝트를 거의 따라잡을 즈음(몇 년이 걸릴지 모른다), 초기 멤버들은 대부분 교체되었다.
- 그리고 그들은 다시 재디자인을 요구한다.
2️⃣ 태도
💡 좋은 코드가 순식간에 나쁜 코드로 전락하는 이유는 전적으로 프로그래머에게 있다.
- 대부분의 매니저들 또한 좋은 코드를 원한다. 그와 동시에 스케쥴을 지키고 싶어한다.
- 그와 마찬가지로 좋은 코드를 지키는 것은 우리의 몫이다.
- 나쁜 코드의 위험을 이해하지 못하는 관리자 말을 그대로 따르는 행동은 전문가답지 못하다.
3️⃣ 원초적 난제
💡 기한을 맞추는 유일한 방법은 언제나 코드를 최대한 깨끗하게 유지하는 습관이다.
- 개발자들은 기한을 맞추기 위하 나쁜 코드를 양산할 수밖에 없다고 느끼지만, 이는 틀렸다.
- 오히려 엉망진창인 상태로 인해 속도가 곧바로 늦어지고, 기한을 놓치게 된다.
4️⃣ 깨끗한 코드라는 예술?
깨끗한 코드를 작성하는 프로그래머는 빈 캔퍼스를 우아한 작품으로 바꿔가는 화가와 같다.
이를 위해선 '청결'이라는 힘겹게 습득한 감각을 활용해 자잘한 기법들을 적용하는 절제와 규율이 필요하다.
📌 Bjarne Stroustrup, inventor of C++ and author of The C++ Programming Language
I like my code to be elegant and efficient. The logic should be straightforward to make it hard for bugs to hide, the dependencies minimal to ease maintenance, error handling complete according to an articulated strategy, and performance close to optimal so as not to tempt people to make the code messy with unprincipled optimizations. Clean code does one thing well.
- 깨끗한 코드는 보는 사람에게 즐거움을 선사해야 한다.
- 성능 뿐만 아니라, cpu 자원을 낭비하는 코드도 우아하지 못하다. 즉, 효율적인 코드여야 한다.
- 나쁜 코드는 나쁜 코드를 '유혹'한다. (실용주의 프로그래머의 '깨진 창문' 이야기)
- 오류 처리, 메모리 누수, 경쟁 상태, 일관성 없는 명명법 등 디테일을 신경 써라.
- 클린 코드는 단 한 가지 일에 '집중'한다.
📌 Grady Booch, author of Object Oriented Analysis and Design with Applications
Clean code is simple and direct. Clean code reads like well-written prose. Clean code never obscures the designer’s intent but rather is full of crisp abstractions and straightforward lines of control.
- 가독성: 클린 코드는 잘 쓴 문장처럼 읽혀야 한다.
- 명백한 추상화: 코드는 추측이 아니라 사실에 기반해야 한다. 반드시 필요한 내용만 담아라.
📌 “Big” Dave Thomas, founder of OTI, godfather of the Eclipse strategy
Clean code can be read, and enhanced by a developer other than its original author. It has unit and acceptance tests. It has meaningful names. It provides one way rather than many ways for doing one thing. It has minimal dependencies, which are explicitly defined, and provides a clear and minimal API. Code should be literate since depending on the language, not all necessary information can be expressed clearly in code alone.
- 다른 이가 수정하기 쉬워야 한다.
- 테스트 케이스가 있어야 한다.
- 코드는 간결할 수록 좋다.
- 코드는 '문학적'이어야 한다. 인간이 읽기 좋은 코드를 작성해라.
📌 Michael Feathers, author of Working Effectively with Legacy Code
I could list all of the qualities that I notice in clean code, but there is one overarching quality that leads to all of them. Clean code always looks like it was written by someone who cares. There is nothing obvious that you can do to make it better. All of those things were thought about by the code’s author, and if you try to imagine improvements, you’re led back to where you are, sitting in appreciation of the code someone left for you—code left by someone who cares deeply about the craft.
- 클린 코드는 주의 깊게 작성한 코드다.
- 누군가 시간을 들여 깔끔하고 단정하게 정리한 코드다.
- 세세한 사항까지 꼼꼼하게 신경쓴 코드다.
- 주의를 기울인 코드다.
📌 Ron Jeffries, author of Extreme Programming Installed and Extreme Programming Adventures in C#
In recent years I begin, and nearly end, with Beck’s rules of simple code. In priority order, simple code:
- Runs all the tests;
- Contains no duplication;
- Expresses all the design ideas that are in the system;
- Minimizes the number of entities such as classes, methods, functions, and the like.
Of these, I focus mostly on duplication. When the same thing is done over and over, it’s a sign that there is an idea in our mind that is not well represented in the code. I try to figure out what it is. Then I try to express that idea more clearly. Expressiveness to me includes meaningful names, and I am likely to change the names of things several times before I settle in. With modern coding tools such as Eclipse, renaming is quite inexpensive, so it doesn’t trouble me to change.
Expressiveness goes beyond names, however. I also look at whether an object or method is doing more than one thing. If it’s an object, it probably needs to be broken into two or more objects. If it’s a method, I will always use the Extract Method refactoring on it, resulting in one method that says more clearly what it does, and some submethods saying how it is done.
Duplication and expressiveness take me a very long way into what I consider clean code, and improving dirty code with just these two things in mind can make a huge difference. There is, however, one other thing that I’m aware of doing, which is a bit harder to explain.
After years of doing this work, it seems to me that all programs are made up of very similar elements. One example is “find things in a collection.” Whether we have a database of employee records, or a hash map of keys and values, or an array of items of some kind, we often find ourselves wanting a particular item from that collection. When I find that happening, I will often wrap the particular implementation in a more abstract method or class. That gives me a couple of interesting advantages.
I can implement the functionality now with something simple, say a hash map, but since now all the references to that search are covered by my little abstraction, I can change the implementation any time I want. I can go forward quickly while preserving my ability to change later.
In addition, the collection abstraction often calls my attention to what’s “really” going on, and keeps me from running down the path of implementing arbitrary collection behavior when all I really need is a few fairly simple ways of finding what I want.
Reduced duplication, high expressiveness, and early building of simple abstractions. That’s what makes clean code for me.
- 중복을 피하라
- 클래스와 메서드는 한 기능만 수행하라.
- 메서드의 이름은 코드가 하는 일을 명시해야 한다.
- 일찍 그리고 작게 추상화해서 프로젝트 진행 속도를 높여라.
📌 Ward Cunningham, inventor of Wiki, inventor of Fit, coinventor of eXtreme Programming. Motive force behind Design Patterns. Smalltalk and OO thought leader. The godfather of all those who care about code.
You know you are working on clean code when each routine you read turns out to be pretty much what you expected. You can call it beautiful code when the code also makes it look like the language was made for the problem.
- 읽고 고개를 끄덕이고는 다음 주제로 넘어갈 수 있는 코드를 작성해라.
- 짐작하는 기능을 그대로 수행하는 모듈을 만들어라.
- 깨끗한 코드는 읽으면서 놀랄 일이 없어야 한다.
- 당신이 사용하는 언어를 탓하지 말라. 코드를 아름답게 만드는 것은 프로그래머다.
4. 우리들 생각
이 책에 나오는 많은 내용들은 논쟁의 여지가 있다. 모든 기법에 동의하지 않을 수도, 격렬히 반대할 수도 있다.
상관없다. 결정은 당신의 몫이다.
이 내용을 연구한 학파의 의견 뿐만 아니라, 다른 경험 많은 집단과 전문가들에게서도 배워라.
5. 우리는 저자다
JavaDoc의 @author 필드는 저자를 소개한다. 우리는 저자다.
저자에게는 독자가 있고, 저자는 독자와 잘 소통할 책임도 존재한다.
다음에 코드를 짤 때는 자신이 저자라는 사실을, 여러분들의 노력을 보고 판단을 내릴 독자가 있다는 사실을 기억하라.
코드를 읽는 시간보다 작성하는 데 더 많은 시간이 필요할지도 모르지만, 실상은 그 반대다.
Bob이 모듈을 열었다.
수정이 필요한 함수로 스크롤한다.
잠시 멈추고 생각한다.
이런, 그가 모듈의 최상단으로 스크롤해 변수의 초기화를 확인한다.
그리고는 다시 돌아가 입력하기 시작한다.
이런, 쓰고 있던 내용을 지운다!
다시 입력한다.
다시 지운다!
다른 무언가를 반쯤 적다가 또 다시 지운다!
지금 수정하고 있는 함수를 부르는 다른 함수로 스크롤해 수정중인 함수가 어떻게 호출되는지 확인한다.
다시 수정중인 함수로 돌아가서는, 방금 전에 지운 내용을 다시 적는다.
잠시 멈춘다.
적던 코드를 또 다시 지운다!
다른 창을 띄워서 subclass를 확인한다.
이 함수 override된 함수인가?
...
실제로 읽기와 쓰기에 들이는 시간은 대략 10:1 정도다. 새 코드를 작성하기 위해서는 옛 코드를 읽어야 하기 때문이다.
💡 급하다면, 서둘러 끝내려면, 쉽게 짜려면, 읽기 쉽게 만들면 된다.
6. 보이스카우트 규칙
💡 캠프장은 처음 왔을 때보다 더 깨끗하게 해놓고 떠나라.
시간이 지나도 언제나 깨끗하게 유지해야 한다. 코드의 퇴보를 막아라.
한꺼번에 많은 시간과 노력을 투자해 코드를 정리할 필요가 없다.
변수 이름을 하나 개선하고, 조금 긴 함수 하나를 분할하고, 약간의 중복을 제거하고, 복잡한 if문 하나를 정리하면 된다.
지속적인 개선이야말로 전문가 정신의 본질이다.
7. 프리퀄과 원칙
이 책은 Agile Software Development: Principles, Patterns, and Practices (PPP)의 프리퀄이다.
SRP(Single Responsibility), OCP(Open Closed Principle), DIP(Dependency Inversion Principle) 등 PPP에서 설명하는 다양한 설계 원칙을 산발적으로 거론하므로 읽어보는 것이 좋다.
8. 결론
예술에 관한 책을 읽는다고 예술가가 된다는 보장은 없다.
단지 뛰어난 프로그래머가 생각하는 방식과 그들이 사용하는 기술과 기교와 도구를 소개할 뿐이다.
"연습하고 또 연습해라!"