3-tier 아키텍처 시스템에서 데이터베이스가 변경되거나 다른 저장소를 추가해야 한다면?
DB와 비즈니스 로직의 강결합으로 인한 문제가 발생한다.
추상화 된 인터페이스가 없이 비즈니스 로직에서 직접적으로 MySQL 구현체를 사용한다.
DIP 위반 - 고수준 모듈(Service)에서 저수준 모듈(Repository)에 의존한다.
OCP 위반 - 확장에 열려있지 않으며, 저수준 모듈에서 수정 시 의존하는 고수준 모듈 역시 수정해야 하므로 수정에 닫혀있지도 않다.
MySQL DB에서 MongoDB로 변경
- 비즈니스(서비스) 로직의 구현체를 MongoDB 구현체로 수정해야 한다.
- 새로 MongoDB의 구현체로 만든 Repository에서 MongoDB에 맞는 데이터 처리 로직을 새로 구현해야 한다.
public class UserService {
private UserRepository userRepository;
public UserService() {
this.userRepository = new UserRepository(); // DIP 위반
}
public List<User> getUser(Long id) {
return userRepository.findById(id); // DB 구현에 의존
}
}
//기존 코드 (MySQL)
public class UserService {
private UserRepository userRepository;
public UserService() {
this.userRepository = new UserRepository();
}
public User getUser(Long id) {
return userRepository.findById(id);
}
}
public interface UserRepository extends JpaRepository<User, Long> {
public User findById(Long id);
}
//변경 코드 (MongoDB)
public class UserService {
private MongoUserRepository userRepository;
public UserService() {
this.userRepository = new MongoUserRepository();
}
public User getUser(Long id) {
return userRepository.findById(id);
}
}
public class MongoUserRepository extends MongoRepository<User, Long>{
public User findById(Long id);
}
레이어드 아키텍처에 클린 아키텍처 적용
4-tier Layer + 클린 아키텍처 개념 => DIP + OCP 만족하는 구조 완성
Presentation Layer -> Application Layer -> Domain Layer <- Infra Layer 구조로 4-tier Architecture
MySQL DB에서 MongoDB로 변경
MongoDB Repository 구현체를 만들어 갈아끼운다. ( MySQL Repository 구현체 -> Mongo Repository 구현체)
public interface UserRepository {
...
}
//JpaRepository를 사용하는 MySQL Repository 구현체
class UserRepositoryImpl implements UserRepository {
private final UserJpaRepository userJpaRepository;
}
class UserJpaRepository extends JpaRepository<UserEntity, Long> {
}
//MongoRepository를 사용하는 Mongo DB Repository 구현체
class UserRepositoryImpl implements UserRepository {
private final UserMongoRepository userMongoRepository;
}
class UserMongoRepository extends MongoRepository<UserEntity, Long> {
}
레이어드 아키텍처란?
- Layered Architecture(계층 구조)는 소프트웨어를 여러 개의 계층으로 나누어 설계하는 구조.
- 각 계층은 특정한 역할과 책임을 가지며, 바로 아래 계층과만 상호작용한다.
- 일반적으로 사용하는 구조는 소프트웨어 애플리케이션을 3가지 계층으로 분리한 3-tier Architecture이다.
- Presentation Layer
- Business Layer(Domain Layer)
- Data Layer
- 3-tier에서 추가된 Persistence Layer에 인터페이스로 통신해 DIP를 적용한 4-tier Architecture
- Presentation Layer
- Business Layer
- Persistence Layer
- Data Layer
기존 레이어드 아키텍처의 문제
- 비즈니스(도메인) 로직이 핵심이 아니며, 보호받지 못한다.
- 상위 계층이 필요한 기능을 하위 계층에서 구현해서 전달하므로 하위 계층의 변경이 상위 계층에 영향을 줄 수 있다.
=> OCP 원칙에 위반하는 문제
OCP 원칙
(개방 폐쇄의 원칙)
소프트웨어 개체(클래스, 모듈, 함수 등등)는 확장에 대해 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다.
확장에 대해 열려있다 => 모듈의 동작을 확장할 수 있어야 한다. 애플리케이션의 요구사항에 맞게 새로운 동작이나 수정을 할 수 있어야 한다.
수정에 대해 닫혀있다 => 모듈의 소스코드를 수정하지 않아도, 모듈의 기능을 확장하거나 변경할 수 있어야 한다.
예시) JPA의 Repository Interface
- Spring Data JPA는 Repository Interface를 제공해 JpaRepository를 추상화한 인터페이스를 구현하여 OCP를 지킬 수 있다.
- 기본적으로 CRUD는 JpaRepository에서 제공해주기 때문에, 기존 코드 수정 없이 인터페이스에 선언만 해주면 된다.
- CRUD 외의 쿼리는 직접 쿼리로 만들어 확장할 수 있다.
클린 아키텍처란?
- 애플리케이션의 핵심은 비즈니스(도메인) 로직에 집중되어 있다.
- Interface Adapters에는 Controller 와 Use Case가 의존하는 추상화 된 Port 역할의 Repository Interface가 위치하고, 실제 Repository 구현체는 가장 바깥 원인 Frameworks&Drivers에 위치해 분리된다. => DIP 만족
- 새로운 Repository 구현체가 필요하면, 기존 코드는 수정하지 않고 인터페이스 구현체만 추가한다. => OCP 만족