Skip to content

Latest commit

 

History

History
161 lines (159 loc) · 11.1 KB

개발 메모.md

File metadata and controls

161 lines (159 loc) · 11.1 KB

메모

개발 원칙

  • 묻지 말고 시켜라 (tell don`t Ask)
  • 메서드 인자로 넘어온 값을 변경하지 마라
  • 커맨드와 쿼리를 분리하라
  • PR 단위는 하루를 넘어가지 않도록 한다.
  • One Goal One Method (하나의 메서드는 하나의 관심사만 가져야 한다)

PR 생성 전 작성자 체크리스트(권장o 강제x 언제나 예외가 있을 수 있음.)

  • import가 제대로 되어 있는가
  • How가 아닌 What이 드러나는가
  • 물어보지 않고 시키는가(tell don’t ask)
  • 캡슐화가 깨지지 않았는가
  • CQS가 지켜지는가
  • 추상화 수준이 적절한가
  • 주석이 적절하게 작성되어 있는가
  • 변경의 범위가 너무 크지 않은가
  • 커밋은 15개를 넘기지 않는가
  • 변경된 파일의 라인이 150줄을 넘지 않는가
  • 메소드 인자로 넘어온 값이 변경되지 않는가
  • 하나의 메소드가 한가지의 관심사만을 가지고 있는가
  • 코드에 중복이 있는가

코드 리뷰 체크리스트

  • import된 패키지의 의존성에 어색한 부분이 없는지 확인.
  • 네이밍이 이상하지 않은가
  • 추상화 수준이 적절한가
  • Command와 Query가 잘 분리되어 있는가
  • 조회-액션-저장 구조로 동작하는가
  • 설계 의도 파악하기

효과가 큰 리팩터링 순위

  1. Rename - 변수나 메서드의 이름을 명확하게 변경하여 코드의 가독성을 높입니다.
  2. Comment - 중요한 부분이나 복잡한 로직에 주석을 추가하여 이해를 돕습니다.
  3. final 추가 - 변경되지 않는 변수나 메서드에 final 키워드를 추가하여 불변성을 보장합니다.
  4. Slide Statement - 관련 있는 코드를 가까이 배치하여 코드의 흐름을 개선합니다.
  5. Reorder - 메서드나 클래스를 논리적인 순서로 재배치하여 가독성을 높입니다
  6. Introduce Parameter Object - 관련된 여러개의 파라미터를 하나의 객체로 묶어 코드의 복잡성을 줄입니다
  7. Extract Method - 중복되거나 긴 코드를 별도의 메서드로 분리하여 재사용성을 높입니다.
  8. Extract Delegate - 특정 기능을 별도의 클래스나 모듈로 분리하여 책임을 분산시킵니다.

훌륭한 프로그래밍의 공통적 가치는 커뮤니케이션, 단순성, 유연성이다. (켄트 벡의 구현 패턴)

  • 읽기 어려운 코드에 대해 왜 이해하기 어려운지, 이유를 설명하는것보다 코드를 바꾸는 편이 났다.
  • 커뮤니케이션이 최우선 가치. 단순성은 독자에따라 복잡해보일 수 있다. 때로는 단순성을 포기하더라도 커뮤니케이션을 선택해야한다.
  • 유연성은 비효율적인 코딩이나 설계를 정당화해주는 가치이다. 유연성이 있으면서 당장 이득을 얻을 수 있는 패턴을 사용하라. 당장 비용이 들지만 앞으로 이득을 얻을 수 있을지 확실하지 않은 경우에는 일단 자제하라. 정말 필요할떄 적용(YAGNI). 유연성은 복잡도를 증가시킨다.

애플리케이션 서비스 로직을 수행하는데 도메인 로직이 1개 이상 호출되는 것은 캡슐화가 깨져있을 가능성이 있다.

  • 가능성이지 꼭 그렇다는 건 아님. 언제나 예외는 존재.
  • 애플리케이션 서비스의 역할은 의존성 간의 오케스트레이션 담당, 도메인 로직이 애플리케이션 서비스에서 여러 번 호출된다면 캡슐화가 깨지지 않았는지 의심해봐야 한다.

새로운 기능을 구현하는데 같은 클래스에 계속 필드를 추가하는 것은

  • DB 테이블에 nullable한 컬럼을 계속 추가하는 것과 같을 수도 있음.
    • nullable한 컬럼은 코어 테이블과 곁가지 테이블로 분리해야 한다는 신호일지도.

TDD 사이클에서 정말 중요한 것은 Test List를 작성하는 것이다.

  • Test List(Todo List)를 만들어 놓고 TDD 사이클을 진행해야 의도한대로 개발할 수 있다.
  • 그렇지 않으면 되는 대로 개발할 가능성이 높아진다.
  • fail fast와도 결이 같다. -> 코드를 작성하지 않아도 Test List를 작성하면서 러프하게 분석이 진행될 수 있음

단위 테스트는 출력 기반 - 상태 기반 - 통신 기반 순으로 좋다.(블라디미르 코리코프 단위테스트)

  • 출력 기반 테스트를 하기 위해서는 상태를 변경하지 않고 값을 반환하는 방식으로 함수형 스타일로 코드를 작성해야 한다.
  • 비즈니스 로직을 처리하는 코드와 부작용을 일으키는 코드를 분리하는 것(Functional Core)이 함수형 프로그래밍의 목표다.
  • 어떻게? 부작용을 비즈니스 연산 끝으로 몰아 비즈니스 로직을 부작용과 분리한다(빵 - 속 - 빵)
  • 다만 은총알은 없기에 함수형 방식의 순수성에 많은 비용이 든다면 따르지 말라.
  • 항상 출력 기반 테스트에만 의존할 수는 없는 법.
  • 목표는 모든 테스트를 출력 기반으로 만드는 것이 아닌 가능한 많은 테스트를 전환하는 것이다.

프로그래밍 패턴

  • 절차적 프로그래밍 -> cohesion(응집도) 확인 후 슬라이드 스테이트먼트(Slide Statement) -> 리오더(Reorder, 읽기 좋은 순으로) -> Extract Method

분석 → 가설 → 예측 → 테스트


레거시 쿼리를 안전하게 애플리케이션 로직으로 전환하는 방법

  • 레거시 쿼리 중 일부 컬럼을 애플리케이션 로직으로 전활할 때는 해당 쿼리를 크게 변경하거나 지우는 것보다 -9와 같은 상수값을 반환하도록 대체한 뒤 애플리케이션에서 계산한 값으로 덮어씌운다.

컴포넌트에서 사용되는 상수형 필드나 정수형 변수는 DB 테이블으로 관리하는게 운영하는 데 효과적일 수 있다.

  • ex) 운영: 기준을 4000에서 4100으로 변경 배포 부탁드립니다.
    • 이런 경우 DB에서 관리할 경우 매번 배포하지 않아도 됨.

환경별로 변경되지 않는 상수가 properties에 정의되어있기 보다는 코드에 있는게 더 나을 때도 있을 수 있다.


메소드에서 파라미터가 옵셔널로 사용된다면 (조건에 따라 일부만 사용된다면) 응집도가 절반인 셈일 수 있다.

  • 컴포넌트의 퍼블릭 메소드가 옵셔널이라면 클래스를 분리해야 할 징조일까? 책임이 너무 많은가?
  • 클래스의 퍼블릭메서드 a에서 a 필드만 쓰이고 b 메서드에서 b만 쓰인다면 클래스를 분리해야할 징조?

변수명 앞에 반복되는 단어가 있다면 클래스로 묶어야 할 징조일 수 있다.

before
Order {
  orderCustomerName
  orderCustomerEmail
  orderCustomerPhone
}

after
Order {
  orderCustomer
}

OrderCustomer {
  name
  email
  phone
}

abstract method가 5~6개씩 되는 추상 클래스 혹은 인터페이스는 그냥 각각의 단일 클래스가 나을 수도 있을 것 같다.

  • 책임이 너무 크거나 혹은 역할 분담이 제대로 안 되어 있을 수도 있지 않을까 의심을?
  • 마찬가지로 퍼블릭 메서드 하나에 private 메소드가 5개가 넘어가면 ..?

테이블에 status, boolean 플래그 컬럼이 있다면, status와 boolean별로 usecase(경우의 수)가 있을 수 있음.


도메인 모델이 가져야 하는 필드는 되도록 boolean 타입보다는 enum을 사용한다.

  • 지금 요구사항은 0과 1만 있을수 있지만 2,3이 언제든 추가될 수 있다. 하지만 boolean으로 고정해놓으면 대응하기 어렵다.

DB 테이블에 도메인 모델의 enum 값을 그대로 저장하지 말라.

  • DB에 enum이 그대로 입력되어있으면 DB와 도메인 모델의 결합도가 높아진다.
  • 더 좋은 이름이 생각나서 enum을 리팩터링하고 싶어도 DB에 결합되어 있어서 리팩터링이 어려워진다.

코드 작성 전 전략에 대해 구성원들에게 사전 공유를 하고, 동의와 이해를 구한 뒤 개발하면, 코드를 두 번 작성하는 상황을 줄일 수 있다.


원하는 기술을 쉽게 도입하는 방법

  • 1, 2, 3안에 대해서 제안하고 트레이드오프를 고려해서 적용하면 당장 도입을 못하더라도 도입하기 쉬운 구조로 만들 수 있다. 때가 되면 바로 도입할 수 있다.

무엇을 도입하기 전 생각해봐야할 문제

  • 무엇을 하기 전에 사용량과 효용을 생각해보자
  • ex) 유료 서비스로 욕설 필터링을 추가함.
    • 그전에 해야 할 것은 현재 욕설이 얼마나 쓰이고 있는지를 파악.
    • 욕설이 쓰이지 않는데 욕설필터링을 돈주고 사용해야 하는 것은 맞지 않음.
    • 빈도를 체크하기 전에 로깅이 선행되어야 함.(비중을 알기 위해)
    • 기대 효과가 있어야 설득력이 있음. 무언가 하기 전에 빈도를 체크하는건 중요하다.

새로운 시도나 기술을 사용하고 싶을때는 사례를 먼저 수집하고 효용을 확인한 뒤 엣지 케이스를 고려해야한다.


주니어는 한 가지 방법으로 어떻게든 해결하려고 한다.(온몸 비틀기)

  • 예시) 백엔드에서만 어떻게든 해결하려고 함.
  • 깊게 파고들어서 원인을 파악하고 매우 어려운 방법으로 문제를 해결해냄 (스스로 우물에 들어간다)
  • 우물의 물을 마시기 위해 어떻게 내려가야 할지, 내려가서 어떻게 해야 할지, 어떻게 올라와야 할지 등등.
  • 시니어는 다른 방법을 찾아서 더 쉽게 해결한다. 시야가 넓다.
    • 예시) 프론트에서 더 쉽게 해결하거나 인프라 수준에서 더 쉽게 해결할 수 있는지 혹은 운영으로 풀 수 있는지 다각도에서 검토.
    • 우물에 물이 있는지, 마실 수 있는지를 확인. 직접 내려가지 않고 도구를 이용.

추상화는 발견하는 것이지 발명하는 것이 아니다.


타입이 있다는 건 추상화의 신호일 수 있다.

  • 신호일 수는 있지만 꼭 하는것이 좋은것만은 아닐수도 있다.

껍데기 데이터가 존재하면 한편으로는 데이터 구조의 유연성이 떨어질 수 있다.


시스템이 망가져도 일은 계속되어야 한다(비상 탈출구를 마련해 두기)


문제가 발생하지 않도록 준비하는 것도 중요하지만, 문제 발생 후 빠르게 후속 대응을 하고 원인 분석을 하는 것도 중요. 롤백 전략이 반드시 필요하다.


큰 문제 한번에 풀면 맥락은 알 수 있지만 너무 많은 정보를 알아야 해서 읽기 어려움. 큰 문제를 작게 여러 개로 쪼개서 읽기 쉽게 만들어야 한다.

  • 작게 여러 개로 쪼갠 문제를 맥락을 이해할 수 있게 만들어야 한다.
  • 작아도 맥락을 충분히 이해할 수 있도록 하기 위해서는 Outside-In이 좋을지도.

할 수 있는 방법이 바로 떠올랐을 때, 한 걸음 물러서서 더 간단한 방법이 없는지 생각해 보기


새로운 기술을 도입할 때 5년간 내가 관리해야한다는 생각으로 고민해보기?