Clean Code에 이어 The Pragmatic Programmer를 읽었다. 이 책은 개발자로써 어떠한 마음가짐을 가져야 하는지, 어떠한 방법을 사용해야 하는지에 대해 매우 개략적으로만 다룬다. 주변에서 이제 막 프로젝트를 하나 끝낸 개발자 지망생들에게 한 번씩 읽어보라고 추천하고 싶은 책이다. 현대 개발론에서 사용하는 agile, prototype, CICD, TDD, DDD 등에 대한 내용을 한 단락으로 정리하기 때문에 개발하면서 불편했던 점을 이렇게 해결할 수 있구나, 하는 큰 방향성을 제시해 주기 때문이다.
Clean Code 포스팅과 마찬가지로 감명깊게 읽은 부분, 내게 필요하다고 생각하는 부분만 간단하게 정리했다. 그 중에서도 중요하다고 느낀 문장은 *를 쳐서 표기했다.
서문
개발자는, 어떤 특정 기술에 메이면 안 되며, 개별 상황마다 그 상황에서 가장 좋은 해결방안을 고를 수 있도록 충분한 배경지식과 경험을 가져야 한다. 배경지식은 컴퓨터 과학의 기본 원리를 이해하는 것에서, 경험은 실제 프로젝트를 수행해 보는 것에서 나온다.
어떤 일을 하면서 자신이 무엇을 하고있는지 생각하라. 모든 개발 과정에서, 매일매일, 모든 선택과 결정에 있어 지속적이고 비판적으로 평가하라.
이 두 문장이 시사하는 바는 결국 기본을 바탕으로 경험을 쌓고, 이를 바탕으로 증명하라는 말이다.
만류귀종이라는 말이 있다. 결국 모든 경지는 하나가 된다는 뜻이다. 이것과 비슷하게, 개발과 관련된 모든 정보는 컴퓨터 과학의 기본 원리에서 온다. 물론 몰라도 잘 할 수도 있다. 그러나 알고 코드를 쓰는 것과, 모르지만 성능이 잘 나와서 사용하는 것은 매우 큰 차이가 있다. 왜 이렇게 코드를 작성해야 하는지, 왜 더 좋은 성능이 나오는지를 이해해야만 다음 번 유사한 상황이 왔을 때 선택할 수 있는 모든 경우의 수 중 최선을 택할 수 있을 것이다. 항상 기본을 놓치지 말자.
1장. 실용주의 철학
이 장에서는 실용주의 개발자로써 가져야 할 덕목들에 대해 다룬다.
자신의 무지나 실수를 인정하고, 자신의 행동에 대해 책임져라.
문제가 생기면 변명하지 말고 대안을 제시하라.
사회 생활의 기본이다. 순간을 모면하기 위해 변명하는 것은 분명 쉬운 길이다. 그러나 실용적이고 현실적인 관점에서 보았을 때 현실을 직시하고 해결하는 것이 낫다. 사람인 만큼 실수할 수도 있고 무지로 인해 일을 망칠 수도 있다. 실수했다면 앞으로 더 주의를 기울여 같은 실수를 하지 않게 하면 되고, 무지로 인한 것이었다면 더 공부하면 된다.
* 깨진 창문을 내버려두지 마라.
문제를 발견했다면 그때 해결해야 한다. 이 문제를 방치한다면 미래에 더 큰 cost를 감당해야 한다. 이걸 알고 cost가 적을 때 해결하는 것이 더 효율적이다.
큰 무리 없이 요구할 수 있을 만한 것을 찾아내고 그것을 잘 개발해라.
개인적으로 무언을 하고 있는가에 정신을 쏟지 말고 주변에서 무슨 일이 벌어지는지 지속적으로 살펴보라.
일개 팀원이어도 기사가 되었다는 마인드를 가지고 프로젝트에 관심을 가지라는 말이다.(== 주인의식을 가지라는 말)
지식 포트폴리오를 구성해라. 주기적으로, 여러가지에 투자하고 재조정하라.
매년 새로운 언어를 최소 하나를 배우고, 기술 서적을 분기마나 하나씩 읽어라.
IT 업계의 기술 변화 속도는 너무 빠르다. 투자와 마찬가지로 아무것도 하고 있지 않는다면 기술 인플레이션으로 인해 지식의 상대적 가치가 떨어질 것이다. 주기적으로 배우고, 여러 가지를 배워야 한다. 여러 가지를 배우다보면 문제 해결을 위한 최적화된 솔루션을 찾을 수 있을 것이다.
청중 이해 전략 WISDOM
What - 무엇을 배우길 원하는가?
Interest - 무엇을 관심있어 하는가?
Sophisticated - 얼마나 소양이 있는가?
Detail - 얼마나 구체적인 내용을 원하는가?
Owe - 누가 정보를 소유하길 원하는가?
Motive - 경청하도록 동기를 주려면 어떻게 해야 할까?
개발자라고 개발만 하는 것은 아니다. 자신이 작성한 코드도 발표해야 하고 남이 작성한 코드도 리뷰해야 한다. 창업을 한다면 PPT를 만들어야 할 수도 있다. 어떻게 내 의견을 상대에게 잘 전달할 수 있을지 끊임없이 고민해 봐야 한다.
말하기 적절한 때를 골라라. 멋져 보이게 하라.
말을 하기 전에 이 말이 적절한 때인지, 내용은 적절한지 글을 쓰는 것처럼 한 번 더 머릿속으로 빠르게 검토해 봐야 한다. 그리고 무언가를 전달할 때는 visual도 중요하다. 보기 좋은 떡이 먹기도 좋다.
2장. 실용주의 접근법
이 장에서는 어떻게 문제에 접근하는지를 다룬다. 사실 읽다보면 Clean Code가 계속 생각나는 내용이다.
* DRY - Don't Repeat Yourself!
소스 코드에서 중복은 죄악이다. 그 부분을 바꿔야 한다면 모든 사본을 바꾸어 주어야 한다. 어떻게든 중복을 줄이려 노력해야 한다. 코드든, 문서든, 주석이든, 테스트든.
component를 나누었을 때 '특정 기능에 대한 요구사항을 극적으로 변경했을 경우, 몇 개의 module이 영향을 받는가?'를 질문해 보라.
책에서 이상적인 답은 1개라고 제시한다. 이처럼 최대한 적은 module이 영향을 받을 수 있도록 설계해야 한다.
* 최종 결정이란 없다.
항상 변할 것을 염두에 두고 아키텍처를 짜고 프로그래밍해야 한다. 요구사항은 언제든지 변한다. 요구사항에 투덜거리기보단 받아들이고 빠르게 반영할 수 있는 방법을 생각해야 한다.
목표를 찾기 위해 예광탄을 사용하라. 예광탄을 사용함으로써 요구사항으로부터 최종 시스템의 일부 측면까지 빨리 눈에 보이게 반복적으로 도달해 줄 무언가를 찾을 수 있다.
아직 미구현된 내용을 interface로 작성하는 것처럼 만드는 것이다. 이렇게 작성하면 실제 내용이 들어왔을 때 쉽게 교체할 수 있으며 미구현된 부분에 dependency를 가짐에도 작동하게 만들 수 있다.
추정을 통해 놀람을 피하라.
추정 결과를 전달할 때, 정확도를 고려해 답변의 단위를 선택해라. 낮은 단위는 정확도가 높게 느껴진다.
추정을 이미 했다고 하더라도 현장에서 실제 데이터를 입력받아 돌아가는 것만이 정말로 의미있는 수치이다.
프로젝트를 시작하기 전 많은 것들을 추정해야 한다. 여러 경험으로부터 추정의 정확성을 높일 수 있다.
추정에 대해서도 증명해야 한다. 어떤 과정으로 이런 결과가 나왔는지, 다른 예외 상황은 없는지. 책은 다음과 같은 예외를 제시한다.
- 700만개의 숫자를 radix sort를 64MB에서 돌리면 swap partitioning으로 인해 실제 수행시간은 O($n^{2}$)보다 훨씬 길어졌다.
3장. 기본적인 도구
이 장에서는 문제에 접근하기 위한 도구 사용법의 중요성을 설명한다.
지식을 일반 텍스트로 저장하라.
내가 쓴 코드를 나만 보는 것이 아니다. 내가 봐도 이해하기 쉽고, 남이 봐도 이해하기 쉽게 명확한 naming으로 저장하자.
* shell을 익혀라.
GUI로 사람이 직접 하는 것보다 훨씬 빠르다. 처음에는 난해하지만 적응되면 최고의 효율을 뽑을 수 있을 것이다
사실상 내가 약한 부분이다. 필요할 때 shell로 문제를 해결해 보는 습관을 들여보자.
선호하는 에디터의 기능을 익혀라.
이미 있는 기능을 사용하지 않을 이유가 없다. 익혀서 1초의 시간을 절약해야 한다. 사소한 디테일 하나하나가 큰 스노우볼을 만든다.
소스코드 관리 시스템을 이용하라.
git은 신이다. 소스코드 버전 관리 시스템으로 인해 삭제를 두려워하지 않을 수 있고, 협업을 간편하게 할 수 있다. jenkins를 이용한다면 빌드와 배포까지도 자동화할 수 있다.
디버깅은 단지 문제 해결이라는 사실을 인정하라.
비난 대신 문제를 해결하라.
누군가가 버그를 만들었다면 그 사람을 비난하기보다 문제 해결에 집중해야 한다. 그게 더 중요한 가치이다. 남을 비난해 봤자 남는 것은 없다.
* 디버깅 시 여유를 가져라.
Rubber Duck을 사용해 보라.
여유를 가지고 큰 시각에서 보아야 문제가 보인다. 알고 있지만 실현하기 어려운 것. 너무 편협해지지 말자.
이를 위해 책에서는 Rubber Duck을 제시한다. 누군가에게 문제를 설명해야 한다면 큰 그림으로 문제를 볼 수 있게 되고, 당연히 생각했던 것들의 제한조건을 명시적으로 이야기해야 한다. 이를 통해 문제를 해결할 수 있을 것이다.
놀라운 버그를 마주치면 왜 지금까지 발견되지 않았을까 생각하라.
복기는 중요하다. 왜 지금까지 발견되지 않았을까? 동시성 문제인가? boundary 문제인가? 뭐든 간에 다른 테스트를 수정할 필요가 있는지 다시 한 번 검토하고 미래를 대비해야 한다.
4장. 실용주의 편집증
이 장에서는 코드를 작성할 때 의심해야 하는 것들을 제시한다.
* 완벽한 소프트웨어는 없기 때문에 방어적으로 코딩해야 한다.
PS할 때 실력자들이 [true == 조건] 이런 식으로 작성하는 이유는 =가 하나일 때 컴파일러가 잡아줄 수 있기 때문이다. 항상 실수할 수 있기 때문에 이를 줄이기 위한 방법을 강구해야 한다. 잘못된 데이터를 찾기 위해 assertion을 사용하고, 일관성을 확인하고 DB에 contraint를 걸어야 한다.
"그건 절대 일어나지 않을 거야"라는 생각이 든다면 그걸 확인하는 코드를 작성하라.
이런 단정에서 문제가 발생한다. 책에서는 다음과 같은 예시를 제시한다. 참고로 모든 경우가 일어날 수 있는 예시이다.
- 한 달이 28일보다 적은 것
- c++에서 a = 2; b = 3; if(a+b != 5) exit(1)
- 내각의 합이 180도가 아닌 삼각형
- 60초가 아닌 1분
- (a+1) <= a
5장. 구부러지거나 부러지거나
코드를 module로 구성하고 이들 간의 상호작용을 제한하라.
dependency가 증가하면 변화가 예상치 못한 결과를 낸다. 따라서 dependency를 최소로 두어 변화의 영향을 인지할 수 있는 범위 내로 두어야 한다.
* 가능한 한 시스템을 설정 가능하게 만들어야 한다. 일반화할 기회를 놓치지 말자.
가령 요구사항이 '회색으로 만들어주세요'라고 해도 색을 설정할 수 있게 만들어야 한다. 언제 변할지 모르니까.
UML을 사용하면 concurrent를 최적화할 수 있다.
concurrent 최적화를 통해 성능을 올릴 수 있다. concurrent하게 작동될 수 있는 것이 무엇인지 면밀한 분석을 해야 한다. 단, static과 global 변수들을 locking해야 할 것이다.
blackboard를 사용하라.
- blackboard를 사용하는 모든 object는 다른 object를 알 필요가 없다. 오직 blackboard만 보면 된다.
blackboard를 이용해 publisher와 subscriber가 asychronize하게 정보를 주고받을 수 있게 된다. event-driven으로 문제를 해결할 수 있는 방법을 생각해 보자.
6장. 코딩하는 동안 해야 할 일들
이 장에서는 프로그래밍을 하더라도 잊지 말아야 하는 것들을 설명한다.
의도적으로 프로그래밍하라.
"왜 됐지?"는 없다. 이유를 찾고 증명해야 한다. 가정하지 말라. 증명하라.
사실 이미 하고 있고, 매우 중요한 덕목 중 하나라 생각한다. 모든 선택에는 근거가 있어야 한다. 모든 결과에는 이유가 있다. 이유가 없다면 아직 찾지 못한 것이다. 찾고 증명해야 한다.
* 리팩토링하라.
* 코드가 더 이상 잘 맞지 않아 장애물에 부딪혔을 때, 사실은 하나로 합쳐져 있어야 할 두 개를 발견했을 때, 어떤 것이든 잘못되었다고 생각될 때, 그 때 바로 변경해야 한다.
문제를 찾으면 그 때 바로 해결해야 한다. 미루다가 깨진 창문이 되어버린다. 깨진 창문이 되면 고치기 위해 훨씬 많은 cost를 투자해야 한다.
코드가 정확하게 동작하는지 검증하는 테스트를 작성하라. boundary test, 예외값 등 최대한 많은 경우의 수를 던져 보아야 한다.
항상 예외는 생각하지 못했던 것에서 오기 때문에 이런 것을 미연에 방지해야 한다.
* 여러분이 테스트하지 않으면 사용자가 테스트하게 된다.
엄격해져야 한다. 부족한 나를 직면하는 것도 부끄럽지만 미완성인 것을 남에게 보여주는 것이 더 부끄럽다.
남이 만든 코드를 사용한다면 모두 이해하라. 이 코드는 당신의 코드와 줄 단위로 섞인다.
외부 library를 사용한다면 모든 것을 이해하고 사용해야 한다. 그렇지 않는다면 그 부분은 내 손에서 벗어나기 때문이다.
7장. 프로젝트 전에
이 장에서는 프로젝트를 시작하기 전 인지하고 있어야 할 것들을 다룬다.
* 요구사항은 수집하는 것이 아니라 채굴하는 것이다.
요구사항은 최대한 일반적 진술로 만들어야 한다.
사용자들이 어떤 작업을 어떻게 해결하길 원하는지 알아내는 것이 아니라, 왜 그걸 하는지 이유를 찾아야 한다.
사용자들도 자신이 진짜 원하는 것이 무엇인지 모른다. 그걸 찾는 것이 우리의 역할이다. 사용자가 구체적인 예시를 제시하더라도 그 방법을 지원하는 일반적 방법을 찾아야 한다.
프로젝트 용어사전을 사용하라. 그것은 프로젝트에서 사용되는 모든 용어와 어휘를 모아 둔 단일한 장소여야 한다. 모든 관계자가 일관성을 위해 동일한 용어를 사용해야 한다.
같은 단어를 다르게 사용하거나 다른 단어를 같게 사용하면 결국 어디선가 문제가 생긴다. 사실 자명한 말이기도 하다...
문제를 마주쳤다면 모든 가능한 솔루션을 생각해 보자. 아무리 바보같더라도 버리지 말고. 이후에 그 과정들을 증명하며 불가능한 것을 버리고, 최적화된 답을 찾아내라.
- 더 쉬운 방법이 존재한는가?
- 문제를 이렇게 풀기 어렵게 하는 것은 무엇인가?
- 반드시 이 방법으로 해야 하는가?
- 반드시 해야 하는 일이긴 한가?
brute-force와 branching으로 최적화된 답을 찾아내라는 뜻 같다. 다만 이 과정에서 명확한 근거(증명)이 있어야 한다.
명세에 너무 많은 투자를 하지 마라.
요구사항이 바뀌면 명세도 바뀐다. 또한 명세는 요구사항을 포착하기 위한 방법 중 하나일 뿐이다.
절대로 방법론의 노예가 되지 마라.
기존의 비효율적인 방법이 있다면 그것을 개선해야 한다. 비판적으로 분석하고 좋은 점만 뽑아내 최적화해야 한다.
8장. 실용주의 프로젝트
이 장은 지금까지 나온 모든 내용들을 정리하며 pragmatic하게 프로젝트를 진행해야 하기 위해 어떤 것이 필요한지 제시한다.
버그는 한 번만 잡아라.
[자동화하라]의 연장선이다. 현존하는 테스트의 예외사항이 있다면 해당 예외사항을 테스트로 작성해 자동화해야 한다.
주석을 최소화하라.
코드에 대한 설명 주석은 코드에 대한 중복이다. 주석은 소스코드가 설명하지 못하는 점(예를 들어 trade-off나 결정의 이유 등) 다른 곳에서 문서화하기 애매한 부분을 문서화하는 용도로만 사용해야 한다.
사용자의 기대를 부드럽게 넘어서라.
요구사항을 만족하기 위해 사용자와 가깝게 지내는 것은 좋지만 딱 거기까지만 만들지 말고 조금만 더 나아가라는 뜻이다. 모든 사람이 그렇듯 예상치 못한 선물을 받을 때가 제일 기쁘다.
정리
책을 읽으면서 공감되는 부분도 많았고, 반성하는 점도 많았다. 이렇게 느낀 점들을 문장씩만 뽑아 정리했는데도 꽤 분량이 나온다. 그만큼 중요한 개념이 많다는 것이다.
책을 읽다보면 같은 말이 여러 가지 반복되는 것을 알 수 있다.이 중에서도 같은 말이 여러 번 반복되는 것을 알 수 있다. 책임을 가져라. 반복하지 마라. 판단과 근거를 증명하라. 모든 경우의 수 중 최적값을 찾아라. 유연해져라. 자동화하라. 등등. 결국 제일 중요한 몇 가지를 얼마나 다양하게 적용할 수 있는지를 보여주는 책이라 생각한다.
지식의 폭과 깊이를 넓히고, 내가 가진 boundary 안에서 최적값을 찾을 수 있도록 계속계속 정진하자.
마지막으로 * 표기한 문장들만 다시 한 번 모으겠다.
- 깨진 창문을 내버려두지 마라.
- Don't Repeat Yourself.
- 최종 결정이란 없다.
- shell을 익혀라.
- 디버깅 시 여유를 가져라.
- 방어적으로 코딩해야 한다.
- 일반화할 기회를 놓치지 말자.
- 어떤 것이든 잘못되었다고 생각될 때, 그 때 바로 변경해야 한다.
- 여러분이 테스트하지 않으면 사용자가 테스트하게 된다.
- 요구사항은 수집하는 것이 아니라 채굴하는 것이다.
- 자동화하라.
- 증명하라.
'Development > Study' 카테고리의 다른 글
[개발서적] Clean Architecture 정리 (0) | 2023.03.25 |
---|---|
[개발서적] 다시 쓰는 Clean Code 정리 (0) | 2023.03.19 |
[개발서적] Clean Code 정리 (0) | 2022.06.24 |