Hexagonal 아키텍처: Common & Global 패키지 재해석
Hexagonal 아키텍처를 활용하여 common과 global 패키지를 재설계하는 방법에 대한 가이드를 제시합니다. 이 아키텍처는 애플리케이션의 핵심 비즈니스 로직과 외부 시스템 간의 의존성을 분리하여 유연하고 유지보수가 용이하도록 설계되었습니다. 본 문서에서는 common과 global 패키지를 헥사고날 아키텍처의 원칙에 따라 재구성하는 과정을 상세히 설명하고, 각 패키지 내 파일들의 역할과 위치를 명확히 정의합니다. 이를 통해 애플리케이션의 구조적 개선을 목표로 합니다.
🚀 핵심 아이디어: Hexagonal 아키텍처 이해
Hexagonal 아키텍처는 Ports and Adapters 아키텍처라고도 불리며, 애플리케이션의 핵심 로직(Domain)과 외부 시스템(Database, UI, 외부 API 등) 간의 상호작용을 명확하게 분리하는 데 중점을 둡니다. 이 아키텍처는 다음과 같은 주요 개념을 기반으로 합니다.
- Core(Domain): 애플리케이션의 핵심 비즈니스 로직을 포함하며, 외부 시스템에 독립적으로 존재합니다. 이 레이어는 외부 시스템에 대한 어떠한 의존성도 가지지 않아야 합니다.
- Ports: Core와 외부 시스템 간의 인터페이스 역할을 합니다. Core는 Ports를 통해 외부 시스템과 통신하며, Ports는 외부 시스템의 기능을 추상화합니다.
- Adapters: Ports를 구현하며, 특정 외부 시스템에 대한 구체적인 구현을 담당합니다. 예를 들어, 데이터베이스 Adapter는 데이터베이스와의 통신을 처리하고, UI Adapter는 사용자 인터페이스와의 상호작용을 처리합니다.
헥사고날 아키텍처의 장점
- 유연성: 외부 시스템의 변경에 유연하게 대응할 수 있습니다. Adapter만 변경하면 되므로 Core 로직에는 영향을 미치지 않습니다.
- 테스트 용이성: Core 로직을 독립적으로 테스트할 수 있습니다. 외부 시스템과의 의존성을 Mocking하여 테스트 환경을 구성할 수 있습니다.
- 유지보수 용이성: 코드의 가독성이 향상되고, 변경 사항의 영향 범위를 예측하기 쉬워 유지보수가 용이합니다.
- 독립성: 핵심 비즈니스 로직이 외부 시스템에 종속되지 않으므로, 다양한 환경에서 애플리케이션을 실행할 수 있습니다.
이러한 장점들 덕분에 Hexagonal 아키텍처는 복잡한 시스템의 설계에 매우 적합하며, common과 global 패키지를 재설계하는 데 있어서도 이러한 원칙을 적용하여 시스템의 구조를 개선할 수 있습니다. 재설계를 통해 코드의 품질을 향상시키고, 미래의 요구사항 변경에 더 쉽게 대응할 수 있도록 하는 것이 목표입니다. 이러한 접근 방식은 장기적으로 애플리케이션의 지속 가능한 개발을 지원합니다.
📝 common 패키지 재구성
common 패키지는 애플리케이션 전반에서 사용되는 공통적인 기능들을 담고 있습니다. Hexagonal 아키텍처를 적용하여 common 패키지를 재구성할 때, 핵심 원칙은 외부 기술과의 결합을 최소화하고, 비즈니스 로직과 관련된 부분만 포함하는 것입니다. 다음은 common 패키지 내 파일들을 재구성하는 방법과 그 이유입니다.
core/common/domain 패키지
BaseEntity.java: 모든 도메인 객체의 기본 속성을 정의하는 클래스입니다. 생성일, 수정일, 삭제 여부 등과 같은 공통적인 속성을 관리합니다. 이 클래스는 비즈니스 로직과 직접적인 관련이 있으므로core패키지 내부에 위치합니다. 외부 시스템과의 의존성이 없어야 합니다.
핵심 고려 사항
- 의존성 최소화:
common패키지 내 파일들은 외부 시스템이나 프레임워크에 대한 의존성을 최소화해야 합니다. 예를 들어, 데이터베이스 관련 어노테이션이나 Spring 프레임워크 관련 어노테이션은 지양해야 합니다. - 재사용성:
common패키지의 파일들은 여러 도메인에서 재사용될 수 있도록 설계되어야 합니다. 일반적인 유틸리티 함수, 데이터 검증 로직, 공통 예외 처리 등이 해당됩니다. - 테스트 용이성:
common패키지의 파일들은 단위 테스트가 용이하도록 설계되어야 합니다. 외부 의존성을 Mocking하여 테스트를 쉽게 수행할 수 있도록 해야 합니다.
이러한 고려 사항들을 바탕으로 common 패키지를 재구성하면, 애플리케이션의 핵심 로직을 더 깔끔하고 유지보수하기 쉽게 만들 수 있습니다. Hexagonal 아키텍처의 원칙을 준수하여, 외부 시스템의 변경에 유연하게 대응하고, 코드의 재사용성을 높이는 것이 목표입니다. 궁극적으로는 애플리케이션의 전반적인 품질을 향상시키는 데 기여할 수 있습니다.
📝 global 패키지 재구성
global 패키지는 애플리케이션의 전역적인 설정, 예외 처리, 보안 관련 기능을 담당합니다. Hexagonal 아키텍처를 적용하여 global 패키지를 재구성할 때, 핵심은 외부 시스템과의 상호작용을 infrastructure 레이어로 격리하고, core 레이어에는 비즈니스 로직과 관련된 부분만 남기는 것입니다. 다음은 global 패키지 내 파일들을 재구성하는 방법과 그 이유입니다.
infrastructure/global 패키지
config: 외부 시스템 설정을 담당합니다. 예를 들어,SwaggerConfig.java,SecurityConfig.java,WebSocketConfig.java등이 여기에 해당합니다. 이러한 설정 파일들은 외부 시스템(Swagger, Spring Security, WebSocket 등)과의 의존성을 가지고 있으므로infrastructure패키지에 위치합니다.exception: 전역 예외 처리를 담당합니다.GlobalExceptionHandler.java,ErrorResponse.java등이 여기에 해당합니다. 예외 처리 로직은 외부 시스템(예: Spring MVC)에 의존할 수 있으므로infrastructure패키지에 위치합니다.security: 보안 관련 기능을 담당합니다.controller,filter,jwt,oauth등의 하위 패키지를 포함합니다. 보안 기능은 Spring Security와 같은 외부 시스템에 의존하므로infrastructure패키지에 위치합니다.util: 인프라 유틸리티를 담당합니다.CookieUtil.java,FileNameUtils.java,UrlUtil.java,MemberUtil.java등이 여기에 해당합니다. 이러한 유틸리티들은 외부 시스템(예: Servlet API)에 의존할 수 있으므로infrastructure패키지에 위치합니다.
core 패키지 내 역할
global 패키지 내에서 core 패키지로 이동할 수 있는 파일은 거의 없습니다. core 패키지는 비즈니스 로직에 집중해야 하며, 외부 시스템과의 의존성을 가지지 않아야 하기 때문입니다. 그러나, 비즈니스 상수는 예외적으로 core 패키지 내에 위치할 수 있습니다.
core/global/constant: 비즈니스 로직에서 사용되는 상수들을 정의합니다. 예를 들어,SecurityConstant.java,UrlConstant.java등이 여기에 해당합니다. 이러한 상수들은 외부 시스템에 대한 의존성이 없으므로core패키지에 위치할 수 있습니다.
핵심 고려 사항
- 외부 시스템 격리:
infrastructure패키지는 외부 시스템과의 상호작용을 담당하고,core패키지는 외부 시스템에 대한 어떠한 의존성도 가지지 않도록 합니다. - 단일 책임 원칙: 각 클래스와 파일은 단일 책임을 가져야 합니다. 예를 들어,
GlobalExceptionHandler는 전역 예외 처리만 담당하고, 다른 기능은 다른 클래스에서 처리해야 합니다. - 테스트 용이성:
infrastructure패키지의 코드도 테스트 가능하도록 설계해야 합니다. Mocking을 통해 외부 시스템과의 의존성을 제거하고, 단위 테스트를 수행합니다.
이러한 고려 사항들을 바탕으로 global 패키지를 재구성하면, 애플리케이션의 구조를 더 명확하게 하고, 외부 시스템의 변경에 유연하게 대응할 수 있습니다. Hexagonal 아키텍처를 통해 코드의 유지보수성과 확장성을 높이는 것이 목표입니다. 궁극적으로는 애플리케이션의 안정성을 향상시키는 데 기여할 수 있습니다.
🚀 결론
Hexagonal 아키텍처를 적용하여 common과 global 패키지를 재설계하는 것은 애플리케이션의 구조적 개선을 위한 중요한 단계입니다. 이 가이드에서 제시된 내용을 바탕으로, 각 패키지 내 파일들의 역할과 위치를 명확히 정의하고, 외부 시스템과의 의존성을 최소화하여 유연하고 유지보수가 용이한 애플리케이션을 구축할 수 있습니다. common 패키지에서는 핵심적인 도메인 로직과 재사용 가능한 유틸리티를 관리하고, global 패키지에서는 외부 시스템과의 상호작용을 infrastructure 레이어에 격리하여, 애플리케이션의 안정성과 확장성을 높이는 데 기여할 수 있습니다.
주요 단계 요약
- Core와 Infrastructure 분리: 핵심 비즈니스 로직은
core패키지에, 외부 시스템과의 상호작용은infrastructure패키지에 위치시킵니다. - Ports와 Adapters 활용: Ports를 통해 Core와 외부 시스템 간의 인터페이스를 정의하고, Adapters를 통해 구체적인 구현을 제공합니다.
- 의존성 최소화: 외부 시스템에 대한 의존성을 최소화하고, Core 로직은 독립적으로 유지합니다.
- 테스트 용이성 확보: 각 컴포넌트의 단위 테스트를 용이하게 설계합니다.
이러한 단계를 통해 Hexagonal 아키텍처의 장점을 최대한 활용하고, 애플리케이션의 지속 가능한 개발을 위한 기반을 마련할 수 있습니다.