Today I Learned
(24.10.10) TDD & DDD / Filter & Interceptor & AOP 비교해보기
계속 CS 관련 모의 면접과 면접 코칭을 받고 있는데
알고 있는 CS 지식을 자연스럽게 말하는데 많이 어려우나
특히 여러개를 비교하라는 점에서 정리가 안되어있기 때문에 당황을 하는 경우가 많았다.
특히, DDD, AOP, Filter, Interceptor등 산발적으로 정리가 된 정보를 보다 함께 정리를 하면서 스스로 공부하면서
비교를 할 수 있도록 하면서
면접 피드백 용, 다음 면접 대비를 하도록 한다.
특히, 정의가 애매할 수 있는 interceptor에 한해서 좀더 다뤄보면서 정리했다.
TDD(Test-Driven Development) & DDD (Domain-Driven Design)
TDD(Test-Driven Development)
- 테스트 주도 개발
- 실제 코드를 작성, 구현하기 전에 먼저 테스트, 또는 테스트코드를 작성하는 개발방법
- 해당 기능이 올바르게 작동하는지 검증 후, 적용하는 방식
- 빠른 주기
- 매우 짧은 주기의 개발이 진행이 될 때, 사용
- 최소한의 코드를 작성하여 테스트 → 리펙토링의 반복
TDD 단계
- Red
- 구현 기능 테스트의 실패 시나리오를 가정하여 테스트 코드 작성, 시행
- Green
- 구현 기능 테스트의 성공 시나리오를 가정하여 최소한의 코드를 작성하여 테스트 시행
- Refactor
- 중복 제거, 코드 최적화를 동시에 진행하면서 리팩토링 → 서비스 구현
장점
- 높은 품질 수준의 코드를 보장
- 요구사항에 맞는 코드를 신뢰성 보장
- 빠른 피드백
- 테스트 주기가 짧은 편에 속하기 때문에, 빠른 피드백으로 수정 즉각 대응
- 안정성 보장
- 이미 진행된 테스트를 통해 버그의 발생 가능성을 최소화
단점
- 느린 초기 개발 세팅
- 테스트를 빠르게 작성하더라도, 그만큼의 테스트코드를 작성하는데에 시간이 들어가기 때문에 초기 개발이 느리게 진행
- 테스트 리소스 낭비
- 테스트 케이스가 처음부터 잘못된 경우/요구사항의 변경이 있을 경우, 다시 작성을 해야하기 때문에 테스트 단에서의 더 많은 리소스가 소비
- 테스트의 강항 의존성
- 테스트가 잘못 진행될 경우, 관련된 모든 코드의 유지보수가 어려울 수 있음, 복잡해지고, 다시 작성해야하므로
사용예시
- Agile 개발 환경
- 빠른 피드백으로 개발, 피드백 하는 루프형식의 개발환경에 적합
- 높은 수준의 품질을 보증해야하는 시스템 개발
- 금융, 의료 등 버그가 매우 치명적인 결과를 야기할 수 있는 도메인의 개발환경 = 신뢰성과 안정성을 보장하는 개발환경
DDD (Domain-Driven Design)
- 도메인 중심 설계 방법
- 소프트웨어 설계의 중심을 “도메인”으로 두는 것
- 중심 도메인의 요구사항을 만족시키기 위해 설계, 개발을 진행하는 것
- 비지니스 문제를 해결을 목적
- 개발 방법론 보다는 설계 접근법에 더 가까운, 도메인 문제를 해결하는데 목적을 두고 있는 접근법
개발에서의 사용
3 Layered Architecture
- 3 Layered Architecture는 DDD의 원칙을 효과적으로 적용할 수 있도록 구조 = 도메인 모델을 기반으로 한 비즈니스 로직을 명확하게 표현한 계층이 있기 때문
- 비즈니스 로직의 캡슐화: Service단에서의 비지니슬 로직으로 개별적으로 업데이트 하고 재사용할 수 있어 Domain 중심이 되는 설계
MSA (Microservices Architecture)
- 비지니스 도메인을 작은 독립적 서비스로 분리해서 도메인을 이루는 방식
- 각 독립적인 서비스가 도메인 로직을 담당, 각각 유용성 있게 독립적으로 작동, 대응이 가능
- DDD 원칙에 의거해 Microservice별 개발팀 운영 가능
API 디자인
- RESTful API를 설계에 있어서 DDD 소스를 반영해서 CRUD 작업을 명확히 구분, 리소스 별 기능을 분리 가능
장점
- 복잡한 비지니스 로직을 명확히 관리
- 도메인 모델링이 있기 때문에, 비지니스 로직이 명확
- 실제 비지니스와 유사하게 개발하는 방식
- 유지보수 용이
- 비지니스 용어자체도 개발에 포함시키기 때문에 코드 이해가 쉽고, 유연하게 대처 가능
- 협업 효율
- 개발자 외에도 다른 업무 담당자와도 직관적으로 의사소통, 요구사항 반영이 이뤄지기 용이
단점
- 높은 초기 리소스 비용
- 모든 소프트웨어 참여자들이 해당 도메인에 대한 이해가 있어야하므로 개발 속도가 저하될 수 있음
- 작은 프로젝트에 부적합
- 스타트업 등 그닥 복잡하지 않은 서비스에 대비하여 오히려 과도하게 설계가 될 수 있는 경향이 있음
사용예시
- 복잡한 비지니스 로직이 필요한 시스템
- 대규모 금융, 물류 시스템과 같은 필요한 해당 도메인 지식이 방대할 경우 설계와 함께 적용이 되어야 할 때
- 비지니스/기술적 요구사항 등이 자주 업데이트 되는 시스템
- 비지니스 로직이 충분히 자주 Update 가능성이 있는 시스템
Filter & Interceptor & AOP
- 공통관심사를 가지고 실제 비지니스로직과 분리한 컴포넌트
- 재사용성과 유지보수성을 향상
Filter
- Servlet 이 제공하는 요청, 응답을 중간에서 처리(전처리, 후처리)하는 컴포넌트
- Servlet : 클라이언트 요청처리/응답 생성의 컴포넌트, HTTP 요청 처리 등 담당, 결과 반환 담당
- Servlet API를 사용
- avax.servlet.Filter 인터페이스를 구현하여 사용
- Filter Chain을 활용해서 순차적으로 사용 가능
Example
- Servlet API 단에서 인증/인가 Filter
- 로그인 요청시 Servlet으로 도달하기 전, Filter단에서 이미 인증/인가를 처리
- 인증/인가 실패 시, Servlet으로 진행 X → Controller 까지 도달하지 않음
- HTTP 요청/응답 전처리 후처리
- 보안, 인코딩, CORS 처리 등
장점
- 모듈화
- 비지니스로직과 분리가 되어있기 때문에 기능을 재사용 가능
- 빠른 처리
- 요청을 가장 먼저 빠르게 처리가 가능
단점
- 사용범위 제한
- Servlet API에서만 사용가능
- Spring Security 필터와 통합을 해야만 하기 때문에 제약
- 단순 구조
- 비지니스로직과 분리가 되어있기 때문에 Filter단에서 해결할 수 있는 간단한 로직만 가능
Interceptor
- 요청/응답을 중간에 처리하는 Filter와 유사하나, Spring이 제공하는 Spring MVC 구조에서 Controller에 적용되는 컴포넌트
- Spring MVC와 통합된 HanderInterceptor 를 통해 구현하여 Spring Interceptor를 사용 가능
- Request → WAS → Filters → Servlet → Spring Intercepter → Controller 순서로 진행
- DispatcherServlet과 Controller 사이에 호출, 작동될 수 있음
- InterceptorChain이 존재하므로 순서대로 적용 가능
Example
- Controller 앞단에서의 인증/인가 Interceptor
- 인증 인가 Filter와 똑같지만 그 적용 단계별 위치가 다를 수 있음
- Controller에 연계되어 있는 처리에 제한
구현 및 설정
- HandlerInterceptor 인터페이스 구현
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean **preHandle**(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 요청 처리 전 실행할 로직 -> 정상 호출
System.out.println("Before handling the request");
return true; // true를 반환하면 다음 인터셉터나 핸들러로 요청이 진행
}
@Override
public void **postHandle**(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 요청 처리 후 실행할 로직 -> 단, 예외가 발생했을 경우 호출 X
System.out.println("After handling the request");
}
@Override
public void **afterCompletion**(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 요청 처리 완료 후, 예외 발생여부 상관없이 실행할 로직
System.out.println("After request completion");
}
}
- Spring Interceptor 설정
@Configuration
public class WebConfig implements **WebMvcConfigurer** {
@Override
public void **addInterceptors**(InterceptorRegistry registry) {
registry.addInterceptor(new CustomInterceptor())
.**order**(1)
.**addPathPatterns**("/**")
.**excludePathPatterns**("/error");
}
}
- WebMvcConfigurer가 제공하는 addInterceptors() 사용하여 인터셉터를 등록
- Order() : 필터체인과 마찬가지로 인터셉터의 호출 순서를 지정
- addPathPatterns() : 인터셉터를 적용할 URL Patterns을 지정
- excludePathPatterns() : 인터셉터에서 제외할 URL Patterns를 지정
AOP (Aspect-Oriented Programming), 관점지향 프로그래밍
- Java의 비지니스 로직을 관심사 기준으로 분리하나, Spring AOP를 통해서 메서드 기준으로 호출 전후 처리에 실행하는 컴포넌트
- 코드의 공통 관심사를 분리하는 요소
- 로깅, 트랜잭션 관리 등
구성
- Pointcut
- AOP 부가기능을 적용할 메서드의 위치를 지정
- Advice
- 메서드에서 호출된 정확한 지점을 정의
Example
- 로깅, 트랜잭션
장점
- Pointcut, Advice로 부가기능을 메서드에 쉽게 적용가능
단점
- 복잡한 흐름이 될 경우, 디버깅에 있어서 혼잡하거나 어려울 수 이씅ㅁ
- AOP로 인한 성능이슈가 발생할 수 있음
비교 요약
특성 | Filter | Interceptor | AOP |
사용 영역 | Servlet API | Spring MVC | 모든 Java 어플리케이션 코드적으로 접근 |
흐름 제어 | Web 요청/응답 전후 Servlet 컨테이너에 도달 전 |
Controller 요청 처리 전후 | 메소드(비지니스로직) 호출 전후 |
유연성 | 제한적(Servlet) | 중간(Controller) | 높음 |
복잡한 로직 | 구현 어려움 | 구현 어려움 | 가능 |
주요 용도 | 인증, 로그 기록 | URL 패턴에 대한 필터링 | 트랜잭션 관리, 로깅 등 |
'Today I Learned' 카테고리의 다른 글
(24.10.17) NginX 정리 + 본인 프로젝트에서 활용한 부분 추가 (1) | 2024.10.17 |
---|---|
(24.10.14) Swagger & Spring REST Doc (2) | 2024.10.14 |
(24.10.08) 보안 공격 정리 : SQL Injection, CSRF, XSS (0) | 2024.10.08 |
(24.10.07) CAP 이론 정리 (0) | 2024.10.07 |
(24.09.26) 정렬 알고리즘 : Quick Sort, Merge Sort (1) | 2024.09.26 |