Book/실용주의 프로그래머

[실용주의 프로그래머] 2장. 실용주의 접근법

데브드그 2022. 3. 20. 17:31

오늘 TIL 3줄 요약

  • 수정하기 쉬운 코드를 작성하라.
  • 중복 코드 작성을 삼가하라. 단, 이때의 중복 코드란 지식 및 의도의 중복을 말하는 것. 하나의 요구사항이 변경되어 코드의 수정이 필요할 때 한 번의 수정으로 해결할 수 있도록 하라. (주석, 문서 등 포함)
  • 예광탄 개발 방법, 프로토타입 등을 이용하면 사용자에게 가시적으로 개발 과정을 보여줄 수 있을 뿐만 아니라 예상되는 위험 요소를 미리 파악할 수 있다.

책에서 기억하고 싶은 내용을 써보세요.

2장 실용주의 접근법(p.37 - p.102)

▶ Topic 8. 좋은 설계의 핵심

어떤 게 잘 설계되었다는 건 그 물건이 사용하는 사람에게 적응하여 맞춰진다는 것이다.
잘 설계된 코드는 바뀜으로써 사용하는 사람에게 맞춰져야 한다.
바꾸기 더 쉽게 Easier to Change. ETC. 이게 전부다.

▷ ETC는 규칙이 아니라 가치

  • 가치는 여러분이 결정을 내리게 도움을 주는 것이다.
  • ETC의 전제는 여러 길 중 어떤 길이 미래의 변경을 쉽게 만드는지 알 수 있다는 것. 실마리가 없을 때는,
    • 여러분이 작성하는  코드를 교체하기 쉽게 만들도록 노력하는 것.  (결합도↓ 응집도↑)
    • 엔제니어링 일지에 현재 상황과 여러분의 선택, 그리고 변경 사항에 대한 추측을 정리. 소스 코드에 이에 대한 표시를 남기기. (직관 발전의 기회)

▶ Topic 9. DRY: 중복의 해악

  • 지식은 변화한다. 프로그래머는 늘 유지 보수 모드에 있다. 유지보수는 별개의 활동이 아니며 전체 개발 과정의 일상적인 부분이다.
  • 소프트웨어를 신뢰성 높게 개발하는 유일한 길, 개발을 이해하고 유지 보수하기 쉽게 만드는 유일한 길은 우리가 DRY라 부르는 원칙을 따르는 것.
  • 모든 지식은 시스템 내에서 단 한 번만, 애매하지 않고, 권위 있게 표현되어야 한다.
DRY: 반복하지 말라. Don't Repeat Yourself
  • DRY를 따르지 않으면 똑같은 것이 두 군데 이상 표현될 것이다. 하나를 바꾸면 나머지도 바꿔야 함을 기억해야 한다.

▷ DRY는 코드 밖에서도

  • DRY는 지식의 중복, 의도의 중복에 대한 것이다. 똑같은 개념을 다른 곳 두 군데에서 표현하면 안 된다는 것이다.

▷ 코드의 중복

▷ 모든 코드 중복이 지식의 중복은 아니다

  • 코드는 동일하지만 두 함수가 표현하는 지식은 다르다. 서로 다른 것을 검증하고 있지만, 우연히 규칙이 같다고 해서 코드 중복인 것은 아니다.

▷ 문서화 중복

  • 함수 이름이 함수가 하는 일을 알려준다.
    • 이 함수의 의도는 두 번 표현되었다. 한 번은 주석으로, 또 한 번은 코드로. 시간이 지남에 따라 주석과 코드의 내용이 서로 어긋나게 될 거라고 거의 확실히 장담할 수 있다.

▷ 데이터의 DRY 위반

  • 자료 구조는 지식을 표현한다.
  • 모듈이 자료 구조를 노출하면 언제나 모듈의 구현과 그 자료 구조를 사용하는 코드 사이에 결합이 생긴다.
    • 가능하다면 언제나 객체의 속성을 읽고 쓸 때 접근자 accessor 함수를 사용하라. (단일 접근 원칙)

▷ 표현상의 중복

 

  • 코드와 API(다른 라이브러리), 코드와 원격 호출 및 외부 저장소의 데이터 등(다른 서비스)으로의 연결 → DRY 위반 발생
  • 연결을 표현하는 지식을 여러분의 코드와 외부의 존재 양쪽이 모두 알아야 하기 때문에 중복 발생
  • 내부 API에서 생기는 중복
    • 언어나 기술에 중립적인 형식으로 내부 API 정의할 수 있는 도구 찾아보기 ~ 모든 API 정의를 중앙 저장소에 넣어 두고 여러 팀이 공유할 수 있게하면 좋다.
  • 외부 API에서 생기는 중복
    • API 명세를 여러분의 API 도구로 불러와서 사용
  • 데이터 저장소와의 중복
    • 데이터 스키마 분석 기능, 영속성 프레임워크(ex. MyBatis) 사용
    • 코드에서 외부 데이터를 키-값 데이터 구조에 밀어 넣기 → 안전성을 위해 데이터를 한 겹 더 감쌀 것을 권장

▷ 개발자 간의 중복

  • 개발자 간에 적극적이고 빈번한 소통으로 해결
    • 일일 스크럼 스탠드업 미팅 운영 → 슬랙slack 채널과 같은 공통의 문제를 다루기 위한 공간 생성
    • 프로젝트 사서 임명 → 소스 트리의 한가운데에 유틸리티 루틴과 스크립트를 모아둘 수 있는 장소를 마련
재사용하기 쉽게 만들어라.

▶ Topic 10. 직교성

관련 없는 것들 간에 서로 영향이 없도록 하라.

▷ 직교성의 장점

  • 우리가 설계하고 싶은 것은 단일하고 잘 정의된 목적을 가진 독립적인 컴포넌트다. → 자족적, 응집
  • 생산성 향상
    • 변화를 국소화해서 개발 시간과 테스트 시간이 줄어든다. 새로운 코드를 추가할 때 마다 기존의 코드 수정 불필요
    • 컴포넌트의 재사용 촉진
    • 직교적인 컴포넌트들을 결합함으로써 단위 노력당 더 많은 기능을 얻을 수 있다.
  • 리스크 감소

▷ 설계

  • 직교적: 모듈식, 컴포넌트 기반, 계층layer
  • 시스템은 서로 협력하는 모듈(독립적인 기능)의 집합으로 구성되어야 한다. 
  • 계층 구조는 직교적 시스템을 설계하는 강력한 방법이다.
  • 각 계층은 자기 바로 밑에 있는 계층이 제공하는 추상화만을 사용하기 때문에, 다른 코드에 영향을 끼치지 않으면서 기반 구현들을 변경할 수 있게 되어 유연성이 높아진다.
  • 설계가 직교적인지 확인하는 방법: 컴포넌트를 나눈 후, 특정 기능에 대한 요구 사항을 대폭 변경하는 경우 몇 개의 모듈이 영향을 받는가?
    • 직교적인 시스템의 경우 '하나'여야 한다.
  • 자신의 힘으로 제어할 수 없는 속성에 의존하지 말라.

▷ 툴킷과 라이브러리

  • 기술을 현명하게 선택하라
    • 외부에서 만든 툴킷이나 라이브러리를 도입할 때 시스템의 직교성을 해치지 않는지 주의 깊게 살펴볼 것.
  • 엔터프라이즈 자바빈즈 EJB 시스템 → 실제 작업을 하는 바깥쪽에 annotation을 이용하여 선언적으로 표현. 내부를 바꾸지 않으면서 기능을 추가하는 장식자 패턴decorator pattern 의 예이기도 함.

▷ 코딩

▣ 직교성 유지하기 위한 기법
코드의 결합도를 줄여라
- '부끄럽쟁이' 코드 작성: 불필요한 것은 다른 모듈에 보여 주지 않으며, 다른 모듈의 구현에 의존하지 않는 코드를 작성
- 데메테르 법칙

전역 데이터를 피하라
- 싱글턴(단일체 패턴)은 불필요한 결합을 만들 수 있다.
- 코드가 전역 데이터를 참조할 때 마다 코드는 해당 데이터를 공유하는 다른 컴포넌트와 묶이게 된다.

유사한 함수를 피하라
- 전략 패턴strategy pattern을 사용하여 더 낫게 구현할 수 없는지 고민

리팩터링

- 자신이 작성하는 코드를 항상 비판적으로 바라보는 습관을 길러라

▷ 테스트

  • 모듈 수준의 테스트나 단위 테스트가 통합 테스트보다 테스트 케이스를 만들고 수행하기 훨씬 쉽다.
  • 단위 테스트 및 버그 수정을 통해 직교성을 테스트 하라.

▷ 문서화

  • 문서에도 직교성을 적용하라: 내용과 표현이라는 두 개의 축
DRY + 직교성
: 시스템 내부의 중복을 최소화하고, 시스템 컴포넌트 간의 상호 의존도를 줄인다.
  시스템이 더 유연하고 이해하기 쉬워질 것이다. 디버깅, 테스트, 유지 보수 또한 쉬워질 것이다.

 

▶ Topic 11. 가역성

  • DRY 원칙, 결합도 줄이기, 외부 설정 사용하기 방법론을 잘 따르면 중요하면서도 되돌릴 수 없는 결정의 수를 가능한 한 줄일 수 있다.
    • 프로젝트 초기에 늘 최선의 결정을 내리지는 못하기 때문에 되돌릴 수 없는 결정은 줄여야 한다.
    • 우리가 소프트웨어를 개발하는 속도는 요구 사항, 사용자, 하드웨어의 변화를 앞지를 수 없다.
  • DB(혹은 이외의 기술) 개념을 올바르게 추상화하여 영속성을 하나의 서비스로 제공하도록 만들었다면 달리는 도중에 말을 갈아탈 수 있는 유연성이 생길 것이다.
최종 결정이란 없다.

 

▶ Topic 12. 예광탄

  • 시스템을 정의하는 중요한 요구 사항을 찾고 개발 우선순위를 정하라.
목표물을 찾기 위해 예광탄을 써라.
  • 예광탄 개발: 기본적인 뼈대 구조를 통해 큰 틀에서 전체 기능을 표현한 코드를 우선 개발한 후, 지속적으로 테스트를 반복함으로써 전체 프로젝트를 완성해나가는 점진적인 접근 방법.
    • 사용자가 작동하는 시스템을 빨리 볼 수 있다.
    • 개발자가 일할 수 있는 구조를 얻는다.
    • 통합integration 작업을 수행할 기반이 생긴다. → 더 빠르고 정확하게 디버깅하고 테스트할 수 있다.
    • 진행 상황에 대해 더 정확하게 확인할 수 있다.
  • 예광탄이 언제나 목표물을 맞히는 것은 아니다. 지금 있는 것을 목표물에 더 가까워지도록 바꾸면 된다.
    • 가벼운 코드일수록 빠르고 쉽게 수정이 가능하다.
  • 프로토타입은 나중에 버리는 코드를 만든다. (얻은 교훈을 바탕으로 코드를 새로 작성). 예광탄 코드는 기능은 별로 없지만 완결된 코드이며, 최종 시스템 골격 중 일부가 된다.
  • 프로토타입은 예광탄을 발사하기 전에 먼저 수행하는 정찰이나 정보 수집과 같은 것이다.

 

▶ Topic 13. 프로토타입과 포스트잇

  • 소프트웨어 프로토타입: 위험 요소를 분석하고 노출시킨 후, 이를 매우 저렴한 비용으로 바로잡을 기회를 얻는 것.
  • 프로토타입을 반드시 코드로 작성할 필요는 없다.
    • 포스트잇은 작업 흐름이나 애플리케이션 로직과 같이 동적인 것을 프로토타이핑할 수 있는 훌륭한 도구다.
  • 프로토타입은 제한된 몇 가지 질문에 답하기 위한 것이므로 실제 제품보다 훨씬 적은 비용으로 빠르게 개발할 수 있다.
  • 프로토타이핑은 학습 경험이다. 그 가치는 생산한 코드에 있는 것이 아니라 이를 통해 배우는 교훈에 있다.
    • 정확성, 완전성, 안정성, 스타일은 무시하고 만들면 된다.
프로토타이핑으로 학습하라.

 

▶ Topic 14. 도메인 언어

문제 도메인에 가깝게 프로그래밍하라.
  • 실용주의 프로그래머라면 어떤 경우에는 한 차원 더 나아가서 그 도메인의 실제 어휘와 문법, 의미론 - 즉, 그 도메인의 언어를- 사용해서 프로그래밍할 수도 있다.
  • 내부 도메인 언어는 궁극적으로는 어떤 형태로 만들더라도 호스트 언어의 문법을 벗어날 수 없다. 
  • 가능하다면 YAML, JSON, CSV처럼 널리 통용되는 외부 언어를 사용하라. 단, 외부 언어의 도입은 애플리케이션으 ㅣ사용자가 직접 도메인 언어로 코드를 작성하는 경우에만 추천한다.

 

▶ Topic 15. 추정

추정으로 놀람을 피하라
  • 추정하는 법을 배우고 추정 능력을 계발하여 무언가의 규모를 직관적으로 짚을 정도가 되면, 추정 대상의 가능성을 가늠하는 마법과 같은 능력을 발휘할 수 있게 될 것이다.
  • 누군가 추정치를 물었을 때 스스로 물어보아야 할 첫 번째 질문은 여러분의 답변이 사용될 상황이 무엇인지다.
  • 모든 추정치는 문제의 모델에 기반한다.
    • 추정하기 전에 미리 어떤 조건이 있을지 생각하는 습관을 길러야 한다.
    • 간단하게 기본적인 것만 갖춘 개략적인 모델을 만들어 보라.
    • 다 만든 모델을 컴포넌트로 분해한 후, 이러한 컴포넌트 들이 어떻게 상호 작용하는지를 수식으로 기술해야한다.
    • 각 컴포넌트가 어떻게 전체 모델에 기여하는지를 나타내는 매개변수를 찾고, 해당 매개변수에 값을 할당하라.
코드와 함께 일정도 반복하며 조정하라.

오늘 읽은 소감은? 떠오르는 생각을 가볍게 적어보세요.

용어와 내용들이 점점 어려워지는 것을 느낀다. 책을 요약 정리하듯 정리를 하고 있지만 경험과 지식이 부족한 나에게는 지금의 방법이 최선이라는 생각이 든다.

처음 개발을 배우면서 학원 이론 시간에 모듈 간의 결합도는 낮추고 응집도를 높이는 프로그래밍을 해야한다라는 말을 처음에는 이해를 잘 못했는데 2장을 읽으면서 드디어 제대로 이해가 되었다. 하지만 이를 실천하는 것은 굉장히 어려운 일일 것이다. 의식적으로 코드를 작성할 때마다 이 컴포넌트가 수정이 되었을 때 영향을 받는 다른 컴포넌트가 있는지 있다면 얼마나 되는지 생각하면서 내가 작성한 코드를 비판적으로 검토하는 과정이 필요할 것이다.

 


궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요.

  • 단일접근원칙(Uniform Access principal): 모듈을 통해 제공되는 모든 서비스는 일관된 표기법notation으로 사용할 수 있어야 한다. 저장한 값으로 구현되었건, 계산을 통해 구현되었건 상관없이. (파이썬, c#, Kotlin 같은 언어에서는 프로퍼티(property)라는 기능을 사용하면 해당 클래스의 클라이언트는 필드처럼 사용하지만, 사실은 메서드로 작동하도록 만들 수 있다.)
  • 목 mock API
  • 이후에 읽으면 좋을 도서: ≪GoF의 디자인 패턴≫
  • 가역성
  • YAML: 일반 텍스트로 데이터 구조를 표현하는 언어. '사람이 쉽게 읽을 수 있는' 데이터 직렬화 양식. 설정이나 간단한 데이터 파일 작성 등에 많이 사용. JSON에는 없는 주석이나 앵커 같은 기능이 유용.  (참고: https://www.inflearn.com/questions/16184)
  • 메타프로그래밍metaprogramming: 프로그램을 하나의 데이터로 보고 동적으로 수정하는 프로그래밍 기법

 

 

오늘 읽은 다른 사람의 TIL(URL)

https://hyuuny.tistory.com/56

https://github.com/geonya/book-the-pragmatic-programmer/blob/master/day3-ch2.md