블로그
전체 42025. 03. 29.
0
[인프런 워밍업 클럽 3기 BE 클린코드 & 테스트 스터디 ] 발자국 4주차
[4주차] 섹션7Mockito로 Stubbing하기외부 서비스를 테스트하려면 실제로 수행하거나, Mocking하여 가짜 객체를 만들어서 사용Mocking하여 Mock 객체의 응답을 정해줌으로써, 외부 서비스와의 독립성을 유지외부 서비스가 있어도 간단하게 서버 로직에 대한 검증 가능Test DoubleDummy : 아무것도 하지 않는 깡통 객체Fake : 단순한 형태로 동일한 기능은 수행하나, 프로덕션에서 쓰기에는 부족한 객체Stub : 테스트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체 그 외에는 응답하지 않는다.Spy : Stub이면서 호출된 내용을 기록하여 보여줄 수 있는 객체, 일부는 실제 객체처럼 동작시키고 일부만 Stubbing할 수 있다.Mock : 행위에 대한 기대를 명세하고, 그에 따라 동작하도록 만들어진 객체Stub -> 상태 검증, Mock -> 행위 검증@Mock, @Spy, @InjectMocksMock은 정해진 행위를 하는 객체를 만드는 것Spy는 실제 객체의 메서드를 수행하지만, 특정 메서드만 mocking한 것InjectMocks는 Mock과 Spy 객체를 자동 주입해주는 것BDDMockito행동주도개발TDD -> when().thenReturn(), BDD -> given().willReturn()Classicist VS MockistClassicist : Mock을 통한 검증은 완전함을 보장할 수 없다.Mockist : Mock을 통해서 각각 테스트를 성공했으면 된다. 섹션 8한 문단에 한 주제완벽하게 제어하기현재 날짜, 현재 시간 등 제어할 수 없는 값은 파라미터로 넘겨서 상위 계층에서 관리테스트 환경의 독립성을 보장하자테스트가 실패하는 부분은 when절 또는 then절이어야 한다. given 절에서 실패하면 안된다.given 절에서 객체를 생성할 때는 순수한 생성자 또는 builder 기반으로 만들면 좋다.테스트 간 독립성을 보장하자테스트 간 공유 자원을 사용하면 안된다.공유 자원을 사용하면 테스트 간 순서에 따라 성공, 실패가 갈린다.한 눈에 들어오는 Test Fixture 구성하기@BeforeEach를 사용하여 설정할 경우, 각 테스트 입장에서 봤을 때, 아예 몰라도 테스트 내용을 이해하는데 지장이 없어야 한다.뇌의 메모리를 적게 사용Test Fixture 클렌징deleteAll, deleteAllInBatch@ParameterizedTestenum 클래스의 각 값에 대하여 테스트를 하고 싶을 때, ParameterizedTest를 수행하면 좋다.ValueSource() 파라미터가 1개일 때NullSOurce, EmptySource, NullEmptySourceCsvSource() csv 형식으로 여러개의 파라미터 사용여러 개의 파라미터 값을 테스트하고 싶을 때 사용@DynamicTest한 문단에 한 주제, 하지만 연속된 상황을 검증하고 싶다면?연속된 상황을 부여하여, 일련의 시나리오를 테스트할 수 있다.테스트 수행도 비용이다. 환경 통합하기테스트 환경이 달라지면, 서버가 각 테스트 클래스마다 새로 부팅한다.통합 테스트 클래스를 만들어서, 통합 테스트 클래스가 실행될 때 1번 서버가 실행되도록 한다.MockBean, SpyBean 등 환경이 달라지면 통합 테스트 클래스를 상속받아도 서버가 새로 부팅된다.MockBean, SpyBean을 통합 테스트 클래스에 옮겨놓으면 1번으로 유지 가능DataJpaTest를 repository 테스트를 할 때 쓴다면 이것도 환경이 달라졌으므로, 서버를 새로 부팅WebMvcTest, SpringBootTest, DataJpaTest 각각 통합 테스트 클래스를 만들어주면 3번만 부팅private 메서드의 테스트는 어떻게 하나요?private 메서드는 테스트할 필요 X외부로 노출되지 않는 기능까지는 알 필요가 없다.단위 테스트 검증 시에 어차피 검사하게 된다.그래도 하고 싶다면, 객체 분리를 통해서 public으로 만든 후 검증테스트에서만 필요한 메서드가 생겼는데 프로덕션 코드에서는 필요 없다면?만들어도 되지만, 지양하자 [회고]벌써 마지막 주차가 되어버렸다. 1달 동안 클린코드와 테스트코드에 대해 전혀 무지했던 내가 개념을 익히고 실습을 하며어떻게 하면 더 깔끔하게, 더 읽기 편하게 적을 수 있을까를 고민하게 되었고, 어떻게 검증해야 할까, 무엇을 검증해야 할까를 고민할 수 있게 되었다.1달이라면 길다면 길고, 짧다면 짧은 시간 동안 한층 더 나아갔고, 더 우수한 사람이 되기 위해 노력했다. 한달 전의 나보다 성장했기에 뿌듯하고, 앞으로 성장할 나를 위해 다시금 노력하자워밍업 클럽을 통하여 궁금했던 질문도 하였고, 앞으로 나아갈 길과 동기를 얻을 수 있었다. 다음 기수에도 신청하고 싶다 [출처]인프런 워밍업 클럽 : https://inf.run/Y4cf2강의 : https://www.inflearn.com/course/readable-code-%EC%9D%BD%EA%B8%B0%EC%A2%8B%EC%9D%80%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1%EC%82%AC%EA%B3%A0%EB%B2%95/dashboard
test
2025. 03. 22.
0
[인프런 워밍업 클럽 3기 BE 클린코드 & 테스트 스터디 ] 발자국 3주차
3주차 [섹션 6]레이어드 아키텍처(Layered Architecture)와 테스트Presentation Layer, Business Layer, Persistence Layer로 분리관심사의 분리통합 테스트여러 모듈이 협력하는 기능을 통합적으로 검증하는 테스트일반적으로 작은 범위의 단위 테스트만으로는 기능 전체의 신뢰성을 보장할 수 없다.풍부한 단위 테스트 & 큰 기능 단위를 검증하는 통합 테스트Persistene Layer 테스트@SpringBootTestspring boot의 모든 빈들을 다 주입한다.@DataJpaTestJPA관련 빈들만 주입한다.속도가 @SpringBootTest보다 빠르다.Business Layer 테스트비즈니스 로직을 구현하는 부분Persistence Layer와의 상호작용을 통해 비즈니스 로직을 전개시킨다.트랜잭션을 보장해야 한다.@DataJpaTest는 @SpringBootTest와 다르게 @Transactional이 자동으로 걸려있다.데이터 롤백이 기본적으로 된다.@SpringBootTest에 @Tracnsactional을 걸었을 때 주의할 점서비스 클래스에서 @Transactional이 없어도 Test시에 걸어줬기 때문에 테스트가 통과될 수 있다.@AfterEach를 통해서 repository들을 초기화할 수 있다. @Transactional을사용하면 deleteAll 등 초기화 단계를 설정하지 않아도 된다. deleteAll과 deleteAllInBatch의 차이deleteAll은 내부적으로 한 건씩 개별 삭제한다. 연관 관계 테이블을 먼저 지우지 않아도, 개별 삭제할 때 같이 지운다.deleteAllInBatch는 개별 삭제가 아닌 bulk query를 사용하여 한 번에 삭제한다.단, 연관 관계 테이블을 먼저 삭제해야지, 외래키 제약 조건에 어긋나지 않는다. Presentation Layer 테스트동시성 이슈생성 함수에서는 동시성을 고려해줘야 한다.함수 호출 빈도가 낮으면, id에 unique 제약 조건을 걸고, 실패 시 재시도하는 로직 추가함수 호출 빈도가 높으면, UUID 같은 것으로 대체서비스단에 readOnly = true를 base로 사용cud 작업일 때는 @Transactioal을 메서드 위에 선언해서, readOnly가 되지 않게끔 작동CQRS - command / read를 분리read 부분은 조회 전문 repository나 로직을 구현 가능command는 복잡한 로직을 담당할 수 있다.Day 11 미션 https://github.com/taeyeongKims/readable-code/tree/main/src/test/java/cleancode/studycafe/tobe/model출처 : https://www.inflearn.com/course/practical-testing-%EC%8B%A4%EC%9A%A9%EC%A0%81%EC%9D%B8-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%80%EC%9D%B4%EB%93%9C/dashboard
cleancode
2025. 03. 11.
0
[인프런 워밍업 클럽 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 DevelopmentTDD에서 파생된 개발 방법함수 단위의 테스트에 집중하기보다, 시나리오에 기반한 테스트케이스(TC) 자체에 집중하여 테스트한다.개발자가 아닌 사람이 봐도 이해할 수 있을 정도의 추상화 수준(레벨)을 권장Given / When / ThenGiven : 시나리오 진행에 필요한 모든 준비 과정 (객체, 값, 상태 등)When : 시나리오 행동 진행Then : 시나리오 진행에 대한 결과 명시, 검증어떤 환경에서(Given) 어떤 행동을 진행했을 때(When) 어떤 상태 변화가 일어난다(Then)DisplayName에 명확하게 작성할 수 있다.[Day7 미션]https://github.com/taeyeongKims/readable-code/tree/day7[미션 회고]실제로 배웠던 것을 제대로 적용하지 못해서 아쉽다.추상에만 신경을 쓰느라, 일급 컬렉션, 상수화 등의 디테일을 신경쓰지 못했다.또한, 단일 책임 원칙에서도 시간권 패스에 라커 패스가 함께 묶여 있는 게 맞는 걸까?라는 생각도 들었다.리스코프 치환 원칙을 생각하느라 공통 인터페이스를 만들었지만 치환성에 중점을 둔 나머지, 다른 원칙을 어긋낸 건 아닐까라는 생각도 든다.또한, 의존성 역전 원칙을 어떻게 적용할지는 감도 안 잡혔었다.하지만, 섹션 7의 리팩토링 강의 영상으로 보니, 이런 식으로 연결짓는구나 라고 조금은 감이 잡히게 되었다.리팩토링에는 정답이 없다고는 하지만, 반복 연습하다보면 정답에 가까워지지 않을까,,? 라는 생각이 든다.앞으로도 계속 클린코드에 대해 생각해보며 코드를 작성해야 겠다. [2주차 회고]리팩토링 강의가 끝나고, 테스트 강의로 넘어가는 주차였다.리팩토링 미션을 진행하며 아쉬움이 많은 주차였으며강의 1개를 완주하였다는 뿌듯함도 남은 주차였으며테스트 강의를 시작하는 기대감이 생긴 주차였다.지금까지 많은 강의를 보았지만, 깊게 생각해본 강의는 이번이 처음이었던 거 같다.앞으로 많은 코드를 만들고, 보겠지만 이번 주차 강의가 많이 생각날 듯하다.
cleancode
2025. 03. 10.
0
[인프런 워밍업 클럽 BE 클린코드 & 테스트 스터디] 발자국 1주차
1주차 발자국 정리 [섹션 2]추상과 구체추상 : 중요한 정보는 가려서 남기고, 덜 중요한 정보는 생략추상으로부터 구체를 유추하지 못 하는 이유추상화 과정에서 중요 정보를 부각시키지 못함해석자가 동일하게 공유하는 문맥이 없음적절한 추상화는 도메인 문맥 안에서, 중요한 핵심 개념만 남기는 것이름 짓기단수와 복수 구분끝에 -(e)s를 붙여 데이터가 단수인지, 복수인지 구분이름 줄이지 않기자주 사용하는 줄임말이 이해될 수 있는 것은 문맥 때문은어/방언 사용하지 않기일부/현재 팀원만 아는 용어 금지도메인 용어 사전 정의좋은 코드 보고 습득비슷한 상황에서 자주 사용하는 단어, 개념 습득메서드와 추상화한 메서드의 주제는 반드시 하나다.생략할 정보와 의미를 부여하고 드러낼 정보를 구분메서드 선언메서드명추상화된 구체를 유추할 수 있는, 적절한 의미가 담긴 이름파라미터와 연결지어 더 풍부한 의미 전달 가능파라미터타입, 개수, 순서를 통해 의미를 전달외부 세계와 소통하는 창반환 타입메서드 시그니처에 납득이 가는, 적절한 타입의 반환값 돌려주기void 대신 충분히 반환할 만한 값이 있는지 고민추상화 레벨하나의 세계 안에서는, 추상화 레벨이 동등해야 한다.추상화 레벨을 주변 코드와 동등하게 구성매직 넘버, 매직 스트링의미를 갖고 있으나, 상수로 추출되지 않은 숫자, 문자열 등상수 추출로 이름을 짓고, 의미를 부여함으로써 가독성 및 유지 보수성이 상승한다. [섹션 3]뇌 메모리 작게 쓰기인지한다는 것 자체가 메모리를 사용하는 것추상화를 통해서 인지할 정보를 추려내기Early Returnelse문을 쓴다는 것은 이전 if문의 조건을 기억해야 하는 것메모리 작게 쓰기의 중요성을 생각하면 이전 조건 기억을 줄여야 한다.빠른 return문을 통해 이전 조건을 기억하지 않도록 하는 기법사고의 depth 줄이기중첩 분기문, 중첩 반복문메서드 분리로 1차원 반복문으로 구성할 수 있다.중첩 구조가 사고하는 데 도움이 된다면 메서드 분리할 필요가 없다.사용할 변수는 가깝게 선언하기공백 라인을 대하는 자세공백 라인도 의미를 가진다. 복잡한 로직의 의미 단위를 나눔으로써, 읽는 사람에게 추가 정보 제공 가능부정어를 대하는 자세부정 연산자 코드는 가독성이 떨어지고, 생각하는 것 자체가 비효율적이다. 메서드 네이밍에 부정의 의미를 담는 것이 생각하기 더 편하다.부정어구를 쓰지 않아도 되는 상황인지 체크부정의 의미를 담은 다른 단어가 존재하는지 고민 or 부정어구로 메서드명 구성해피 케이스와 예외 처리예외가 발생할 가능성 낮추기어떤 값의 검증이 필요한 부분은 주로 외부 세계와의 접점사용자 입력, 객체 생성자, 외부 서버의 요청 등의도한 예외와 예상하지 못한 예외를 구분하기사용자에게 보여줄 예외와 개발자가 보고, 처리해야 할 예외 구분Null을 대하는 자세 (Optional에 관하여)Optional은 비싼 객체이다. 꼭 필요한 상황에서 반환 타입을 사용한다.Optional을 파라미터로 받지 않도록 한다. (분기 3가지)Optional이 가진 데이터가 null인지 아닌지 + Optional 자체가 null인지Optional을 반환받았다면 최대한 빠르게 해소분기문을 만드는 isPresent() - get() 대신 다른 API 사용ex) orElseGet(), orElseThrow(), ifPresent(), ifPresentOrElse()orElse() : 항상 실행, 확정된 값일 때 사용, 호출할 필요가 없을 도 실행orElseGet() : null인 경우 실행, 값을 제공하는 동작 정의orElseThrow() : null인 경우 실행, 예외 동작 정의 [섹션 4]추상의 관점으로 바라보는 객체 지향관심사의 분리, 높은 응집도, 낮은 결합객체 설계하기 (1)절차 지향에서 잘 보이지 않았던 개념을 가시화관심사가 한 군데로 모이기 때문에 유지보수성을 상승시킨다.객체 내부에서 객체가 가진 데이터의 유효성 검증 책임을 가질 수 있다.여러 객체를 사용하는 입장에서는 구체적인 구현에 신경쓰지 않고, 보다 높은 추상화 레벨에서 도메인 로직을 다룰 수 있다.새로운 객체를 만들 때, 주의할 점1개의 관심사로 명확하게 책임이 정의되어 있는지 확인하기생성자, 정적 팩토리 메서드에서 유효성 검증이 가능하다.setter 사용 자제, 외부 세계 데이터로 변경해야 하는 경우, update~ 같이 의도를 드러내는 네이밍을 쓰자.필드의 수는 적을수록 좋다.SRP : Single Responsibility Principle (단일 책임 원칙)하나의 클래스는 단 한 가지의 변경 이유만을 가져야 한다.객체가 가진 공개 메서드, 필드, 상수 등은 해당 객체의 단일 책임에 의해서만 변경 되는가?관심사의 분리높은 응집도, 낮은 결합도OCP : Open-Closed Principle (개방 폐쇄 원칙)확장에는 열려 있고, 수정에는 닫혀 있어야 한다.추상화와 다형성을 활용해서 OCP를 지킬 수 있다.LSP : Liskov Substitution Principle (리스코프 치환 원칙)상속 구조에서, 부모 클래스의 인스턴스를 자식 클래스의 인스턴스로 치환할 수 있어야 한다.자식 클래스는 부모 클래스의 책임을 준수하며, 부모 클래스의 행동을 변경하지 않아야 한다.LSP를 위반하면, 상속 클래스를 사용할 떄 오동작, 예상 밖의 예외가 발생하거나, 이를 방지하기 위한 불필요한 타입 체크가 동반될 수 있다.ISP : Interface Segregation Principle (인터페이스 분리 원칙)클라이언트는 자신이 사용하지 않는 인터페이스에 의존하면 안 된다.ISP를 위반하면, 불필요한 의존성으로 인해 결합도가 높아지고, 특정 기능의 변경이 여러 클래스에 영향을 미칠 수 있다.DIP : Dependency Inversion Principle (의존성 역전 원칙)상위 수준의 모듈은 하위 수준의 모듈에 의존해서는 안 된다. 둘 모두 추상화에 의존해야 한다.의존성의 순방향 : 고수준 모듈이 저수준 모듈을 참조하는 것의존성의 역방향 : 고수준, 저수준 모듈이 모두 추상화에 의존하는 것 저수준 모듈이 변경되어도, 고수준 모듈에는 영향이 가지 않는다. [섹션 5]상속과 조합상속은 시멘트처럼 굳어지는 구조, 수정이 어렵다.조합과 인터페이스를 활용하는 것이 유연한 구조상속을 통한 코드의 중복 제거가 주는 이점보다, 중복이 생기더라도 유연한 구조 설계가 주는 이점이 더 크다.Value Object도메인의 어떤 개념을 추상화하여 표현한 값 객체값으로 취급하기 위해서, 불변셩, 동등성, 유효성 검증 등을 보장해야 한다.불변성 : final 필드 사용, setter 금지동등성 : 서로 다른 인스턴스여도 내부의 값이 같으면 같은 값 객체로 취급equals() & hashCode() 재정의 필요유효성 검증 : 객체가 생성되는 시점에 값에 대한 유효성을 보장하기Value Object vs EntityEntity는 식별자가 존재한다. 식별자가 아닌 필드의 값이 달라도, 식별자가 같으면 동등한 객체로 취급한다.Value Object는 식별자 없이, 내부의 모든 값이 다 같아야 동등한 객체로 취급한다.일급 컬렉션컬렉션을 포장하면서, 컬렉션만을 유일하게 필드로 가지는 객체컬렉션을 추상화하며 의미를 담을 수 있고, 가공 로직의 보금자리가 생긴다.만약, getter로 컬렉션을 반환할 일이 생긴다면, 외부 조작을 피하기 위해 꼭 새로운 컬렉션으로 만들어서 반환, new 사용Enum의 특성과 활용Enum은 상수의 집합이며, 상수와 관련된 로직을 담을 수 있는 공간이다.특정 도메인 개념에 대해 그 종류와 기능을 명시적으로 표현해줄 수 있다.만약, 변경이 정말 잦은 개념은 Enum 보다 DB로 관리하는 것이 나을 수 있다.다형성 활용하기인터페이스 구현을 통하여 여러 개의 구현 클래스들을 인터페이스로 관리숨겨져 있는 도메인 개념 도출하기도메인 지식은 만드는 것이 아니라 발견하는 것객체 지향은 현실을 100% 반영하는 도구가 아니라, 흉내내는 것이다.설계할 때는 근식적, 거시적 관점에서 최대한 미래를 예측하고, 시간이 지나 만약 틀렸다는 것을 인지하면 언제든 돌아올 수 있도록 코드를 만들어야 한다.[Day2 Mission]ㅇhttps://taey-coding.tistory.com/75 [Day4 Mission]https://taey-coding.tistory.com/77
cleancode