개요
전에 클린 아키텍쳐에 대해 공부하고 나름 이해하고 앞으로 프로젝트를 만들 때, 잘 적용할 수 있다는 자신감이 있었는데, 실제로 프로젝트를 진행하면서 테스트 코드를 작성하는데 어려움을 느꼈다
아마도 이는 프로젝트가 진행되면서 클린하지 못하게 확장되고 있었기 때문이지 않을까?..
이 글에선 내가 어떤 부분에서 잘못 코드를 작성하고 있었는가에 대해 원인을 생각해 본다
우선 이에 앞서 클린 아키텍쳐에 대해 간략하게 정리하고, 현재 프로젝트를 어떤식으로 개선해 나갈지를 마무리로 정리한다
- 클린 아키텍쳐
- 문제점 분석과 개선 방향
클린 아키텍쳐
밥 아저씨의 블로그를 가보면 아래와 같이 클린 아키텍쳐 이미지를 볼 수 있다
각 구성요소들에 대해선 다음 글에 자세히 정리했다
각 레이어는 기능적 역할과 책임에 따라 논리적으로 묶인다
흔히 알려진 3 Layer Architecture(Presentation-Domain-Data)를 위의 아키텍쳐 이미지에서 표현하면 다음과 같다
클린 아키텍쳐에서 의존성은 항상 내부(핵심)에서 외부로 향하는 Dependency Rule을 따른다
View → ViewModel → UseCase → Data
하지만 실제로는 다음과 같이 Domain 레이어의 UseCase는 Data 레이어의 요소를 사용해야 하기에 Inversion Dependency가 필요하다
Data 레이어 요소의 Interface를 만들고, 이를 등록해 놓은 Container를 통해 UseCase에서 해당 요소를 주입받아 사용하면, Domain 레이어의 UseCase는 Dependency Rule을 위배하지 않으면서 그 밖의 레이어 요소를 이용할 수 있게 된다
그리고 이런 Container를 DIContainer(Dependency Injection Container)라고 한다
문제점 분석과 개선 방향
문제점
엔티티와 UI 모델 구분 미흡
현재 프로젝트에서는 엔티티와 UI 모델을 명확하게 구분하지 않고 사용하였다
UI 모델을 핵심 비즈니스 모델과 동일시하여 별도의 데이터 변환 과정 없이 처리한 점이 문제로 작용한다
엔티티는 다양한 플랫폼에서 공통적으로 활용되는 핵심 모델임을 인지해야 한다
핵심 엔티티를 우선 구상한 후 UI 모델을 엔티티의 변환으로 정의하면, 뷰에 특화된 구조를 마련하기 용이해진다
작은 앱에서는 큰 문제가 없겠으나, 앱의 규모가 커질수록 구분 미흡으로 인해 복잡도가 증가하고 확장성이 저해됨을 기억하자..
ViewModel 내 로직 분리 미흡
현재 프로젝트 코드에서 ViewModel은 DIContainer를 통해 다양한 Data 레이어 요소를 주입받아 비즈니스 로직과 UI 업데이트를 동시에 수행하고 있다
UI 업데이트와 비즈니스 로직의 명확한 분리가 이루어지지 않으면, 테스트 코드 작성 시 어려움이 발생한다..
Data 레이어에서의 의존성 관계
기존에는 Service라는 명칭 아래 무분별하게 요소를 생성하고 주입받아 처리하는 방식으로 운영되었다
특히, 하나의 서비스는 단순히 레포지터리만을 주입받거나, 특정 요소 하나만을 포함해야 한다고 생각했다
그러다 보니 특정 서비스를 활용하는 코드가 불필요하게 복잡해졌고, 여러 기능을 조합할 때 가독성이 떨어지는 문제가 발생했다
하지만 서비스 또한 다른 서비스를 주입받아 구성될 수 있음을 깨닫고 나니, 코드의 복잡도를 줄일 수 있는 방법이 보였다
추가적으로, Data 레이어를 보다 명확히 구분하기 위해 Infrastructure 레이어를 도입하는 것도 고려할 수 있다
이 레이어는 외부 라이브러리, API 클라이언트, 데이터베이스와 같은 요소들을 포함하며, 핵심 비즈니스 로직과의 분리를 명확히 하는 역할을 수행한다
개선방향
우선 비즈니스 핵심 모델인 엔티티를 정의하고, UI 모델을 엔티티의 변환으로 구성한다
이를 바탕으로 View 및 ViewModel의 구조를 재점검한다
Data 레이어의 의존성 관계를 명확하게 재정립하여 각 요소의 역할과 책임을 분리하고, ViewModel에서 사용할 UseCase를 정의하여 테스트 코드 작성의 용이성을 도모한다
ViewModel에서는 UseCase를 도입하여 비즈니스 로직과 UI 업데이트 로직을 명확히 분리한다
마무리
예전에도 클린 아키텍처 관련 글을 작성하면서 개념을 대략적으로 이해했었다
하지만 성능 최적화를 위해, 굳이 도메인 레이어를 두어 데이터 변환을 수행할 필요는 없다고 여겼다
엔티티와 모델을 하나로 사용하면 코드가 간결해지고, 별도의 변환 과정 없이 바로 활용할 수 있어 더 효율적이라고 생각했던 것이다
하지만 실제로 작은 규모의 앱에서는 이런 방식이 큰 문제를 일으키지 않았다 하지만 앱의 규모가 점점 커지고 유지보수와 테스트 코드 작성이 필요해지면서, 엔티티와 모델을 구분하지 않은 구조가 예상보다 큰 불편함을 초래한다는 것을 깨닫게 되었다
테스트를 위해 UI 모델을 조작하는 과정에서 비즈니스 로직과 UI 상태가 뒤섞이고, ViewModel이 불필요하게 복잡해지면서 변경이 어려워졌다
이제는 단순한 최적화보다는 장기적인 유지보수성과 확장성을 고려해야 할 시점이다
이 글에서 정리한 내용을 바탕으로 리팩토링을 진행한다면, 테스트 코드 작성의 어려움을 해소하고 전체 시스템의 구조적 안정성을 확보할 수 있을 것으로 기대된다
'회고록' 카테고리의 다른 글
주간 오류 해결 모음집(25.02.10-15) (1) | 2025.02.16 |
---|---|
MovieApp 회고록 (1) | 2024.05.31 |