![[인프런 워밍업 클럽 3기 BE 클린코드 & 테스트 스터디 ] 발자국 2주차](https://cdn.inflearn.com/public/files/blogs/540b7857-3180-47c4-a684-23e21d35a099/워밍업 클럽 백엔드 클린코드&테스트코드 썸네일.jpeg)
[인프런 워밍업 클럽 3기 BE 클린코드 & 테스트 스터디 ] 발자국 2주차
[2주차]
[섹션 6]
주석의 양면성
후대에 전해야 할 "의사 결정 히스토리"를 코드로 표현할 수 없을 때, 주석으로 상세하게 설명한다.
주석을 작성할 때, 자주 변하는 정보는 최대한 지양해서 작성한다.
관련 정책이 변하거나, 코드가 번경되었다면 주석도 잊지 않고 업데이트
주석이 없는 코드보다, 부정확한 주석이 달린 코드가 치명적이다.
좋은 주석
우리가 가진 모든 표현 방법을 동원해 코드에 의도를 녹여내고, 그럼에도 불구하고 전달해야 할 정보가 남았을 때 사용하는 주석
변수와 메서드의 나열 순서
변수는 사용하는 순서대로 나열한다.
메서드의 나열 순서는 개인 취향
객체는 협력을 위한 존재, 외부 세계에 내가 어떤 기능을 제공할 수 있는지 드러냄
공개 메서드를 상단에 배치
공개 메서드끼리도 기준을 가지고 배치하는 것이 좋다
중요도 순, 종류별로 그룹화하여 배치하면 중복된 로직을 만드는 것을 피할 수 있다.
상태 변경 >> 판별 >= 조회 메서드
패키지 나누기
패키지는 문맥으로써의 정보를 제공할 수 있다.
Level 패키지 안의 Beginner, Middle 등에 Level을 붙이지 않아도 되는 이유는 문맥상 레벨 단위라고 생각할 수 있기 때문
패키지를 쪼개지 않으면 관리가 어려워진다.
패키지를 너무 잘게 쪼개면 그것대로 관리가 어려워진다.
대규모 패키지 변경은 팀원과의 합의를 이룬 시점에 하자.
다같이 사용하는 패키지를 변경하면, 충돌이 발생할 수 있다.
처음부터 잘 고민해서 패키지를 나누자!
기능 유지보수하기 (1) - 버그 잡기
기능을 개발하다 보면 리팩토링 과정에서 달라진 부분에 따라 수정해야 하는 경우가 생긴다.
리팩토링을 진행하며 판별 조건이 세분화될 경우 세분화된 경우에 따라 수정해야 한다.
기능 유지보수하기 (2) - 알고리즘 교체하기
사용하는 알고리즘에 따라 시간 복잡도를 감소시킬 수도 있고, 메모리 사용을 감소시킬 수도 있다.
재귀 대신 스택을 사용할 수도 있고, 그리디 방법에서 다이나믹 프로그래밍을 사용하여 감소시킬 수도 있다.
IDE의 도움 받기
코드 포맷 정렬 Ctrl + Alt + L
코드 품질에 도움을 주는 플러그인
포맷 규칙을 설정할 수 있는 파일
[섹션 7]
스터디 카페 코드 리팩토링 연습
중점으로 리팩토링한 것
SRP (단일 책임 원칙)
OCP (개방 폐쇄 원칙)
LSP (리스코프 치환 원칙)
추상화 레벨 맞추기
getter 사용 지양
판별 메서드 사용
중복 제거, 인터페이스 활용
내가 놓친 것
DIP (의존성 역전 원칙)
핸들러 통합
의미있는 내용 상수화
일급 컬렉션 활용
[섹션 8]
능동적 읽기
복잡하거나, 엉망인 코드를 읽고 이해하려 할 때, 리팩토링하면서 읽기
리팩토링 후, 돌아갈 수 있는 git reset --hard가 있다.
핵심 목표는 도메인 지식을 늘리고, 이전 작성자의 의도를 파악하는 것
오버 엔지니어링
필요한 적정 수준보다 더 높은 수준의 엔지니어링
ex) 구현체가 하나인 인터페이스
구현체가 하나라면 굳이 인터페이스로 만들 필요가 없다. 근시일 내로 추가된다면 좋다.
ex) 너무 이른 추상화
추상화로 인해 정보가 숨겨지기 떄문에 복잡도는 증가, 이해도는 감소
후대 개발자들이 선대의 의도를 파악하기 힘들다.
은탄환은 없다
은탄환은 없다 : 만능 해결사는 없다.
클린코드가 무조건 좋은가?
유지보수성은 좋지만, 변경성이 없는 코드라면 동작면에서 달라지는 게 없다.
실무 : 2가지 사이의 줄다리기
지속 가능한 소프트웨어의 품질 VS 기술 부채를 안고 가는 빠른 결과물
모든 기술과 방법론은 적정 기술의 범위 내에서 사용되어야 한다.
ex) 급한 배포인데, style 관련 리뷰를 주고, 고치도록 하는 사람..?
도구라는 것은, 일단 그것을 한계까지 사용할 줄 아는 사람이 그것을 사용하지 말아야 할 때도 아는 법이다.
[섹션 9]
강의 마무리
추상 (抽象)
전문가는 언제나 탑다운으로 깔끔하게 생각할 것이다.
추상 -> 구체로 생각하자
테스트 강의
[섹션 1]
어떻게 학습하면 좋을까?
선택과 집중
모든 것을 잘할 수는 없다.
[섹션 2]
테스트는 왜 필요할까?
기능 개발 중 이전 개발 영역과 겹치는 부분이 생긴다. (중복되는 부분)
기존 코드를 건드리게 된다면 여전히 정상 작동하는지 검증이 필요하다.
사람이 검증을 한다면?
커버할 수 없는 영역 발생
경험과 감에 의존
늦은 피드백
유지보수 어려움
소프트웨어 신뢰 저하
테스트를 통해서 얻을 수 있는 것
빠른 피드백
자동화
안정
테스트 코드를 작성하지 않는다면?
변화가 생기는 매순간마다 발생할 수 있는 모든 Case를 고려
변화가 생기는 매순간마다 모든 팀원이 동일한 고민
빠르게 변화하는 소프트웨어의 안정성을 보장할 수 없다.
테스트 코드가 병목이 된다면?
프로덕션 코드의 안정성을 제공하기 힘들다.
테스트 코드 자체가 유지보수하기 어려운, 새로운 짐이 된다.
잘못된 검증이 이루어질 가능성이 생긴다.
[섹션 3]
수동 테스트 vs 자동화된 테스트
수동 테스트 : 콘솔에 출력하며, 사람이 직접 확인한다.
단점
사람이 검증해야 한다.
다른 사람이 봤을 때, 어떤 것을 검증해야 하는지 알기 어렵다.
자동 테스트 : 자동화 테스트 도구로 검증을 자동으로 한다.
장점
사람이 직접 검증하지 않는다.
테스트 환경과 검증 목표를 뚜렷히 알 수 있다.
JUnit5로 테스트하기
단위 테스트 : 작은 코드 단위(클래스 or 메서드)를 독립적으로 검증하는 테스트
검증 속도가 빠르고, 안정적이다.
테스트 케이스 세분화하기
해피 케이스,
예외 케이스 -> 경계값 테스트(범위, 구간, 날짜 등)
정상 작동만 테스트하는 것이 아니라, 예외 상황도 검증을 해야 한다!
테스트하기 어려운 영역을 분리하기
현재 시간, 날짜 , 랜덤 값 등 고정적인 것이 아닌 유동적인 요소를 분리하자
테스트하기 어려운 영역을 외부로 분리할수록 테스트 가능한 코드는 많아진다.
테스트하기 어려운 영역?
관측할 때마다 다른 값에 의존하는 코드
현재 날짜/ 시간, 랜덤 값, 전역 변수/함수, 사용자 입력 등
외부 세계에 영향을주는 코드
표준 출력, 메시지 발송, 데이터베이스에 기록
순수 함수
같은 입력에는 항상 같은 결과
외부 세상과 단절된 형태
테스트하기 쉬운 코드
[섹션 4]
TDD : Test Driven Development
프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현 과정을 주도하도록 하는 방법
레드 - 그린 - 리팩토링
레드 : 실패하는 테스트 작성 (구현부 없이 테스트 작성)
그린 : 테스트 통과를 위한 최소한의 코딩 (최소한의 구현)
리팩토링 : 구현 코드 개선 및 테스트 통과 유지
선 기능 구현, 후 테스트 작성
테스트 자체의 누락 가능성
특정 테스트 케이스만 검증할 가능성 -> 해피 케이스
잘못된 구현을 다소 늦게 발견할 가능성
선 테스트 작성, 후 기능 구현
복잡도가 낮은 테스트 가능한 코드로 구현할 수 있게 한다.
쉽게 발견하기 어려운 엣지 케이스를 놓치지 않게 해준다.
구현에 대한 빠른 피드백을 받을 수 있다.
과감한 리팩토링이 가능해진다.
TDD : 관점의 변화
테스트는 구현부 검증을 위한 보조 수단 -> 테스트와 사옿 작용하며 발전하는 구현
클라이언트 관점에서의 피드백을 주는 Test Driven(테스트 주도)
[섹션 5]
테스트는 []다
테스트는 문서다.
프로덕션 기능을 설명하는 테스트 코드 문서
다양한 테스트 케이스를 통해 프로덕션 코드를 이해하는 시각과 관점을 보완
어느 한 사람이 과거에 경험했던 고민의 결과물을 팀 차원으로 승격시켜서, 모두의 자산으로 공유할 수 있다.
DisplayName을 섬세하게
테스트 코드는 팀 전체가 보는 것
모두가 쉽고, 명확하게 알아볼 수 있게끔 적어야 한다.
테스트 목적과 환경, 검증 요소를 명확하게
테스트 행위에 대한 결과까지 기술하기
도메인 용어를 사용하여 한층 추상화된 내용을 담기
메서드 자체의 관점보다 도메인 정책 관점으로
테스트의 현상을 중점으로 기술하지 말 것
특정 시간 이전에 주문을 생성하면 실패한다 -> 영업 시작 시간 이전에는 주문을 생성할 수 없다.
명사의 나열보다 문장으로 작성
A이면 B이다.
A이면 B가 아니고, C다.
BDD 스타일로 작성하기
BDD, Behavior Driven Development
TDD에서 파생된 개발 방법
함수 단위의 테스트에 집중하기보다, 시나리오에 기반한 테스트케이스(TC) 자체에 집중하여 테스트한다.
개발자가 아닌 사람이 봐도 이해할 수 있을 정도의 추상화 수준(레벨)을 권장
Given / When / Then
Given : 시나리오 진행에 필요한 모든 준비 과정 (객체, 값, 상태 등)
When : 시나리오 행동 진행
Then : 시나리오 진행에 대한 결과 명시, 검증
어떤 환경에서(Given) 어떤 행동을 진행했을 때(When) 어떤 상태 변화가 일어난다(Then)
DisplayName에 명확하게 작성할 수 있다.
[Day7 미션]
https://github.com/taeyeongKims/readable-code/tree/day7
[미션 회고]
실제로 배웠던 것을 제대로 적용하지 못해서 아쉽다.
추상에만 신경을 쓰느라, 일급 컬렉션, 상수화 등의 디테일을 신경쓰지 못했다.
또한, 단일 책임 원칙에서도 시간권 패스에 라커 패스가 함께 묶여 있는 게 맞는 걸까?라는 생각도 들었다.
리스코프 치환 원칙을 생각하느라 공통 인터페이스를 만들었지만 치환성에 중점을 둔 나머지, 다른 원칙을 어긋낸 건 아닐까라는 생각도 든다.
또한, 의존성 역전 원칙을 어떻게 적용할지는 감도 안 잡혔었다.
하지만, 섹션 7의 리팩토링 강의 영상으로 보니, 이런 식으로 연결짓는구나 라고 조금은 감이 잡히게 되었다.
리팩토링에는 정답이 없다고는 하지만, 반복 연습하다보면 정답에 가까워지지 않을까,,? 라는 생각이 든다.
앞으로도 계속 클린코드에 대해 생각해보며 코드를 작성해야 겠다.
[2주차 회고]
리팩토링 강의가 끝나고, 테스트 강의로 넘어가는 주차였다.
리팩토링 미션을 진행하며 아쉬움이 많은 주차였으며
강의 1개를 완주하였다는 뿌듯함도 남은 주차였으며
테스트 강의를 시작하는 기대감이 생긴 주차였다.
지금까지 많은 강의를 보았지만, 깊게 생각해본 강의는 이번이 처음이었던 거 같다.
앞으로 많은 코드를 만들고, 보겠지만 이번 주차 강의가 많이 생각날 듯하다.
댓글을 작성해보세요.