TOC
- 참고
- Topic 8 : 좋은 설계의 핵심
- Topic 10 : 직교성
- Topic 11 : 가역성
- Topic 12 : 예광탄
- Topic 13 : 프로토타입과 포스트잇
- Topic 15 : 추정
- 총평
- 실천 계획
참고
본 내용은 실용주의 프로그래머 를 읽고 정리한 내용입니다. 책의 내용과 함께 개인적인 의견과 생각을 담아 작성하였습니다.
Topic 8 : 좋은 설계의 핵심
ETC 원칙 : Easier To Change
좋은 설계는 나쁜 설계보다 바꾸기 쉽다
어떤 게 잘 설계되었다는 건 그 물건이 사용하는 사람에게 적용하여 맞춰진다는 것이다. 잘 설계된 코드는 바뀜으로써 사용하는 사람에게 맞춰져야 한다. 그래서 우리는 ETC, 바꾸기 더 쉽게 만들어야 한다.
모든 것은 ETC?
- 왜 결합도를 줄여야 하는가? 관심사를 분리함으로써 각각이 더 바꾸기 쉬워지기 때문이다.
- 단일 책임 원칙(SRP)은 왜 유용한가? 요구 사항이 바뀌더라도 모듈 하나만 바꿔서 반영할 수 있기 때문이다.
- 왜 이름 짓기가 중요한가? 이름이 좋으면 코드를 읽기 쉬워지고, 코드를 바꾸려면 코드를 읽어야 하기 때문이다.
ETC는 안내자이자 가치이다
ETC는 선택의 갈림길에서 도움을 주는 안내자다. 파일을 바꾸고 추가할 때 스스로 물어보자. "내가 방금 한 일이 전체 시스템을 바꾸기 쉽게 만들었을까?" 앞으로 어떤 모습으로 바뀔지 잘 모르겠을 때 언제건 궁극의 '바꾸기 쉽게'라는 길을 선택하라.
DRY 원칙 : Don't Repeat Yourself
우리는 유지 보수 속에 산다
프로그래머는 늘 유지 보수 모드에 있다. 유지 보수는 별개의 활동이 아니며 전체 개발 과정의 일상적인 부분이다. 소프트웨어를 신뢰성 높게, 유지보수하기 쉽게 만드는 길은 바로 DRY 원칙을 따르는 것이다.
모든 지식은 시스템 내에서 단 한 번만, 확실하고 권위 있게 표현되어야 한다.
DRY를 따르지 않으면 하나를 바꿀 때 나머지도 바꿔야 한다. DRY 여부를 판단할 때 이런 관점을 따져보면 된다.
- 코드의 어떤 측면 하나를 바꿔야 할 때, 여러 곳을 바꾸고 있나?
- 여러 가지 다른 형태를 바꾸고 있나?
- 코드를 바꾸고 문서도 바꾸는가?
DRY의 위배를 허용할 때
개발을 진행할 때에는 성능상의 이유로 DRY를 위배할 수도 있다. 요령은 중복의 영향을 국소화 하는 것이다. 모듈의 바깥 세상에는 DRY 원칙 위배를 노출하지 않는다.
모듈이 자료 구조를 노출하면 언제나 모듈의 구현과 자료구조의 사용부 사이에 결합이 생긴다. 가능하다면 객체의 속성을 읽고 쓸 때 접근자(accessor)를 사용하라. 이렇게 하면 객체의 내부 구조를 숨길 수 있고, 객체의 내부 구조를 바꾸더라도 다른 코드를 바꿀 필요가 없다.
단일 접근 원칙: Uniform Access Principal
모듈을 통해 제공되는 모든 서비스는 일관된 표기법(notation)으로 사용할 수 있어야 한다. 저장한 값으로 구현되었건, 계산을 통해 구현되었건 상관없이.
개발자간의 중복
가장 발견하거나 없애기 어려운 중복은 같은 프로젝트에서 일하는 개발자들 사이에서 발생할 것이다. 이런 중복의 방지를 위해 빈번히 소통하는 것이 최선책이다. '데일리 스크럼'을 운영하라. 그리고 다른 사람의 소스 코드와 문서를 반드시 읽어라. 일상적으로든 코드 리뷰를 통해서든. 그리고 거기에서 배우고 중복을 파악해라.
재사용하기 쉽게 만들어라
뭔가를 직접 만드는 것보다 기존의 것을 찾아내고 재사용하기 쉬운 환경을 조성해야 한다. 사람들은 쉽지 않으면 하지 않는다. 재사용에 실패한다면 지식 중복의 위험을 감수해야 한다.
Topic 10 : 직교성
직교성(orthogonality)은 기하학에서 빌려온 용어다. 벡터에서 두 선이 직각으로 만나는 경우를 직교한다고 하며, 두 선은 각자의 방향에 대해 독립적이다.
컴퓨터 과학에서는 이러한 독립성을 '결합도 줄이기(decoupling)'를 의미한다. 하나가 바뀌어도 나머지에 어떤 영향도 주지 않으면 서로 직교한다고 할 수 있다.
관련 없는 것들 간에 서로 영향이 없도록 하라
컴포넌트들이 각기 격리되어 있으면 어느 하나를 바꿀 때 나머지 것들을 걱정하지 않아도 된다. 직교적인 시스템은 두 가지 장점이 있다. 바로 '생산성 향상'과 '리스크 감소'다.
생산성 향상
- 변화를 국소화해서 개발 시간과 테스트 시간이 줄어든다. 코드의 추가와 수정이 단위적이기 때문이다.
- 재사용을 촉진한다. 만들었던 의도와 달리 다른 곳에서 다른 용도로 재조합해 사용할 수 있다.
리스크 감소
- 감염된 코드가 격리된다. 문제가 생겨도 다른 부분에 영향을 주지 않고, 국소적인 부분만 해결하면 된다.
- 테스트를 더 많이 하게 된다. 테스트를 설계하고 실행하기 더 쉬워지기 때문이다.
- 특정 업체나 제품, 플랫폼에 덜 종속적이게 된다. 외부로 연결되는 인터페이스들은 전체 중 작은 부분에 격리하기 때문이다.
설계
시스템은 서로 협력하는 모듈의 집합으로 구성되어야 한다. 각 모듈은 다른 부분과 독립적인 기능을 구현해야 한다.
계층(layer) 구조는 직교적 시스템을 설계하는 강력한 방법이다. 각 계층은 자기 바로 밑에 있는 계층이 제공하는 추상화만을 사용하기 때문에, 다른 코드에 영향을 끼치지 않으면서 기반 구현들을 변경할 수 있게 되어 유연성이 높아진다.
직교적인 설계인지 검증하기
컴포넌트들을 나누었을 때 스스로에게 물어보라. "특정 기능에 대한 요구 사항을 대폭 변경하는 경우 몇 개의 모듈이 영향을 받는가?" 바람직한 답은 '하나'이다.
자신의 힘으로 제어할 수 없는 속성에 의존하지 말라
"현실 세계의 변화와 설계 사이의 결합도를 얼마나 줄였는가?" 주민등록번호, 우편 번호, 이메일 주소 등 외부의 식별자는 제어할 수 없고, 언제 어떤 이유로든 바뀔 수 있다. 자신의 힘으로 제어할 수 없는 속성에 의존하지 말라.
기술을 현명하게 선택하라
외부에서 만든 툴킷이나 라이브러리를 도입할 때 시스템의 직교성을 해치지 않는지 주의 깊게 살펴보라. 코드에 수용해서는 안 될 변화를 강요하지는 않는지 검토해보라.
직교성을 유지하기 위한 코딩
코드의 결합도를 줄여라
부끄럼쟁이(shy) 코드를 작성하라. 불필요한 것은 다른 모듈에 보여 주지 않으며, 다른 모듈의 구현에 의존하지 않는 코드를 작성하라. 객체의 상태를 바꿀 필요가 있다면 객체가 직접 상태를 바꾸게 하라.
유사한 함수를 피하라
유사해 보이는 함수를 여럿 구현해야 할 때가 있다. 아마도 시작과 끝에서는 동일한 코드를 사용하지만, 중간의 알고리즘이 다를 것이다. 중복 코드는 구조에 문제가 있다는 징후다. 전략 패턴을 사용하여 더 낫게 구현할 수는 없는지 고민해 보기 바란다.
비판적으로 생각하라
자신이 작성하는 코드를 항상 비판적으로 바라보는 습관을 길러라. 기회가 있을 때마다 코드의 구조와 직교성을 개선하기 위해 노력하라.
테스트
단위 테스트를 작성하는 행위 자체가 직교성을 테스트해 볼 수 있는 기회다. 단위 테스트를 빌드하고 실행하기 위해 어떤 작업이 필요한지 생각하라. 시스템의 상당 부분을 불러와야 한다면 모듈과 나머지 시스템 사이의 결합도를 충분히 줄이지 못한 것이다.
버그 수정
버그 수정은 시스템의 직교성을 총체적으로 점검해 볼 수 있는 값진 시간이다. 문제가 발생했다면 버그 수정을 얼마나 국소화할 수 있는지 평가해 보라. 이를 위해 자동화에 힘을 쏟아야 한다.
Topic 11 : 가역성
되돌릴 수 없는 결정을 줄여야 하는 까닭은 우리가 프로젝트 초기에 늘 최선의 결정을 내리지는 못하기 때문이다. 결정이 바뀌지 않을 것이라 가정하고서 발생할지도 모를 우연한 사건에 대비하지 않는 데에서 실수가 나온다. 결정이 돌에 새겨진 것이 아니라 바닷가의 모래 위에 쓰인 글씨라 생각하라. 언제든지 큰 파도가 글씨를 지워버릴 수 있다. 최종 결정이란 없다.
유연한 아키텍처
아키텍처가 변덕스러운 환경에서 어떻게 계획을 세울 수 있겠는가? 못한다. 여러분이 할 수 있는 것은 그저 바꾸기 쉽게 만드는 것이다.
- 외부의 API를 여러분이 만든 추상화 계층 뒤로 숨겨라.
- 여러분의 코드를 여러 컴포넌트로 쪼개라.
Topic 12 : 예광탄
움직이는 목표물을 맞히려면 실제 조건하에서 즉각적인 피드백을 받아야 한다. 우리는 이것을 시각적으로 묘사하기 위해 '예광탄 개발'이라는 말을 쓴다.
빨리, 눈에 보이게 도달하기
- 시스템을 정의하는 중요한 요구사항 찾기
- 의문이 드는 부분이나 가장 위험이 커 보이는 곳 찾기
- 이런 부분의 코드를 가장 먼저 작성하도록 개발 우선순위 정하기
: 전체 애플리케이션에서 불확실한 곳이 어디인지 찾아보고 해당 부분을 작동시키는데 필요한 뼈대를 추가한다.
예광탄 코드의 목적
한 시스템을 처음 접근할 때의 불확실성을 최대한 배제하는 것이다. 간단하더라도 처음부터 끝까지 시스템을 구성하는 요소를 모두 연결해 놓은 후라면 목표물에 얼마나 근접했는지 확인할 수 있다. 필요하다면 조정도 할 수 있다. 일단 정확하게 조준하고 나면 기능을 추가하는 일은 쉽다.
예광탄 코드 접근의 장점
- 사용자가 뭔가 작동하는 것을 일찍 보게 된다.
- 개발자가 들어가서 일할 수 있는 구조를 얻는다.
- 통합 작업을 수행할 기반이 생긴다.
- 진행 상황에 대해 더 정확하게 감을 잡을 수 있다.
예광탄이 언제나 목표물을 맞힐 순 없다
예광탄 코드 기법은 일이 어떻게 될지 100% 확신할 수 없는 상황에서 사용된다. 때문에 맞히지 못할 수도 있다. 다만 지금 있는 것을 목표물에 더 가까워지도록 바꿔라. 그리고 가벼운 개발 방법론을 선택했다는 사실에 감사하라. 코드의 크기가 작으면 관성 역시 약하므로 빠르고 쉽게 바꿀 수 있다.
프로토타이핑과의 차이점
프로토타입은 최종 시스템의 어떤 특정한 측면을 탐사해 보는 것이 목표다. 진짜 프로토타입 방식을 따른다면 프로토타입은 어떤 개념을 실험해보느라 대충 끼워 맞추어 구현한 것이므로 모두 버려야 한다. 그리고 실험 과정에서 얻은 교훈을 바탕으로 코드를 새로 작성한다.
하지만 예광탄 코드 접근 방법은 다른 종류의 문제를 푼다. 애플리케이션이 전체적으로 어떻게 연결되는지를 알고 싶다. 사용자에게 실제로 애플리케이션의 요소들이 어떻게 상호 작용하는지 보여주고 싶고, 개발자에게는 코드를 붙일 아키텍처 골격을 제시하고 싶다.
정리하면, 프로토타입은 나중에 버리는 코드를 만든다. 예광탄 코드는 기능은 별로 없지만 완결된 코드이며, 최종 시스템 골격 중 일부가 된다. 프로토타입은 예광탄을 발사하기 전에 먼저 수행하는 정찰이나 정보 수집과 같은 것이다.
Topic 13 : 프로토타입과 포스트잇
포스트잇은 작업 흐름이나 애플리케이션 로직과 같이 동적인 것을 프로토타이핑할 수 있는 훌륭한 도구다.
프로토타이핑 대상
대상은 위험을 수반하는 모든 것이다. 이전에 해 본 적이 없는 것, 증명되지 않았거나, 실험적이거나, 의심이 가는 것, 마음이 편하지 않은 것 등
- 아키텍처
- 기존 시스템에 추가할 새로운 기능
- 외부 데이터의 구조 혹은 내용
- 외부에서 가져오는 도구나 컴포넌트
- 성능 문제
- 사용자 인터페이스 설계
프로토타이핑의 목적
프로토타이핑의 가치는 생산한 코드에 있는 것이 아니라 이를 통해 배우는 교훈에 있다. 그리고 목적은 전체적으로 시스템이 어떻게 동작할지에 대해 감을 잡는 것이다. 세부사항은 무시한다.
아키텍처 프로토타입을 설계한다면?
- 주요 영역의 책임이 잘 정의되었고 적절한가?
- 주요 컴포넌으 간의 협력 관계가 잘 정의되었는가?
- 결합도는 최소화했는가?
- 중복이 발생할 만한 곳이 있는가?
- 정의된 인터페이스와 제약 사항은 수용할 만한가?
- 각 모듈이 실행 중에 필요한 시점에 데이터 접근이 가능한가?
프로토타입 코드를 사용하지 않도록 하려면
프로토타입은 폐기된다. 하지만 내면을 잘 모르는 사람들에게는 충분히 매력적일 수 있다. 때문에 모든 사람에게 여러분이 폐기 처분할 코드를 작성하고 있다는 사실을 이해시켜야 한다. 코드는 불완전하며, 완성할 수 없다는 사실을 분명히 주지시켜야 한다. 기대치를 적절히 설정해두지 않으면 프로토타입 자체 또는 이를 보완한 결과를 배포하자고 주장할지도 모른다.
Topic 15 : 추정
프로젝트를 진행하다보면 미래를 계산하고 예측해야 할 때가 있다. 이를 위한 추정의 기술을 알아보자.
얼마나 정확해야 충분히 정확한가
누군가 추정치를 물었을 때 가장 중요한 것은 답변이 사용될 상황이 무엇인지다. 매우 높은 정확도의 답을 요구하는가, 아니면 큰 그림만을 요구하는가?
흥미로운 점은 추정값에 사용하는 단위가 결과의 해석에 차이를 가져온다. 정확도가 높은 답변처럼 보이고 싶다면 단위의 크기를 줄여라. 예를 들어, 4개월이 아니라 130일이라고 대답하면 더 정확해 보인다. 전달하려는 정확도를 고려하여 답변의 단위를 선택하라.
추정치를 구하는 노하우
모든 추정치는 문제의 모델에 기반한다. 모델을 작성하는 기술에 대해 깊이 파고들기 전에 항상 좋은 답을 알려주는 기본적인 추정의 비법은 그 일을 해본 사람에게 물어보기다. 다른 사람의 경험을 바탕으로 놀라울 정도로 성공적인 추정치를 낼 수 있을 것이다.
- 추정을 할 때에는 상대방이 무엇을 묻고 있는지 먼저 이해하라.
- 추정하기 전에 미리 어떤 조건이 있을지 생각하라.
- 요청을 이해한 뒤에는 간단히 기본적이고 개략적인 모델을 만들어 보라.
- 다 만든 모델을 컴포넌트로 분해하고 각 컴포넌트들의 상호 작용을 수식으로 기술하라.
- 수식의 매개변수를 찾아 값을 할당하라.
- 결과에 가장 큰 영향을 미치는 매개 변수를 찾아 이 매개 변수의 값을 최대한 정확하게 산출해내라. 이에는 나름의 근거가 있어야 한다.
- 답을 계산하라.
- 결과를 기록하고 대조하라. 틀렸으면 왜 틀렸는지 찾아라.
프로젝트 일정 추정하기
프로젝트가 복잡하면 복잡할수록 추정은 매우 어렵다. 때문에 PERT 기법을 사용해보자.
프로그램 평가 검토 기법(PERT; Program Evaluation Review Technique)은 프로젝트 관리에서 사용하는 통계적인 방법이다. PERT는 최적 추정치, 최소 추정치, 최대 추정치. 이 세 가지 추정치를 사용하여 평균적인 추정치를 계산한다. 숫자 하나로 대답해야 하는 상황이 아니라면 숫자 하나가 아니라 여러 가지 시나리오로 추정하는 것이다.
총평
이번 장은 전체적으로 밑줄을 그을 일이 많았다. 모든 페이지에서 인상이 깊은 구절이 많았고, 얻어가고 싶은 내용이 많았다. 특히 첫 토픽으로서 ETC원칙을 강조한 좋은 설계의 핵심 부분에서는 한 페이지의 절반을 밑줄 그을 정도로 모든 내용이 중요해보였으며, 페이지에 이렇게 글을 남겨두기까지 했다. "어떻게 한 문단 전체를 밑줄 쳐야 할만큼 중요할 수가...!"
DRY 원칙과 ETC 원칙이 객체 지향 원리나 유지보수 기법 등 모든 프로그래밍 원리의 근간이라는 사실을 알았고 사뭇 그렇기도 하다는 생각이 들었다. 그것이 이 책이 그렇게도 '쉽게 바꿔라'라는 메시지를 던지던 이유였음에 공감할 수 있었다. 앞으로 코드를 작성할 때 결합도를 최대한 낮추고 모듈이 자체적인 권한과 책임을 가질 수 있도록 해야겠다고 생각했다.
한편으로는 객체 지향에서 지향하고자 하는 SOLID 원칙(책에서 등장하지는 않았지만)에 대해 생각해보았는데, 이 역시 결국 다양하게 쪼개고 책임을 분산하고 조합한 구조로서 유연하게 확장하고 수정할 수 있는 코드를 작성하려는 것이 아닐까 생각해보며 원리에 대해 다시금 생각해보게 되었다.
그리고 역시나 비판적 사고에 대한 중요성을 재강조했다. 서문부터 시작해서 매 장마다 내 가슴에 새겨지는 비판적 시각... 또 잘 해내보자는 다짐을 하게 된다.
실천 계획
- 중복된 코드를 최대한 지양하고 단일 책임 원칙을 지키도록 노력하자.
- 바꾸기 쉬운 코드를 위해 모듈화와 캡슐화를 통해 책임과 권한을 적절히 분리하자.
- 단순 값이든, 계산 값이든 외부에서는 모듈의 접근자를 통해 모듈 내부의 값에 접근할 수 있도록 해보자.
- 항상 내가 만든 코드가 바꾸기 쉬운지 비판적인 시선으로 검토하고, 개선하자.
- 또 비판적으로 남의 이야기에 곧이곧대로 순응하지 말고 항상 의문을 가지고 생각해보자.
- 되돌려질 수 있다는 가정으로 유연한 코드를 작성하기 위해 노력하자. 역시나 ETC