클린 아키텍처 설명 따라 직접 구현해보기
개요
지난 글에서 클린 아키텍처에 대한 내용을 다뤘었는데 아래와 같은 시나리오가 나왔었다.
전형적인 시나리오
아래 이미지의 다이어그램은 웹 기반 자바 시스템의 전형적인 시나리오를 보여준다.
- 웹 서버는 사용자로부터 입력 데이터를 모아서 좌측 상단의 Controller로 전달한다.
- Controller는 데이터를 평범한 자바 객체(POJO)로 묶은 후, InputBoundary 인터페이스를 통해 UseCaseInteractor로 전달한다. UseCaseInteractor는 이 데이터를 해석해서 Entities가 어떻게 동작할지를 제어하는데 사용한다.
- UseCaseInteractor는 DataAccessInterface를 사용하여 Entities가 사용할 데이터를 데이터베이스에서 불러와서 메모리로 로드한다.
- Entities가 완성되면, UseCaseInteractor는 Entities로 부터 데이터를 모아서 또 다른 평범한 자바 객체인 OutputData 를 구성한다.
- 그리고 나서 OutputData는 OutputBoundary 인터페이스를 통해 Presenter로 전달된다.
글만 읽었을 때 대략적인 이해는 되었지만 실제로 구현했을 때는 어떤 느낌일까 라는 생각이 들어 직접 구현을 해보았다.
구현
구현 코드는 github에 clean-architecture-impl 레포지토리를 만들어 올려두었다.
최종 프로젝트 구조는 다음과 같다.
email 주소를 통해서 DB에서 일치하는 User를 조회해오고, OutputData로 변환하면서 User의 name 정보만 가져오는 예시를 작성해보았다.
물론 데이터베이스는 실제 데이터베이스를 사용하지 않았고 아래와 같이 샘플 데이터를 만들어서 filter를 통해 데이터를 추출하게 처리하였다.
private final List<User> users = List.of(
new User("dev@jonghoonpark.com", "박종훈"),
new User("thanos@jonghoonpark.com", "타노스"),
new User("joker@jonghoonpark.com", "조커")
);
@Override
public User fetchDataFromDatabase(String userEmail) {
return Objects.requireNonNull(users.stream().filter((user) -> user.getEmail().equals(userEmail)).findFirst().orElse(null));
}
WebServer 역할을 한 main문의 코드는 다음과 같다.
public class WebServer {
public static void main(String[] args) {
UserDataAccessInterface dataAccess = new UserDataAccess();
UserUseCaseInteractor userUseCaseInteractor = new UserUseCaseInteractor(dataAccess);
UserController userController = new UserController(userUseCaseInteractor);
OutputBoundary presenter = new UserPresenter();
OutputData outputData = userController.findUsername("dev@jonghoonpark.com");
presenter.present(outputData);
}
}
아키텍처들의 목표는 관심사의 분리(separation of concerns)이다.
따라서 핵심은 직접 호출을 하게 하는 것이 아니라 인터페이스를 통해서 호출을 해야한다는 것이다. 직접 호출해 버리면 의존성 규칙을 위반하게 되버린다.
이해가 잘 안된다면 이전 글을 다시 보고오자.
나머지 코드들은 크게 복잡하지도 않고 위에 있는 레포지토리에서 볼 수 있으므로 구체적으로 적지는 않는다.
결론
구현을 해보니 프로젝트 구조가 Spring 비슷해진 것 같다는 생각이 들었다.
프레임워크의 도움 없이 프로젝트 아키텍처 구조를 작성해보았다는 것에 의의가 있는 것 같다.
구현한 코드를 보면서 당분간 여러번 생각해봐야겠다.