Programming 40

단위 테스트 대상 분리하기!

아래는 최범균님의 유튜브를 보고 느낀 점을 나름대로 정리한 것이다. https://www.youtube.com/watch?v=qZ1R0C_iiV4 테스트 불가능한 문제 아래의 코드가 테스트가 불가능한 문제가 있었다고 한다. ResultBuilder builder = ...; InputPeriod realPeriod = mapper.selectPeriod(param); // 1. DB에서 읽음 if (realPeriod == null) { // 2. 없으면 다른 값 읽음 InputPeriod expectedPeriod = mapper.selectExpectedPeriod(otherParam); builder.period(expectedPeriod).type(EXPECTED); } else if (realP..

필요한 파라미터만 사용하기! (DTO를 남용하지 말자.)

Controller - Service - Repository 패턴 아래는 전통적인 계층형 아키텍처(Layered Architecture)이다. DTO 형태로 요청을 받고 Controller, Service, Repository 등이 메시지를 주고받을 때도 DTO를 사용한다. 그러면 되는 걸까?! 아키텍처 Layered Architecture 관점으로 봤을 때 Controller는 Service를 알아야 하는 것이 맞다. 그렇지만 호출되는 Service가 Controller를 알아야 할 필요는 없다. 각 계층은 단지 하위의 있는 계층을 사용하면 된다. Controller에서 DTO를 자신의 Needs로 사용한다면 Service가 DTO를 통해 간접적으로 웹 계층에 의존하게 된다. 개념적 의존이 역류하게 ..

객체지향 생활 체조 원칙 9가지 정리!

최근에 우아한형제들에서 코드 리뷰를 객체지향 생활 체조 원칙를 기반으로 한다는 얘기를 처음 접했다. 객체지향 생활 체조 원칙에 대해 관심을 가지고 찾아봤고, 객체지향의 사실과 오해라는 책과 DDD 관련 책에서도 많이 언급하던 내용에 대한 가이드와 다른 좋은 개념도 많았다. 이번 포스팅에서는 객체지향 생활 체조 원칙에 대해서 작성한다. 객체지향 생활 체조 원칙 객체지향 생활 체조 원칙은 소트웍스 앤솔러지(ThoughtWorks Anthology) 라는 책에 나오는 원칙이다. 소트웍스 앤솔로지에서는 9가지 원칙을 준수하면서 객체지향을 추구할 수 있다고 한다. 한 메서드에 오직 한 단계의 들여쓰기(indent)만 한다. else 예약어를 쓰지 않는다. 모든 원시 값과 문자열을 포장한다. 일급 컬렉션을 쓴다. ..

Programming/OOP 2023.05.22

Clean Architecture - 헥사고날 아키텍처에서 테스트 작성하기!

테스트 피라미드일반적으로 테스트의 기본 전제는 만드는 비용이 적고, 유지보수하기 쉽고, 빨리 실행되고, 안정적인 작은 크기의 테스트들에 대해 높은 커버리지를 유지하는 것이다.하나의 단위(일반적으로 하나의 클래스)가 제대로 동작하는 지 확인할 수 있는 테스트는 단위 테스트이며, 여러 개의 단위를 넘는 경계나 아키텍처, 시스템을 결합하는 테스트는 비용이 더 비싸지고, 실행이 더 느려지며, 깨지기 쉬워진다.단위 테스트는 의존하는 다른 클래스들은 인스턴스화 하지 않고 테스트하는동안 필요한 작업들을 흉내(mock)만 내도록 대체한다.통합 테스트는 하나의 기능에 필요한 여러 유닛을 인스턴스화하고 데이터를 보낸 후 전체적인 기능을 테스트한다.시스템 테스트의 경우 애플리케이션을 구성하는 모든 객체 네트워크를 가동시켜 ..

헥사고날 아키텍처 - 영속성을 구현하는 방법!

클린 아키텍처에서는 전통적인 계층형 아키텍처에서 모든 것이 영속성 계층에 의존하게 되는 점을 역전시켜, 영속성 계층을 애플리케이션 계층의 플러그인처러 만든다. 아키텍처 헥사고날 아키텍처에서는 코어의 서비스가 영속성 어댑터에 접근하기 위해 포트를 사용하는 구조를 가진다. 코어의 서비스는 포트 인터페이스를 통해 의존성을 역전시킨다. 더이상 DB를 교체하거나 JPA에서 JDBC로 기술을 바꾸는 등의 변경이 도메인 코드에 전파되지 않는다. 영속성 어댑터의 책임 영속성 어댑터의 책임은 아래와 같다. 포트의 입력 모델을 DB 포맷으로 매핑한다. DB에 쿼리 요청을 보낸다. DB 출력을 포트의 출력 모델로 매핑한다. 결과를 반환한다. 포트 인터페이스 포트 인터페이스의 크기는 어떻게 하는 것이 적당할까? 일반적으로 아..

헥사고날 아키텍처 - 웹 어댑터(컨트롤러) 구현하기!

헥사고날 아키텍처에서 Controller의 역할은 외부 세계로 보고 어댑터를 통해 이루어진다. 이를 어떻게 구현하는 지 알아보자. 의존성 아래 그림은 웹 어댑터와 애플리케이션 코어가 어떻게 상호작용하는 지 나타낸다. 웹 어댑터(인커밍 어댑터)는 애플리케이션에 의해 구현된 인터페이스인 전용 포트를 통해 애플리케이션 계층과 통신하고, 외부로부터 요청을 받아 애플리케이션 코어를 호출하는 역할을 수행한다. 해당 그림에서 만약 웹 어댑터에 능동적으로 알림을 줘야 한다면 서비스를 거쳐 아웃고잉 포트를 통과하도록 구현하면 된다. 역할 웹 어댑터는 일반적으로 다음의 처리를 한다. (시간 순으로 기술) HTTP 요청을 자바 객체로 매핑 권한 검사 입력 유효성 검증 입력을 유스케이스의 입력 모델로 매핑 유스케이스 호출 유..

헥사고날(Hexagonal) 아키텍처란 무엇인가?!

헥사고날 아키텍처는 전통적인 계층형 아키텍처의 단점을 보완하기 위해 생겼다. 도메인 중심 아키텍처의 일종으로 클린 아키텍처를 일반화한 구조 중 하나이다. (포트와 어댑터(Ports and Adaters) 아키텍처라고도 말한다.) 계층형 아키텍처의 문제 1. 데이터베이스(+ 영속성)에 대한 의존이 퍼지게 된다. 전통적인 계층형 아키텍처의 도메인 계층은 영속성에 의존한다. 즉, 도메인 계층이 자연스레 데이터 베이스에 의존하게 되어서 데이터 베이스에 변화가 일어난다면 도메인 계층도 변화가 생긴다. 추가로 아래와 같이 서비스 계층에서도 영속성 모델을 도메인 모델 처럼 사용하게 된다. 결과적으로 해당 도메인 모델을 사용하는 서비스 계층에서도 즉시 로딩, 지연 로딩, 트랜잭션, 플러시 등을 고려해야 하고, 영속성에..

패키지 의존성 사이클 검사 및 개선하기! (feat. IntelliJ)

우아한 테크 세미나에서 발표한 우아한 객체지향 by 우아한형제들 개발실장 조영호님 강연을 무척 재밌게 봤다. Link: https://www.youtube.com/watch?v=dJ5C4qRqAgA&t=5217s 해당 영상에는 패키지 의존성 관련 내용이 주를 이룬다. 추가로 얼마 전 백기선님께 공개 코드 리뷰를 받으면서도 패키지 의존성 관련해서 대화를 많이 나눴다. Link: https://jaehoney.tistory.com/276 그래서 최근 진행하던 사이드 프로젝트의 패키지 의존성 사이클이 있는 지 검사해보기로 하였다. Analyze Cyclic Dependencies(feat. IntelliJ) ArchUnit을 사용해서 의존성 검사를 자동화할 수도 있다. Custom한 Layered archit..

테스트 코드가 실제 코드에 영향을 줘선 안되는가 ?

많은 분들이 테스트 코드가 프로덕트 코드에 영향을 줘선 안된다고 알고 있을 것이다. 나 조차도 내가 개발한 코드는 절대 테스트 코드가 프로덕트 코드에 영향을 주지 않고 있다고 믿었다. 그러던 어느날, 회사 팀 동료 A가 나에게 이런 질문을 했다. 동료 A: Jerry! 서비스 테스트 코드를 작성할 떄 RequestDto가 필요한데, 해당 Dto는 getter만 열어뒀거든요. 서비스 테스트하려면 Builder나 Constructor를 만들어줘야 하나요?? Jerry(본인): (3분 정도 고민하다가..) 헐헐 그러네요!! 저는 테스트가 프로덕트 코드에 영향이 절대 없게 개발하는 것을 목표로 했었는데, 따지고 보면 생성자 조차도 필요 없는 것이네요..! 해당 질문으로 나는 완전 충격을 받았다. 상황 상황은 이..

OOP - IS-A 관계, HAS-A 관계 차이 (상속)

IS-A 관계 (is a relationship) 상속 관계를 의미한다. 상속 관계에서는 '~은 ~이다.'가 성립한다. 아래의 예시에서 Student와 Person은 IS-A 관계가 성립한다. public class Student extends Person { private int studentId; } 여기서 Person은 추상화된 개념을 표현한 것이다. HAS-A 관계 (has a relationship) 포함 관계를 의미한다. 포함 관계는 '~은 ~를 가진다.`가 성립한다. 아래의 예시에서 Student와 Book은 HAS-A 관계가 성립한다. public class Student { private Book book; }

Programming/OOP 2022.08.08