실용주의 프로그래머 2
실용주의 접근법
- 소프트웨어 개발은 좋은 설계에 뿌리를 두고 있다.
- 시스템에서 중복을 제거하고, 파편화를 경계하라
- 환경의 변화로부터 프로젝트를 보호해야 한다.
- 요구사항을 모으고, 설계를 검증하고 코드 구현을 할 수 있는 예광탄 방식을 사용해보라
- 프로토타입의 사용을 고려해라
- 추상화된 언어의 사용법을 고민해라
- 추정을 통해 시간과 자원의 필요를 예측해라.
좋은 설계의 핵심
좋은 설계는 나쁜 설계보다 바꾸기 쉽다.
잘 설계된 코드는 바꾸기 더 쉽다. (Easier to Change)
- 결합도를 줄이면 좋은 이유는? 관심사를 분리해서 ETC
- 단일 책임 원칙이 유용한 이유는? 요구 사항에 따라 모듈 하나만 바꾸면 되니까 ETC
- 이름 짓기가 중요한 이유는 ? 이름이 좋으면 코드를 읽기 쉬우니, ETC
ETC 도 규칙이 아니라 가치이기에, 옳바른 방향으로 의사 결정을 내릴 때 참고할 수 있는 수단일 뿐이다. 이 수단을 자신의 것으로 만들기 위해서는 의식적으로 스스로에게 물어봐야 한다.
그러나 현재 단계에서는 미래의 변경을 더 쉽게 만들기 위한 길이 무엇인지를 명확히 알기 어렵다.
- 교체 가능하게 만들기 위해 결합도를 낮추고 응집도를 높여라
- 직관을 발전시키는 기회로 삼기 위해 엔지니어링 일지에 현재 상황과 선택, 변경 사항에 대한 추측을 정리해 둬라.
이런 경험은 쌓여서 나중에 비슷한 갈림길에서 도움이 될 것이다.
중복의 해악
지식은 고정적이지 않고 변화한다. 따라서 우리는 항상 우리의 시스템을 유지 보수해야 한다. 유지 보수를 쉽게 하기 위해서는 DRY 원칙을 따르는 것이다.
모든 지식은 시스템 내에서 단 한 번만, 애매하지 않고 권위 있게 표현되어야 한다.
Dont Repeat Yourself 인 DRY 를 따르지 않으면 똑같은 것이 두 군데 이상에 표현되고, 이는 변경점을 넓힌다.
DRY 원칙이 단순히 똑같은 소스 코드를 복사하지 말라는 것은 아니다. 이는 지식의 중복, 의도의 중복에 대한 것이다. 똑같은 코드라도 개념이 다르고 역할이 다르면 중복이 아닌 것이다.
어찌보면, 함수에 대한 주석을 다는 것도 DRY 원칙을 위반하는 것일 수 있다.
1
2
3
4
5
6
7
8
9
10
# 계좌의 수수료를 계산한다
# 반려된 수표 하나당 $20
# 계좌가 3일 넘게 마이너스면 하루에 10$ 부과
def fees(a)
f = 0
...
end
함수의 의도는 주석으로 한 번, 코드로 한 번 표기되었다. 수수료가 변경되면 코드와 주석을 모두 변경해야 한다. 이러한 주석은 DRY 원칙의 위반이라고 할 수 있다. 이 외에도, 데이터의 구조에 있어서 특정 필드가 다른 필드의 연산으로 생성되는 경우엔 해당 필드를 ‘중복’해서 가지고 있어야 할 이유가 있는지 생각해보라.
가장 어려운 유형은 개발자 같의 중복이다. 이를 해결하기 위해서는 의사소통을 잘하는 튼튼하고 유대가 돈독한 팀을 만들 수 밖에 없다. 일일 스크럼 스탠드업 미팅을 운영하거나, 슬랙 채널을 활용할 수도 있다. 팀원 중 한명을 프로젝트 사서로 임명해서 지식 교환을 돕고, 코드 리뷰를 장려해라.
직교성
직교성은 서로 간의 독립성을 보장해서 결합도 줄이기(decoupling)를 의미한다. 하나가 바뀌어도 나머지에 영향을 주지 않으면 서로 직교한다고 할 수 있다. 잘 설계된 시스템일수록 각각의 구성 요소가 서로 직교할 것이다.
직교성이 뛰어난 시스템은 변경과 조정에 있어서 유연하다. 이를 통해 우리는 생산성 향상과, 리스크 감소를 꾀할 수 있다.
- 작고 자족적인 컴포넌트를 구성하기에 개발과 테스트가 용이하다.
- 컴포넌트에 명확하고 잘 정의된 책임이 할당되어 있으면 새로운 컴포넌트와 결합이 용이하기에 재사용성이 높아진다.
- 감염된 코드가 격리되어 있기에, 이식성이 좋고, 오염의 전파를 막을 수 있다.
- 시스템이 견고해진다.
직교적으로 설계하기 위해서는 계층 구조를 활용할 수 있다. 각 계층은 서로 간의 추상화된 계층을 사용한다. 즉 다른 코드에 영향을 끼치지 않으면서 기반 구현들을 변경할 수 있다. 또한 현실 세계의 변화와 설계 사이의 결합도를 얼마나 줄였는지도 확인해봐라. 내가 제어할 수 없고, 바꿀수 없는 속성에 의존해서는 안된다.
외부에서 만든 툴킷이나 라이브러리를 도입할 때는 항상 시스템의 직교성을 해치지 않는지 주의 깊게 살펴봐야 한다. 기술을 현명하게 선택해라. 자신이 사용하는 기술과 코드를 항상 비판적으로 바라보는 습관을 길러라. 기회가 있을 때마다 코드의 구조와 직교성을 개선하기 위해 노력하라.
테스트를 정규 빌드 과정의 일부로 수행하고, 단위 테스트를 작성하는 행위 자체로 직교성을 검증해봐라.
가역성
당신이 가진 생각이 딱 하나밖에 없다면, 그것만큼 위험한 것은 없다.
엔지니어는 문제를 풀 때 여러 가지 방법을 고려해야 한다. 결정을 내리더라도, 결정이 바뀔 수 있다고 생각해라. 결정은 돌에 새겨진 것이 아니라 바닷가의 모래 위에 쓰인 글씨고, 언제든지 큰 파도가 글씨를 지울 수 있다.
바꾸기 쉽게 만들어야 한다. 외부의 API 를 여러분이 만든 추상화 계층 뒤로 숨겨라. 여러분의 코드를 여러 컴포넌트로 쪼개라. 어떤 미래가 펼쳐질지 알 수 없기에, 여러분의 코드가 로큰롤을 할 수 있게 해라. 락을 할 수도 있고 필요한 경우 롤을 할 수도 있어야 한다.
예광탄
예광탄은 일반 탄환들 사이에 일정하게 끼어 있다. 예광탄을 통해서 실시간 피드백을 바탕으로 조준을 재조정할 수 있다. 프로젝트에서도 즉각적인 피드백을 받기 위해서 예광탄 개발을 활용한다. 요구 사항으로부터 최종 시스템의 일부 측면까지 빨리, 눈에 보이게, 반복적으로 도달하게 해 줄 무언가를 찾아야 한다.
시스템을 정의하는 중요한 요구 사항을 찾고, 해당 코드를 가장 먼저 작성해라. 예광탄 코드에 모든 기능이 들어가 있을 필요는 없지만 실제 시스템을 구성하는 요소를 모두 연결해 놓아야 한다. 목표물에 얼마나 근접했는지 확인하고 조정할 수 있어야 한다. 일단 정확하게 조준하고 나면 기능을 추가하는 일은 쉽다. 예광탄 방법은 다음과 같은 장점이 있다.
- 사용자가 뭔가 작동하는 것을 일찍부터 보게 된다.
- 개발자가 들어가서 일할 수 있는 구조를 얻는다.
- 통합 작업을 수행할 기반이 생긴다.
- 보여줄 것이 생긴다.
- 진행 상황에 대해 더 정확하게 감을 잡을 수 있다.
예광탄이 언제나 목표물을 맞히는 것은 아니지만, 점차 개선을 통해 목표물에 더 가까워지돌고 바꿀 수 있을 것이다. 가벼운 개발 방법론을 통해서 더 정확한 버전을 만들어가자. 이는 프로토타이핑과 차이가 있는데, 프로토타이핑은 최종 시스템의 특정한 부분을 실험해보기 위해서 구현한 것이다. 이 실험이 끝나면 모두 버려야 한다. 반면 예광탄 방법은 완결된 코드로, 최종 시스템의 골격이 될 것이다.
추정
추정하는 법을 배우고 추정 능력을 통해서 무언가의 규모를 직관적으로 짚을 정도가 되면, 추정 대상의 가능성을 가늠하는 능력을 발휘할 수 있을 것이다.
추정치는 문제의 모델에 기반한다. 상대방이 묻고 있는 문제와 조건에 대해서 감을 잡아야 한다. 이후, 개략적인 모델을 만들면서 추정치를 예측해보자. 모델을 정교하게 만들수록 추정치도 정확해질 것이지만, 모델을 만드는데 소모되는 노력에 비례하지는 않을 것이다. 그 정도를 타협해라. 이후에, 모델을 컴포넌트로 나누고 각 모델에 영향을 미칠 수 있는 매개 변수를 산출해보자. 스프레드시트를 활용해서 답을 산출하고, 이 추정치를 기록해둬라. 나중에 이 실제 값이 얼마나 가까운지를 비교 분석하면서 추정 실력을 키울 수 있는 경험이 될 것이다.
미 해군은 PERT 라고 부르는 방법론을 사용한다. 이는 낙관적 추정치, 가능성이 높은 추정치, 비관적 추정치를 갖는다.혹은 기능을 매우 작은 단위로 나누고, 각 작업에 대한 반복 주기를 통해서 추측을 다듬어 갈 수 있을 것이다. 즉, 코드와 함께 일정도 반복하여 조정하는 형식이다.