실용주의 프로그래머 읽어보기 3주차
들어가며
이 포스트는 데이비드 토머스, 앤드류 헌트의 「실용주의 프로그래머」 Topic12 ~ 20까지 읽고 개인적으로 학습한 내용을 정리한 글입니다.
- 책: 실용주의 프로그래머
- 저자: 데이비드 토머스, 앤드류 헌트
- 출판사: 인사이트
- 챕터: Topic 12 ~ Topic 20
핵심 내용 정리
Topic 12. 예광탄
어둠 속에서 빛는 내는 코드
Tip 20. 목표물을 찾기 위해 예광탄을 써라
- 시스템을 정의하는 중요한 요구 사항을 찾고, 의문이 드는 혹은 가장 위험이 커 보이는 곳을 찾아라
- 이 부분을 최우선 개발 순위로 정하라
- 예광탄 코드는 앞으로 계속 쓸 코드이므로, 오류 검사, 올바른 구조, 문서화, 자체 검사도 찾아야 한다
- 예광탄 개발 방법은 점진적인 접근 방법
예광탄 코드 접근 방법의 장점
사용자가 뭔가 작동하는 것을 일찍부터 보게 된다
- 사용자는 자신이 사용할 시스템에 진전을 보고 기뻐할 것이며, 사용자가 직접 기여하게 함으로서 관심도 커질 것이다
개발자가 들어가서 일할 수 있는 구조를 얻는다
- 애플리케이션의 모든 요소 간 상호 작용을 다 만들고 코드로 구체화까지 해 놓았다면, 생산성과 일관성이 좋아진다
통합 작업을 수행할 기반이 생긴다
- 시스템 요소들이 모두 연결되면, 새로 작성한 코드를 단위 테스트가 끝나자마자 붙일 수 있어 매일 통합할 수 있는 환경이 된다
- 이로 인해 더 빠르고 정확한 디버깅, 테스트를 할 수 있게 된다
보여줄 것이 생긴다
- 프로젝트 후원자에게 데모를 보여줄 수 있게 된다
진행 상황에 대한 더 정확한 감을 잡을 수 있게 된다
- 유스케이스를 볼 수 있게 되며 평가가 쉬워지고 프로젝트의 진전도를 알 수 있게 된다
예광탄이 언제나 목표물을 맞히는 것은 아니다
- 예광탄은 지금 맞히고 있는 것이 무엇인지 보여준다.
- 꼭 그것이 목표물이라는 보장은 없으며, 맞지 않을 경우 목표물에 맞을 때까지 조준을 옮겨야 한다. 이것이 핵심이다
예광탄 코드 대 프로토타이핑
- 프로토타입은 최종 시스템의 어떤 특정한 측면을 탐사하는 것
- 진짜 프로토타입 방식을 따른다면 프로토타입은 어떤 개념을 실험한 것 -> 대충 구현하고 코드를 모두 버려야한다
- 예광탄 코드 접근 방법은 실제 애플리케이션의 요소를 사용자에게 어떻게 상호작용하는 지 보여주고, 개발자에게 코드를 붙일 아키텍처 골격을 제시한다
- 예광탄 코드는 기능은 별로 없지만, 완결된 코드이며, 최종 시스템 골격 중 일부
Topic 13. 프로토타입과 포스트잇
프로토타입 위험 요소를 분석하고 노출시킨 후, 이를 매우 저렴한 비용으로 바로잡을 기회를 얻는 것
프로토타입을 반드시 코드로 작성할 필요는 “없다”
프로토타이핑 대상
프로토타이핑으로 학습하가
- 프로토타이핑 대상
- 아키텍처
- 기존 시스템에 추가할 새로운 기능
- 외부 데이터의 구조 혹은 내용
- 외부에서 가져온 도구나 컴포넌트
- 성능 문제
- 사용자 인터페이스 설계
프로토타입을 어떻게 사용할 것인가?
사용자 인터페이스 프로토타입을 만들 때는 외양과 상호 작용에만 집중할 수 있는 도구를 사용하라
정확성
아키텍처 프로토타이핑
- 프로토타이핑의 목적은 전체적으로 시스템의 동작에 감을 잡는 것
- 아키텍처 프로토타이핑으로 규명할만한 사항
- 주요 영역의 책임 정의 및 적절성
- 주요 컴포넌트 간의 협력 관계의 정의
- 결합도 최소화
- 중복 발생 확인
- 인터페이스와 제약 사항이 수용할만한지 확인
- 각 모듈이 실행 중 필요한 데이터에 접근할 수 있는 경로를 갖고 있는지 확인
- 모듈이 데이터가 필요한 시점에 접근 가능한지 확인
프로토타입 코드를 사용하지 않도록 하려면?
프로토타입을 코드로 만들 때는 시작하기 전에 항상 모든 사람에게 이 코드는 “폐기처분할 코드”라는 사실을 이해시켜야한다
Topic 14. 도메인 언어
실세계 도메인 언어의 예
RSpec - Ruby용 테스트 라이브러리
describe BowlingScore do
it "3점을 네 번 얻으면 총점은 12점" do
score = BowlingScore.new
4.times {score.add_pins(3)}
expect(score.total).to eq(12)
end
end
도메인 언어의 특성
- 내부 도메인 언어
- RSpec 이나 피닉스 라우터
- 호스트 언어를 사용해 원하는 내용을 작성함
- 외부 도메인 언어
- 큐컴버나 앤서블
- 그들 자체의 언어를 사용
내부와 외부 언어의 장단점
기본적으로 가능하다면 YAML, JSON, CSV처럼 널리 통용되는 외부 언어를 사용하라
- 내부 도메인 언어
- 장점
- 호스트 언어를 사용할 수 있음
- 단점
- 호스트 언어의 문법과 의미론을 따라야만 한다
- 외부 도메인 언어
- 장점
- 호스트 언어의 제약이 없다
Topic 15. 추정
Tip 23 추정으로 놀람을 피하라
얼마나 정확해야 충분히 정확한가?
- 기간 추정 시 단위
기간 | 추정의 단위 |
---|---|
1 ~ 15일 | 일 |
3 ~ 6주 | 주 |
8 ~ 20주 | 달 |
20주 이상 | 추정치를 말하기 전에 다시 한번 생각해보라 |
추정치는 어디에서 나오는가?
- 모든 추정치는 문제의 모델에 기반한다
- 그 일을 이미 해본 사람이 성공적인 추정치를 낼 수 있다
무엇을 묻고 있는지 이해하라
- 추정의 첫 단계는 상대방이 무엇을 묻고 있는지 이해하는 것
- 추정의 정확도 뿐만 아니라 도메인에 존재하는 조건에 대해서도 감을 잡을 필요가 있다
시스템의 모델을 만들어라
- 의뢰인의 요청을 이해한 후에 간단하게 기본적인 것만 갖춘 개략적인 모델을 만들어라
- 모델을 만드는 것은 창의적이면서 동시에 장기적으로 유용한 작업일 수 있다
모델을 컴포넌트로 나눠라
- 다 만든 모델은 컴포넌트로 분해할 수 있다
- 이 컴포넌트들이 어떻게 상호작용하는지 수식을 기술해야 한다
각 매개 변수에 값을 할당하라
- 매개 변수를 찾았다면 각 매개 변수에 값을 할당한다. 이 단계에 약간의 오차가 발생할 수 있다
- 이 때 요령은 결과에 가장 큰 영향을 미치는 매개 변수를 찾아서 이 매개 변수의 값을 최대한 정확하게 산출해 내는 것
- 주요 매개 변수 계산에는 나름의 근거가 필요하다
- 현재 시스템에서 발생하고 있는 실제 시간당 요청 수 등
답을 계산하라
- 주요 매개 변수둘의 값을 변경시켜 가며 여러 번 계산하고, 이 가운데 어떤 모델에 잘 들어맞는지 찾아내라
자신의 추정 실력을 기록하라
- 자신이 계산한 추정치를 기록하고, 나중에 이 값이 실제 결과에 얼마나 가까웠는지 평가하라
- 추정치가 틀렸더라도 움츠리거나 도망가지 말고, 틀린 원인을 찾아라
프로젝트 일정 추정하기
Tip 24. 코드와 함께 일정도 반복하며 조정하라
미사일에 페인트칠하기
- 숫자 하나로 대답해야만 하는 상황이 아니라면 여러 가지 시나리오로 추정하기
- 낙관적 추정치
- 가장 가능성이 높은 추정치
- 비관적 추정치
- 값을 범위로 추정하기
코끼리 먹기
- 초기 기능의 구현과 테스트를 마친 후, 이를 첫 번째 반복 주기의 끝으로 삼아라.
- 첫 반복 주기의 경험을 바탕으로 반복 주기의 수와 각 반복 주기에서 무엇을 할지에 대한 처음의 추측을 다듬기
누군가 추정해 달라고 하면 뭐라고 대답해야 할까?
“나중에 연락드릴게요” 라 말해야 한다
Topic 16. 일반 텍스트의 힘
실행주의 프로그래머로서 우리의 기본 재료는 나무나 쇠가 아니라 지식이다
우리가 수집하는 요구 사항은 지식이고, 그 지식을 설계와 구현, 테스트, 문서로 표현한다
일반 텍스트란?
Tip 25 지식을 일반 텍스트로 저장하라.
- 일반 텍스트는 인쇄 가능한 문자로 이루어지고, 정보를 전달하기에 적합한 형식을 갖추어야 한다
텍스트의 힘
- HTML, SMTP, IMAP 등 인터넷에서 사용되는 핵심 프로토콜도 대부분 일반 텍스트다
지원 중단에 대한 보험
- 원래의 애플리케이션이 단종된 지 한참 지나더라도 데이터가 남아 있는 한 그걸 사용할 기회는 찾아온다
기존 도구의 활용
- 컴퓨터 세계의 거의 모든 도구는 일반 텍스트를 다룰 수 있다
더 쉬운 테스트
- 일반 텍스트로 표현하면 특별한 도구를 만들 필요 없이 간단하게 테스트 데이터를 추가하거나 수정할 수 있다
최소 공통분모
자율적으로 서로 데이터를 교환하면서 거칠고 위험한 인터넷을 여행하는 블록체인 기반 지능형 에이전트의 미래 시대에도 텍스트 파일은 어디에나 존재하고 여전히 살아남을 것이다.
Topic 17. 셸 가지고 놀기
- 텍스트 파일을 다루는 프로그래머에겐 명령어 shell이 작업대다
- 모든 작업을 GUI로만 할 수 없으며, GUI 환경의 기능은 일반적으로 설계자가 의도한 범위를 넘을 수 없다
자신만의 셸
- 색깔 조합 설정
- 프롬프트 설정
- 취향에 따라 마음대로 설정하라
- Alias와 Shell 함수
- 명령어 자동 완성
- 명령어 자동 완성을 지원하므로 적극적으로 사용할 것
Topic 18. 파워 에디팅
Tip 27. 에디터를 유창하게 쓸 수 있게 하라
어떤 것이 ‘유창’한 것인가?
마우스 없이 사용할 것
- 텍스트를 편집할 때 문자, 단어, 줄, 문단 단위로 커서를 이동하거나 내용을 선택
- 코드를 편집할 때 반대쪽 괄호로 이동하거나, 함수, 모듈 등 다양한 문법 단위로 커서를 이동
- 변경한 코드의 들여쓰기를 자동 정렬
- 여러 줄의 코드를 명령 하나로 주석 처리했다가 다시 주석 해제
- 실행 취소를 여러번 했다가 취소한 명령을 재실행
- 에디터 창을 여러 구역으로 쪼개고, 이 구역 사이를 이동
- 특정 줄 번호로 이동
- 여러 줄을 선택한 후 가나다순으로 정렬
- 문자열로, 또 정규 표현식으로 검색
- 선택 영역이나 패턴 검색을 이용해 일시적으로 여러 개의 커서를 만든 다음 동시에 텍스트를 편집
- 현재 프로젝트의 컴파일 오류를 표시
- 현재 프로젝트의 테스트를 실행
유창해지기
- 유창하게 에디터를 쓰는 방법
- 자신의 에디터 사용 모습 관찰 > 더 나은 방법이 있는지 찾아보기
- 유용한 기능을 찾았다면 이 기능을 반복 숙달
에디터 성장시키기
- 사용 중인 에디터에서 명백한 한계에 봉착한다면 필요한 기능을 추가하는 확장 기능을 찾아라
- 사용 중인 에디터의 확장 기능 언어를 파악해보라
- 더 멀리가면 온전한 확장 기능을 만들기도 해보라
Topic 19. 버전 관리
버전 관리 시스템은 일종의 거대한 ‘실행 취소’ 키와 같다
소스 코드부터 시작
Tip 28 언제나 버전 관리 시스템을 사용하라
- VCS의 장점
- 코드 변경자 확인
- 현재 버전과 이전 버전의 코드 비교
- 이번 릴리스의 변경 line 수
- 자주 변경되는 파일 이름
- 자료의 장기간 보관 가능
- 동일 파일을 둘 이상의 사용자가 동시에 작업할 수 있다
- 이런 종륭릐 정보는 버그 추적이나, 감사 기능, 성능 관리, 품질 관리 때 매우 소중한다
브랜치 사용하기
- VCS의 매우 강력하고 유용한 기능으로 브랜치가 있다
- 브랜치의 장점
- 다른 브랜치로부터의 격리
- 상호간의 간섭이 불가능해 병렬적인 작업이 가능함
- 브랜치가 팀의 프로젝트 업무 흐름에서 핵심이 되는 경우가 많음
- 다른 브랜치로부터의 격리
프로젝트 허브로서의 버전 관리
- 버전 관리 저장소에 필요한 기능들
- 확실한 보안과 권한 관리
- 직관적인 UI
- 명령 줄에서도 모든 작업 수행 가능
- 자동화된 빌드와 테스트
- 브랜치 병합을 잘 지원
- 이슈 관리. 커밋이나 브랜치 병합과 연계가 가능하고 지표도 구할 수 있으면 이상적
- 적절한 보고서 기능. 칸반 보드 형식으로 처리할 이슈나 작업을 표시할 수 있으면 매우 유용
- 원활한 팀 의사소통을 돕는 기능.
Topic 20. 디버깅
디버깅의 심리
Tip 29. 비난 대신 문제를 해결하라
- 디버깅은 많은 개발자에게 예민하고 감성적인 주제
- 디버깅은 단지 문제 풀이일 뿐이라는 사실을 받아들이고, 그런 마음으로 공략하라
디버깅 사고방식
Tip 30. 당황하지 말라
- 자신의 자아를 보호하기 위해 늘 켜 놓은 많은 방어막을 꺼 버리고, 자신을 짓누르고 있는 프로젝트의 압력을 무시해서 자신을 편안하게 만들어야 한다
- 디버깅할 때 근시안의 함정에 주의하라
- 표면에 보이는 증상만 고치려는 욕구를 이겨 내라
실마리 찾기
- 버그를 살펴보기 전에 일단 작업 중인 코드가 경고 없이 깨끗하게 빌드되는지부터 확인하라
- 어떤 문제건 해결을 위해 관련 자료를 모두 모아야한다
- 정확하게 관찰해야 한다
디버깅 전략
버그 재현하기
Tip 31. 코드를 고치기 전 실패하는 테스트부터
- 버그는 번식하지 “않으며” 우리가 해야 하는 일은 버그를 “재현”하는 것이다
- 버그를 고치는 첫걸음으로 가장 좋은 것은 그 버그를 재현할 수 있게 만드는 것이다
미지의 세계에 온 프로그래머
Tip 32. 그놈의 오류 메시지 좀 읽어라
이상한 결과
- 디버거를 붙인 다음 자신의 실패한 테스트를 이용해 문제를 재현하라
- 디버거에 잘못된 값이 나타나는지부터 문제를 재현하라
- 옆에 종이와 펜을 두고 메모하는 것이 도움이 될 때도 있다
입력값에 따라 바뀜
- 데이터에서 시작하는 것이 더 디버깅하기 쉬운 경우도 있다
이진 분할
- 특정 데이터 세트에서 버그가 발생하는 경우
- 데이터 세트를 둘로 나누고, 각각을 프로그램에 넣었을 때 문제가 발생하는 지 확인
- 현재 릴리스에서 과거 릴리스에는 없었던 버그가 발생했을 경우
- 현재 릴리스에서 실패하는 테스트 생성
- 문제가 없었던 버전 중 가장 최근 버전과 현재 버전 사이에서 중간 저옫에 위치하는 릴리스를 선택하고 테스트 수행
로깅과 트레이싱
- 트레이싱 구문
- 화면 혹은 파일에 출력하는 작은 진단용 메시지
- 디버거가 진단할 수 없는 몇 가지 종류의 오류를 진단하는 데 효과적
- 호출 트리에서 내려갈 때마다 트레이싱 구문을 추가할 수 있다
- 트레이싱 구문으로 남기는 메시지는 규칙적이고 일관된 형식이어야 한다
고무 오리
- 문제의 원인 분석을 위해 누군가에게 문제를 설명하는 방법
소거법
- 만약 여러분이 ‘단 하나만 변경’했는데 시스템이 작동을 멈춘다면 설사 아무 관련이 없어 보여도 십중팔구 직접적이든 간접적이든 변경한 그 하나에 책임이 있다
놀라운 구성
Tip 34 가정하지 말라. 증명하라.
- 어떤 버그로 놀라게 될 때 애지중지 믿고 있던 진실들을 재평가해야만 한다
- 예상치 못한 ‘놀라운’ 실패를 대면했을 때 자신이 세운 가정이 적어도 하나는 잘못되었다는 것을 받아들여야한다
- 버그와 관련된 루틴이나 코드가 제대로 작동하는 걸 ‘안다’고 해서 대충 얼버무리고 지나치지 말라. 그것을 증명하라
- 놀라운 버그를 마주쳤을 때, 단순히 그걸 고치는 것을 넘어서 왜 이 문제가 더 일찍 발견되지 않았을까 생각해봐야 한다
- 버그가 누군가의 잘못된 가정으로 발생했다면 이 문제를 전체 팀과 함께 토론하라
디버깅 체크 리스트
- 보고된 문제가 내재하는 버그의 직접적 결과인가 아니면 단순한 증상인가?
- 버그가 정말로 여러분이 사용하는 프레임워크에 있나? OS에, 코드에 있나?
- 이 문제를 동료에게 상세히 설명한다면 어떻게 말하겠는가?
- 의심 가는 코드가 단위 테스트를 통과한다면 테스트는 충분히 갖춰진 것인가? 이 데이터로 테스트를 돌리면 무슨 일이 생기는가?
- 이 버그를 야기한 조건이 시스템의 다른 곳에도 존재하는가? 다른 버그가 발전이 되고 있는 것은 아닌가?