Batch와 API 모듈간 엔티티 공유 전략

90736

Spring Boot 기반의 API와 Spring Batch 프로젝트를 독립적으로 운영하는 환경에서 겪었던 도메인(Entity) 클래스 불일치 문제와 이를 멀티 모듈 구조를 통해 해결한 경험을 공유합니다.

프로젝트가 분리되어 개발될 때 흔히 발생하는 복사/붙여넣기 기반 개발 의 문제점, 불필요한 변경을 최소화하면서도 핵심 도메인의 일관성을 유지하기 위한 타협점을 어떻게 잡았는지 소개합니다.

문제 상황 : 독립된 프로젝트와 도메인 불일치

처음에는 API 프로젝트와 Batch 프로젝트들이 각각 독립된 단위로 운영되었습니다. 배치 프로젝트들은 교내 학생 데이터를 DB에 주입하기 위해 Data JPA 기반의 ItemWriter를 사용하고 있었고, 이는 곧 API 프로젝트의 Domain(Entity) 클래스에 의존한다는 것을 의미했습니다.

image

발생했던 문제점:

  1. 코드 불일치 : 시스템의 중심인 Domain 클래스는 모든 프로젝트에서 동일한 구조와 로직을 가져야 했습니다. 하지만 프로젝트가 분리되어 있다 보니, Student 엔티티에 필드 하나를 추가하면 이를 사용하는 모든 배치 프로젝트에 수동으로 복사/붙여넣기 해야 했고, 이 과정에서 코드 불일치가 쉽게 발생했습니다.
  2. 일관성 보장 메커니즘 부재 : 개발자들이 동일한 도메인 구조를 사용해야 한다는 원칙 외에는 이를 기술적으로 강제할 메커니즘이 없었습니다.

결국, 핵심 Domain의 변경은 모든 배치 프로젝트에 반복적인 복붙 작업을 강요되는 원인이었습니다.

해결책 : 멀티 모듈 구조 도입

문제의 해결책은 멀티 모듈 프로젝트 구조를 도입하여 독립된 프로젝트들을 하나의 부모 프로젝트 아래로 통합하는 것이었습니다.

이상적인 멀티 모듈 구조는 Domain 자체를 별도의 모듈로 분리하여 모든 애플리케이션 모듈들이 이를 의존하도록 만드는 것이었습니다.

하지만 여기서 고민이 시작되었습니다.

image

"Domain 전체를 분리할 만큼의 이득이 있을까?"

현재 배치 프로젝트들은 여러 도메인 중 최대 1~2개의 엔티티만 사용하고 있었습니다. Domain 모듈을 완전히 분리하게 되면, 당장은 메인 application 모듈 내의 로직에서도 패키지 구조 변경 등의 추가 작업이 발생해야 했습니다. 전체 도메인이 아닌, 필요한 엔티티만 공유할 수 있는 중간 타협점이 필요했습니다.

타협점 : 필요한 엔티티만 수동 스캔

제가 선택한 타협점은 Domain 코드를 메인 application 모듈에 유지하되, 다른 배치 모듈들이 이를 의존하여 사용할 수 있도록 구조를 변경하는 것이었습니다.

  1. 프로젝트 통합 및 Gradle 종속성 주입:

흩어져 있던 모든 프로젝트(application, batch-lecture, batch-enrollment...)를 하나의 프로젝트 아래로 통합했습니다. 그리고 각 배치 모듈의 build.gradle 파일에서 application 모듈을 의존성으로 추가했습니다.

// Batch 모듈의 build.gradle 
dependencies { 
// application 모듈에 있는 Domain 클래스를 사용하기 위해 종속성 주입 
implementation project(':application') 
// ... 나머지 Spring Batch 관련 의존성 
}
  1. @EntityScan 을 이용한 수동 스캔:

image

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource ...: 'com.example.api.domain.Student' not a managed type...

종속성 주입만으로는 Spring Boot가 자동으로 다른 모듈에 있는 엔티티를 인식하지 못합니다. Spring Batch는 여전히 EntityManagerFactory 를 구성할 때 엔티티를 찾지 못합니다.

따라서, 각 배치 모듈의 @SpringBootApplication 메인 클래스에 EntityScan을 사용하여 application 모듈에 있는 엔티티 패키지 경로를 명시적으로 지정 해 주었습니다.

@SpringBootApplication @EntityScan("com.example.application.domain") // application 모듈의 엔티티 패키지를 직접 스캔 
public class BatchLectureApplication { 
// ... 
}

결과

타협점을 통해 다음과 같은 이점을 얻을 수 있었습니다.

  • 코드 일관성 보장 : 모든 배치 모듈은 이제 application 모듈의 원본 Domain 클래스를 참조하므로, 도메인 변경 복사/붙여넣기가 아닌 의존성 업데이트만 필요하게 되었습니다. 더 이상 코드 불일치 문제가 발생하지 않습니다.
  • 유지보수 용이성 : 여러 프로젝트 모듈들을 하나의 프로젝트 구조 내에서 관리하게 되어, 코드를 찾아다니는 시간이 줄고 중복 로직의 관리도 수월해졌습니다.
  • 최소한의 변경: Domain 전체를 별도의 모듈로 분리되지 않아 application 모듈 내부의 대대적인 리팩터링 없이도 문제를 해결했습니다.

Spring Boot의 자동 설정(Auto-Configuration) 은 편리하지만, 멀티 모듈 경계에서는 @EntityScan 과 같은 명시적인 수동 설정을 통해 프레임워크가 올바른 컨텍스트를 찾아주도록 돕는 것또한 시스템 운영에 필요함을 느끼는 경험이었습니다.

Reference

https://techblog.woowahan.com/2637/

https://github.com/anandgaur22/MultiModuleTest