1. 자신의 기예craft 에 관심을 가져라.
소프트웨어 개발을 잘하고 싶지 않다면 왜 여기에 인생을 바치고 있는가?
2. 자기 일에 대해 생각하라.
자동 조종 장치를 끄고 직접 조종하라. 자신의 작업을 끊임없이 비판적으로 살펴보라.
3. 당신에게는 에이전시agency 가 있다.
당신의 인생이다. 꽉 움켜쥐고, 원하는 바를 이뤄라.
4. 어설픈 변명 말고 대안을 제시하라.
변명하는 대신 대안을 제시하라. 그 일은 할 수 없다고만 말하지 말고, 무엇을 할 수 있는지 설명하라.
5. 깨진 창문을 내버려 두지 말라.
눈에 뜨일 때마다 나쁜 설계, 잘못된 결정, 좋지 않은 코드를 고쳐라.
6. 변화의 촉매가 되라.
사람들에게 변화를 강요할 수는 없다. 대신 미래가 어떤 모습일지 보여주고, 미래를 만드는 일에 그들이 참여하도록 하라.
7. 큰 그림을 기역하라.
주변에 무슨 일이 일어나는지 점검하는 걸 잊을 정도로 세부사항에 빠지지 말라.
8. 품질을 요구 사항으로 만들어라.
프로젝트의 진짜 품질 요구 사항을 결정하는 자리에 사용자를 참여시켜라.
9. 지식 포트폴리오에 주기적으로 투자하라.
학습을 습관으로 만들라.
10. 읽고 듣는 것을 비판적으로 분석하라.
벤더, 매체들의 야단법석, 도그마에 흔들리지 말라. 여러분과 여러분 프로젝트의 관점에서 정보를 분석하라.
11. 한국어든 영어든 하나의 프로그래밍 언어일 뿐이다.
한국어든 영어든 하나의 프로그래밍 언어인 것처럼 다뤄라. 문서 작성도 코드를 작성하듯이 하라. DRY 원칙, ETC, 자동화 등을 지켜라.
12. 무엇을 말하는가와 어떻게 말하는가 모두 중요하다.
효과적으로 전달하지 못하면 좋은 생각이 있어 봐아 소용없다.
13. 문서를 애초부터 포함하고, 나중에 집어넣으려고 하지 말라.
코드와 별개로 만든 문서가 정확하거나 최신 정보를 잘 반영하기는 힘들다.
14. 좋은 설계는 나쁜 설계보다 바꾸기 쉽다.
어떤 게 잘 설계되었다는 건 그 물건이 사용하는 사람에게 적응하여 맞춰진다는 것이다. 이 말을 코드에 적용해 보면, 잘 설계된 코드는 바뀜으로써 사용하는 사람에게 맞춰져야 한다.
15. DRY: 반복하지 말라 Don’t Repeat Yourself.
모든 지식은 시스템 내에서 단 한 번만, 애매하지 않고, 권위있게 표현되어야 한다.
16. 재사용하기 쉽게 만들어라.
재사용하기 쉽다면 사람들이 재사용할 것이다. 재사용을 촉진하는 환경을 만들어라.
17. 관련 없는 것들 간에 서로 영향이 없도록 하라.
컴포넌트를 자족적이고, 독립적이며 단 하나의 잘 정의된 목적만 갖도록 설계하라.
18. 최종 결정이란 없다.
돌에 새겨진 것처럼 바뀌지 않는 결정은 없다. 모든 결정이 바닷가의 모래 위에 쓰인 글씨라 생각하고 변화에 대비하라.
19. 유행을 좇지 말라.
닐 포드가 말했다. “어제의 모범 사례는 내일의 나쁜 사례가 된다.” 유행이 아니라 본질을 보고 아키텍처를 선택하라.
20. 목표물을 찾기 위해 예광탄을 써라.
예광탄은 일들을 시도해 보고 그것들이 목표와 얼마나 가까운 곳에 떨어지는지 봄으로써 목표를 정확히 맞히게 해준다.
예광탄이란, 실제 조건 하에서 즉각적인 피드백을 받는 것으로 수 많은 미지의 기술을 맞닥트릴 때 시스템을 극도로 세세히 명세화하고, 모든 불확실한 점을 잡아매고, 환경 조건을 제약하는 대신 요구 사항으로부터 최종 시스템의 일부 측면까지 빠르게, 눈에 보이게, 반복적으로 도달하게 해 줄 무언가를 찾는 것으로 시스템을 정의하는 중요한 요구 사항을 찾고, 의문이 드는 부분이나 가장 위험이 커 보이는 부분의 코드를 가장 먼저 작성하는 것이다
21. 프로토타이핑으로 학습하라.
프로토타이핑은 학습 경험이다. 프로토타이핑의 가치는 생산한 코드에 있는 것이 아니라 이를 통해 배우는 교훈에 있다.
22. 문제 도메인에 가깝게 프로그래망하라.
사용자의 언어를 사용해서 설계하고 코딩하라.
23. 추정으로 놀람을 피하라.
시작하기 전에 추정부터 하라. 잠재적인 문제점을 미리 발견할 수 있을 것이다.
24. 코드와 함께 일정도 반복하며 조정하라.
구현하면서 얻는 경험을 바탕으로 프로젝트의 소요 시간을 재조정하라.
25. 지식을 일반 텍스트로 저장하라.
일반 텍스트 형식은 시간이 지나도 못 쓰게 되는 일이 없다. 일반 텍스트 형식은 기존 도구를 사용할 수 있고 디버깅과 테스트를 쉽게 만든다.
26. 명령어 셀의 힘을 사용하라.
그래픽 사용자 인터페이스로는 할 수 없는 일에 셀을 이용하라.
27. 에디터를 유창하게fluency 쓸 수 있게 하라.
에디터는 가장 중요한 도구다. 필요한 일을 빠르고 정확하게 하는 방법을 익혀라.
28. 언제나 버전 관리 시스템을 사용하라.
버전 관리 시스템은 여러분의 작업을 위한 타임머신이다. 언제라도 과거로 돌아갈 수 있게 해 준다.
29. 비난 대신 문제를 해결하라.
버그가 여러분의 잘못인지 다른 사람의 잘못인지는 중요치 않다. 어쨌거나 그 버그는 여러분의 문제고, 고쳐야만 한다.
30. 당황하지 말라.
숨을 깊게 들이쉬고, 무엇이 버그의 원인인지 생각하라.
31. 코드를 고치기 전 실패하는 테스트부터.
코드를 고치기 전에 버그 재현에 초점을 둔 테스트부터 만들어라.
32. 그놈의damn 오류 메시지 좀 읽어라.
대부분의 예외는 무엇이 어디서 실패했는지 알려준다. 운이 좋으면 어떤 매개 변수가 쓰였는지도 알 수 있다.
33. “select”는 망가지지 않았다.
OS나 컴파일러의 버그를 만나는 일은 정말 드물다. 심지어 외부 제품이나 라이브러리일지라도 드문 일이다. 버그는 여러분의 애플리케이션에 있을 가능성이 가장 크다.
34. 가정하지 말라. 증명하라.
진짜 데이터와 경계 조건을 사용하여 실제 환경에서 여러분의 가정을 증명하라.
35. 텍스트 처리 언어를 익혀라.
여러분은 매일 많은 시간을 텍스트와 씨름하여 보낸다. 왜 그중 일부를 컴퓨터에게 맡기지 않는가?
36. 여러분은 완벽한 소프트웨어를 만들 수 없다.
소프트웨어는 완벽할 수 없다. 불가피한 오류로부터 여러분의 코드와 사용자를 보호하라.
37. 계약으로 설계하라.
코드는 많지도 적지도 않게 자신의 일이라고 주장하는 만큼의 일만 해야 한다. 이를 계약으로 문서화하고 검증하라.
계약에 의한 설계(DBC)
프로그램의 정확성을 보장하기 위해 소프트웨어 모듈의 권리와 책임을 문서화하고 합의하는 데 초점을 맞춘다. 소프트웨어 시스템의 모든 함수와 메서드는 뭔가를 한다. 그 뭔가를 시작 하기 전에 해당 함수는 세상의 상태에 대해 어떤 전제 조건을 갖고 있을 테고, 루틴이 끝난 후에는 세상의 상태가 어떠할 것이라고 선언할 수 있을 것이다. 이런 전제를 다음 3가지로 나눌 수 있다
- 선행 조건 precondition
루틴이 호출되기 위해 참이어야 하는 것. 즉, 루틴의 요구사항. 루틴의 선행 조건이 위반되면 루틴이 호출되어서는 안된다. 제대로 된 데이터를 전달하는 것은 호출하는 쪽의 책임이다.
- 후행 조건 postcondition
루틴이 자기가 할 것이라고 보장하는 것. 즉, 루틴이 완료되었을 때 세상의 상태. 루틴에 후행 조건이 있다는 것은 루틴이 언젠가는 종료된다는 것을 의미한다
- 클래스 불변식 class invariant
호출자의 입장에서 이 조건이 언제나 참인 것을 클래스가 보장한다. 루틴의 내부 처리 중에서는 불변식이 참이 아니라도, 루틴이 끝나고 호출자로 제어권이 반환되는 시점에는 참이어야 한다. 예를 들어 리스트를 정렬하는 함수의 불변식은 리스트의 길이일 것이다.
그래서 루틴과 그 루틴을 호출하려는 코드 간의 계약은 다음과 같다.
만약 호출자가 륀의 모든 선행 조건을 충족한다면 해당 루틴은 종료 시 모든 후행 조건과 불변식이 참이 됨을 보장한다
38. 일찍 작동을 멈춰라.
일반적으로 죽은 프로그램은 이상한 상태의 프로그램보다 휠씬 피해를 적게 끼친다.
39. 단정문으로 불가능한 상황을 예방하라.
일어날 수 없는 일이라면 단정으로 일어나지 않는 것을 확인하라. 단정은 여러분의 가정을 검증한다. 불확실한 세상에서 단정으로 여러분의 코드를 보호하라.
40. 자신이 시작한 것은 자신이 끝내라.
리소스를 할당한 함수나 객체가 가급적 리소스를 해제하는 책임도 져야 한다.
41. 지역적으로 행동하라.
변경 가능한 변수나 리소스의 유효 범위를 짧고 눈에 잘 들어오게 만들어라.
42. 작은 단계들을 밟아라. 언제나.
언제나 작은 단계를 밟고, 더 진행하기 전에 피드백을 확인하고 조정하라.
43. 예언하지 말라.
여러분이 볼 수 있는 만금만 내다보라.
44. 결합도가 낮은 코드가 바꾸기 쉼다.
여러 가지를 묶어서 결합도가 높아지면 딱 하나만 바꾸기가 어려워진다.
45. 묻지 말고 말하라 Tell. Don’t Ask.
객체에서 값을 얻은 다음, 변환한 후 결과를 다시 객체에 붙이지 말라. 객체가 직접 처리하도록 하라.
46. 메서드 호출을 엮지 말라.
무언가에 접근할 때 마침표를 딱 하나만 쓰려고 노력하라.
47. 전역 데이터를 피하라.
전역 데이터는 모든 메서드에 매개 변수를 추가하는 것과 마찬가지다.
48. 전역적이어야 할 만큼 중요하다면 API로 감싸라.
하지만 정말 정말 전역적이어야 할 때만 써야 한다.
49. 프로그래밍은 코드에 관한 것이지만, 프로그램은 데이터에 관한 것이다.
모든 프로그램은 데이터를 변환한다. 받은 입력을 출력으로 바꾼다. 변환을 사용하여 설계하라.
50. 상태를 쌓아 놓지 말고 전달하라.
함수나 모듈 안에서 데이터를 계속 보관하지 말라. 꺼내어 전달하라.
51. 상속세를 내지 말라.
상황에 맞게 인터페이스, 위임, 믹스인 같은 대안을 사용하라.
52. 다형성은 인터페이스로 표현하는 것이 좋다.
인터페이스는 상속으로 인한 결합 없이도 명시적인 다형성을 만들어 준다.
53. 서비스에 위임하라. Has-A가 Is-A보다 낫다.
서비스를 상속하지 말고 객체 안에 소유하라.
54. 믹스인으로 기능을 공유하라.
믹스인으로 상속세 없이 여러 클래스에 기능을 추가할 수 있다. 인터페이스와 함께 사용하여 고통 없는 다형성을 구현하라.
믹스인(mix-in), 트레이트(trait), 카테고리(category), 프로토콜 확장(extension) 등으로 불린다. 클래스나 객체에 상속을 사용하지 않고 새로운 기능을 추가하여 확장하고 싶을 때, 일련의 함수들을 만들고 이름을 붙인 다음 이 것으로 어떻게든 클래스나 객체를 확장하는 것이다. (언어마다 용어와 방법이 다르다)
55. 외부 설정으로 애플리케이션을 조정할 수 있게 하라.
애플리케이션이 출시된 이후 바뀔 수도 있는 값에 코드가 의존하고 있다면, 그 값을 애플리케이션 외부에서 관리하라.
56. 작업 흐름 분석으로 동시성을 개선하라.
사용자의 작업 흐름 속에 있는 동시성을 최대한 활용하라.
57. 공유 상태는 틀린 상태다.
공유 상태는 버그로 가득 찬 상자를 열어젖힌다. 재부팅 말고는 방법이 없는 경우가 많다.
58. 불규칙한 실패는 동시성 문제인 경우가 많다.
타이밍과 전후 상황의 변화가 동시성 버그를 드러낼 수 있다. 하지만 비일관적이고 재현이 힘들 것이다.
59. 공유 상태 없는 동시성을 위하여 액터를 사용하라.
액터 모델을 사용하여 외부 동기화 없이 동시에 상태를 관리하라.
액터란 자신만의 비공개 지역 상태state 를 가진 독립적인 가상 처리 장치(virtual processor) 이다. 각 액터는 우편함mailbox 을 하나씩 보유하고 있으며 액터가 잠자고 있을 때 우편함에 메시지가 도착하면 액터가 깨어나며 메시지를 처리한다. 처리가 끝나면 우편함의 다른 메시지를 처리하고, 우편함이 비어 있다면 다시 잠든다
60. 칠판으로 작업 흐름을 조율하라.
칠판을 사용하여 참여자들의 독립성과 고립성을 유지하면서도 개별적인 사실과 에이전트들을 조율하라.
61. 여러분 내면의 파충류에게 귀 기울여라.
코드가 반발하는 것처럼 느껴진다면, 사실은 여러분의 무의식이 무엇인가 잘못되었다고 말하려는 것이다.
62. 우연에 말기는 프로그래밍을 하지 말라.
믿을 만한 것만 믿어야 한다. 우발적인 복잡성에 주의하고, 우연한 행운을 목적을 가지고 세운 계획으로 착각하지 말라.
63. 사용하는 알고리즘의 차수를 추정하라.
코드를 작성하기 전에 실행 시간이 얼마나 걸릴지 대락이라도 감을 잡아라
64. 여러분의 추정을 테스트하라.
알고리즘의 수학적 분석이 모든 것을 다 알려주지는 않는다. 실제 환경에서 코드의 수행 시간을 측정해 보라.
65. 일찍 리팩터링하고, 자주 리팩터링하라.
정원의 잡초를 뽑고 식물 배치를 바꾸는 것과 같이 코드도 필요할 때마다 다시 작성하고, 다시 작업하고, 아키텍처를 다시 만들라. 근본적인 문제를 해결하라.
66. 테스트는 버그를 찾기 위한 것이 아니다.
테스트는 여러분의 코드를 보는 한 관점이다. 코드의 설계, API, 결합에 대한 피드백을 준다.
67. 테스트가 코드의 첫 번째 사용자다.
테스트가 주는 피드백으로 코드의 방항을 잡아라.
68. 상향식이나 하향식이 아니라 끝에서 끝까지end-to-end 만들어라.
끝에서 끝을 잇는 조그만 기능 조각들을 만들고, 그 과정에서 문제에 대하여 배워라.
69. 테스트할 수 있도록 설계하라.
코드를 쓰기 전 테스트에 대해 먼저 생각하라.
70. 여러분의 소프트웨어를 테스트하라. 그러지 않으면 사용자가 테스트하게 된다.
가차 없이 테스트하라. 사용자가 여러분 대신 버그를 찾도록 하지 말라.
71. 속성 기반 테스트로 가정을 검증하라.
속성 기반 테스트는 여러분이 절대 시도해 보지 않을 만한 것들을 시도하고, 여러분이 의도하지 않은 방식으로 여러분의 코드를 사용할 것이다.
속성 기반 테스트(property-based testing) 이란, 코드에 존재하는 계약과 불변식 (.37 참고) 을 뭉뚱그려 ‘속성property’ 이라고 부르고, 코드에서 이런 속성을 찾아내어 테스트 자동화에 사용하는 것을 의미한다
단위 테스트를 작성하더라도 인간의 주관이 들어가면 테스트 자체가 틀릴 수 있기 때문에, 이런 속성 기반 테스트를 이용할 수 있다.
속성 기반 테스트의 예로 리스트 정렬 기능의 테스트를 만든다 하면, 우선 정렬된 리스트는 원래 리스트와 길이가 같아야 하고, 정렬된 리스트에서 모든 원소는 다음 원소보다 클 수 없다는 속성도 존재한다. 이를 이용해 테스트를 작성할 수 있을 것이다.
72. 단순함을 유지하고 공격 표면을 최소화하라.
복잡한 코드는 버그의 온상이고, 공격자가 뚫고 들어올 여지도 높인다.
73. 보안 패치를 신속히 적용하라.
공격자들은 최대한 빠르게 취약점을 공격한다. 여러분은 더 빨라야 한다.
74. 이름을 잘 지어라. 필요하면 이름을 바꿔라.
읽는 사람에게 의도를 표현할 수 있는 이름을 붙이고, 의도가 변하자마자 이름을 바꿔라.
75. 자신이 뭘 원하는지 정확히 아는 사람은 아무도 없다.
어쩌면 전반적인 방향은 알 수도 있지만, 다양한 경우를 속속들이 알지는 못한다.
76. 프로그래머는 사람들이 자신이 원하는 바를 깨닫도록 돕는다.
소프트웨어 개발은 사용자와 프로그래머의 공동 창작 작업이다.
77. 요구 사항은 피드백을 반복하며 알게 된다.
요구 사항을 이해하려면 탐험과 피드백을 거쳐야 한다. 결정한 요구 사항의 여파들 바당으로 처음의 발상을 다듬는다.
78. 사용자처럼 생각하기 위해 사용자와 함께 일하라.
시스템이 정말로 어떻게 사용될지 통찰을 얻을 수 있는 가장 좋은 방법이다.
79. 정책은 메타데이터다.
정책을 시스템 코드 안에 고정하지 말라. 대신 시스템이 사용하는 메타데이터로 표현하라.
80. 프로젝트 용어 사전을 사용하라.
프로젝트에서 쓰이는 용어와 어휘들을 모두 한곳에 모으고 관리하라.
81. 생각의 틀을 벗어나지 말고, 틀을 찾아라.
불가능한 문제와 마주쳤다면 진짜 제약 조건을 찾아라. 스스로 물어보라. ‘정말로 반드시 이렇게 해야 하나? 꼭 해야 하는 일이긴한가?’
82. 코드에 혼자 들어가지 말라.
프로그래밍은 어렵고 힘들 수 있다. 친구와 함께 가라.
83. 애자일은 명사가 아니다. 애자일은 무언가를 하는 방식이다.
애자일은 형용사다. 즉, 무언가를 하는 방식이다.
84. 작고 안정적인 팀을 유지하라.
팀은 작고 안정적이어야 한다. 모두가 서로를 신뢰하고 의존해야 한다.
85. 실현하려면 계획하라.
계획하지 않으면 실현되지 않을 것이다. 회고, 실험, 학습, 기술 연마를 계획하라.
86. 모든 기능을 갖춘 팀을 조직하라.
직무가 아니라 기능성을 중심으로 팀을 조직하라. UI/UX 디자이너와 코더를 분리하거나, 프론트엔드와 백엔드, 테스터와 데이터 모델러, 설계와 배포를 분리하지 말라. 코드를 처음부터 끝까지 점진적이고 반복적으로 만들 수 있는 팀을 조직하라.
87. 유행하는 것이 아니라 실제로 잘 맞는 것을 사용하라.
다른 회사가 쓴다는 이유만으로 개발 방법론이나 기법을 도입하지 말라. 여러분의 팀과 여러분의 환경에 잘 맞는 것을 도입하라.
88. 사용자에게 필요할 때 제공하라.
프로세스가 그렇다는 이유안으로 몇 주 혹은 몇 달이나 기다리게 하지말라.
89. 버전 관리 시스템으로 빌드, 테스트, 릴리스를 운용하라.
커밋이나 푸시로 빌드, 테스트, 릴리스를 시작시켜라. 버전 관리 시스템의 태그로 서비스 배포 여부를 지정하라.
90. 일찍 테스트하고, 자주 테스트하라. 자동으로 테스드하라.
빌드 때마다 도는 테스트는 책장에 꽃혀 있는 테스트 계획보다 월씬 더 효과적이다.
91. 모든 테스트가 끝날 때까지는 코딩이 끝난 게 아니다.
당연하다.
92. 버그를 심어 놓고 테스트를 테스트하라.
소스 코드의 복사본에 고의로 버그를 심어 놓고 테스트가 잡아내는지 검증하라.
93. 코드 커버리지만 올리지 말고 상태 조합을 테스트하라.
중요한 프로그램 상태들을 파약해서 테스트하라. 코드의 각 행을 테스트 했다는 것만으로는 부족하다.
코드의 어느 줄이 실행되지 않았는지(커버리지 분석)만으로는 100% 커버리지를 기대하지 마라. 우연히 코드의 모든 줄이 실행되더라도 정말로 중요한 것은 프로그램이 갖는 상태state의 개수이다
예를 들어 0부터 999 사이의 정수 두 개를 받는 다음과 같은 코드가 있다고 할 때
int test(int a, int b) {
return a / (a + b);
}
이 세 줄 짜리 함수는 이론상 1,000,000 가지의 논리적 상태를 가지고, 그 가운데 하나만은 작동하지 않을 것이다 (a, b가 0인경우) 그러므로 프로그램의 모든 상태를 확인해야 한다
94. 버그는 한 번만 잡아라.
한 번 인간 테스터가 버그를 찾았다면 더는 인간 테스터가 그 버그를 만나서는 안 된다. 그 이후로는 자동화 테스트가 확인해야 한다.
95. 수작업 절차를 사용하지 말라.
컴퓨터는 똑같은 명령을 똑같은 순서로 반복해서 실행할 것이다.
96. 사용자를 기쁘게 하라. 그저 코드만 내놓지 말라.
사용자의 사업 가치를 창조하는 해법을 개발하라. 그리고 매일 사용자를 기쁘게 하라.
97. 자신의 작품에 서명하라.
옛 장인들은 자신의 작품에 서명하는 것을 자랑스러워했다. 여러분도 그래야 한다.
98. 먼저, 해를 끼치지 말라.
실패는 피할 수 없다. 그로 인해 누구도 고통받지 않게 하라.
99. 쓰레기 같은 인간을 돕지 말라.
여러분도 똑같은 인간이 되고 말 것이다.
100. 결국 당신의 삶이다. 삶을 사람들과 나누고, 삶을 축하하고, 삶을 만들어가라. 그리고 그걸 즐겨라!
우리에게 주어진 놀라운 삶을 즐기고, 위대한 일을 하라.