멀티모듈 프로젝트를 구성하고, 사용하는 와중에, 다시 한 번 각 모듈간의 의존성 관계에 있어서 고민이 생겼습니다. 이 프로젝트에서는 간단하게 두 모듈로 구성하였습니다.
1. Domain 을 관리하는 Core 모듈,
2. WAS(Tomcat)로 부터 요청을 받고, 서비스 로직을 처리하는 API 모듈.
이 두 모듈을 의존관계는 Api 모듈이 --> Core 모듈을 의존하는 상황이였습니다. 이 떄, core 모듈에서 의존하는 라이브러리를 api 모듈에 노출 시키는 것이 맞는지에 대한 고민이 있었습니다.
(이렇게 노출 시킨다면, 모듈을 나눈 것에 의미가 있는것인가?)
이번 글은 이 질문에 대한 공부한 것을 작성한 글입니다.
[목차]
- Gradle 외부 라이브러리 depenecies를 설정할 때, 사용되는 api, implementation 의 차이
- api, implmentation을 사용하여 의존성을 설정하였을 때, 갖게 되는 장단점
사진을 통해 api, implementation의 사용을 일단 보겠습니다.
해당 Gradle은 위의 설명한 core 모듈의 라이브러리 의존성 목록 입니다.
api로 외부 라이브러리의 의존성을 받게 되면, core 모듈을 의존하는 api 모듈에서도, 라이브러리 함수에 접근할 수 있습니다. api 키워드를 사용하지 않으면, 어떻게 되는지 알아봅시다.
간단한 예시를 통해 봅시다.
상황) domain model 의 spring-data-jpa의 구현체를 사용하는 Repository를 만들었습니다.
domain : Member
package com.example.contractcore.Domain;
import com.example.contractcore.Repository.MemberRepository;
import lombok.*;
import org.hibernate.envers.Audited;
import javax.persistence.*;
@Entity
@Getter
@Setter
@Audited
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Member extends MainBaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id ;
@Column
private String name;
@Column
private int age;
@Column
private String tel;
}
repository : MemberRepository (spring-data-jpa에 의해 추상화된 JpaRepository를 상속)
package com.example.contractcore.Repository;
import com.example.contractcore.Domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface MemberRepository extends JpaRepository<Member,Long> {
}
Springboot, spring-data-jpa를 활용하여, 간단한 api를 만들 때 볼 수 이는 간단한 상황입니다.
이, 상황에서 api 모듈에서, MemberRepository를 bean 주입 받아서 사용하는 것을 보여드리겠습니다.
구현된 함수 내용들에 모두 직접적으로 접근할 수 있습니다.
spring-data-jpa에 구현된 많은 내용들에 접근할 수 없게 됩니다.
(jpa를 직접적으로 다룰 수 있는 @Transactional .. 기타 등등 다 사용안됩니다.)
이 경우에 맨 처음에는 api를 사용하여 api 모듈에서 core 모듈에서 의존하는 spring-data-jpa 라이브러리에 접근할 수 있도록 하면 되겠다 생각하고 끝내버렸습니다.
근데 추가적으로 생각을 해보니 이런 의존성을 갖는게 맞는지.. 이러면 core 모듈에서 의존하는 외부라이브러리를 api 모듈에서 의존하게 되는데 맞는가에 대해 고민하게 되었습니다.
(이러면 멀티모듈을 쓰는게 의미가 있나..)
이런 의문점을 갖고, 여러 자료들을 찾는 결과, 저와 같은 고민을 한 사람들의 질문을 찾을 수 있었습니다. (Reference 참조해주세요)
이제 api, implementaton 을 사용했을 때의 장단점에 대해 이야기 해보겠습니다.
장점
단점
장점
단점
아래의 reference의 질의응답을 봤을 때 내가 내린 결론은 다음과 같다.
spring과 관련 없는 외부라이브러리 사용할 경우, 어느 모듈에 두어야하는지 고민해야합니다. 각 의존성 관계를 잘 생각해서 설계를 해야한다 생각합니다. 위와 같은 고민을 하게 되는 경우라면, 구조 설계가 잘못됬을 것이라 생각합니다.
"남이 말하는 Best Practice 만을 쫒지 말고, 자신의 생각대로 만들고, 문제가 생기면 고치도록 하자"
"Multimodule로 설계하더라도, runtime에는 필요한 의존성을 다들고 있다. compile 타임에만, 접근을 하지 못하도록 하는것이다. "
(내가 이해한 바로는, compile 타임엔 접근하지 못하지만, runtime 에는 모든 코드를 하나로 만들어 돌리기 때문에, 접근이 가능하다고 이해했습니다. 즉 개발자가, implementaton 키워드를 쓰면 상위모듈에서 접근하지 못하게 하는 것뿐이지, application이 돌 때는, 관련 라이브러리 코드들을 다 메모리에 올려서 사용하고 있다고 이해했습니다.)
https://discuss.gradle.org/t/best-practice-for-api-vs-implementation-in-multi-module-project/30519
(친절한 설명, 각각의 장단점에 대해 자세히 설명되어 있어서 도움이 많이 되었습니다. 감사합니다~)