
약 1년 이상의 기간동안 회사에서 진행했던, 또는 사이드 프로젝트 팀에서 진행한 프로젝트들에 로버트 마틴의 클린 아키텍처를 적용해서 개발을 하고 있다.
사실 진행한 여러 프로젝트들 중 굳이 클린 아키텍처를 적용할 필요가 없는 것들도 있었지만, 클린 아키텍처의 장단점을 지속적으로 경험함으로써 클린 아키텍처라는 개념을 딱딱하게 가져가기보다는 핵심 개념을 개발 과정에서 체득하기 위함이였다.
그렇게, 클린 아키텍처는 파고 들어갈수록 어떤 구체화된 하나의 아키텍처가 아니라, 더 유연하고 확장성 있는 개발을 위한 추상적인 개념들의 집합체로써 받아들이게 되었다.
내가 클린 아키텍처를 좋아하는 이유도 어떤 고정적 구조를 가지는 이상적인 아키텍처라서 그렇다기보다는, 주니어 개발자인 나에게는 구조적 이점을 가져감으로써 소프트웨어의 장기적인 건강(유지보수성, 확장성)을 향상시키는 것에 대해 깨우쳐주었기 때문이다.
1. 구글의 권장 아키텍처 vs 클린 아키텍처

구글의 권장 아키텍처가 Domain 레이어를 사용하는 목적은, Ui 레이어와 Data 레이어의 상호작용을 최소화하고 재사용하기 위함이다. 게다가 Domain 레이어를 필요에 따라 "선택적"으로 사용하는 것을 권장한다.
반면 로버트 마틴의 클린 아키텍처는 Ui 계층과 Data 계층 간의 상호 작용이 Domain 계층에 의존해서 이루어진다.
구글 권장 아키텍처에서 계층 간 DIP를 적용해서 의존성을 역전시킴으로써 Domain 계층의 비즈니스 정책으로부터 모든 구체적인 사항들이 결정되는 구조로 변경했다.
나는 이에 대해서 "개념적인 요소를 구조적으로 녹여냈다"고 생각하는데, 이는 "개발자는 현실의 문제를 개발로써 풀어내는 사람"이라는 문장에 기인한다.
현실의 문제(비즈니스적 요구사항)는 추상적이며, 그것을 해결하는 방법은 구체적이기 때문이다.
A: 알림 페이지에서 (최신순, 오래된순으로 정렬)해서 (알림 목록)을 보여줘야 하는데, (알림을 클릭했는지 여부에 따라) 해당 알림이 (읽음, 안 읽음으로 상태가 변경)되어야 해요
위와 같은 요구사항을 풀어내야 한다고 가정해 보자.
개발자는 비즈니스 정책에 따라서 구체적인 구현을 결정하지, 개발자의 구현 방식이 비즈니스 정책에 영향을 미쳐서는 안된다.
하지만 이건 현실 세계에서 너무나 당연한 관계지만, 소프트웨어에서는 의존 관계에 따라 이 규약을 어기게 될 수 있다.
만약 비즈니스 정책들의 집합체인 Domain 계층이 data 계층이나 presentation 계층에 의존성을 가지게 된다면 이는 곧 비즈니스 정책이 외부 요인에 따라 변경될 수 있다는 것을 의미하기 때문이다.
2. 클린 아키텍처의 핵심

클린 아키텍처의 핵심은 "의존성 규칙"이다.
모듈 레벨에서 의존성을 엄격하게 분리하고, 클래스 레벨에서도 변동성이 적은 것에 의존하도록 구현함으로써 핵심 비즈니스 로직이 외부에 영향을 받지 않고, 결과적으로 유지보수성과 테스트용이성이 크게 향상된다.
이처럼 로버트 마틴의 클린 아키텍처는 현실 세계에서의 "비즈니스 정책과 그것을 풀어내는 방법"의 관계를 아키텍처 수준에 적용했다.
그래서 안드로이드에서 클린 아키텍처를 적용할 때, Domain 계층은 순수 Kotlin 모듈로 그 어떤 프레임워크나 외부 계층에 대한 의존성이 없는 고수준 모듈로 구성되어, data 관련 로직과 ui 관련 로직은 domain 계층에 의존적으로 구현된다.
3. Data 계층을 유연하게

초기 도입 단계에서는 보통 이 구조를 고정적으로 가져가는 경우가 많은데, 오늘은 내가 여러 프로젝트에 적용하며 유동
적으로 변경했던 것들에 대해 설명하고자 한다.
난 위 사진의 구조에서 Data 계층에 DataSource 인터페이스와 구현체를 추가한 형태로 적용했는데, 구현 과정에서 DataSource의 목적에 대해 생각해보게 되었다.
❓Repository 구현체의 책임의 범위
클린 아키텍처에서는 고수준 계층인 Domain 계층이 외부의 영향을 받지 않도록 DIP를 적용한다.
이를 위해 Domain 계층에서 Repository 인터페이스를 작성하고 Data 계층에서 구현체를 작성하는데,
이 구조에서 Repository 구현체의 역할은 Data 계층과 Domain 계층의 연결이라는 것에 집중해야 한다.
DataSource가 없으면 Repository 구현체에서 Api 호출이나 로컬 DB 접근 로직을 작성해야 하고,
이는 단일 책임 원칙을 위배하게 되어 유지보수성과 테스트 용이성을 저하시키는 구조가 된다.
❓로컬 DB를 사용하지 않는 경우
LocalDB를 사용하지 않는 경우에도 DataSource 계층을 추가해야 할까?
만약 DataStore를 사용한다고 해도 이 정도 리소스를 들일 필요가 있을까?
다른 데이터 호출 원천이 추가되지 않는다는 것이 거의 확실한 상황에서, DataSource를 사용하지 않는 것이 Repository의 유지보수성을 저하시킬까?
사실 데이터의 원천이 다양하지 않다면 리포지토리 패턴 자체의 사용 의미가 무색해지지만, 클린 아키텍처에서 리포지토리는 디자인 패턴으로서의 역할을 넘어 모듈간 의존성 역전의 매개체 역할도 수행하기 때문에 이 부분은 고려하지 않았다.

위와 같은 고려사항들이 많았지만, 클린 아키텍처를 적용한 첫 프로젝트에서는 DataSource를 두지 않고 Api 호출부를 Repository 구현체에 작성했다.
Domain 계층의 비즈니스 로직의 규모가 작은 경우에는 DataSource 추가보다는 Repository 구현체의 책임 범위를 확대하는 것이 더 적합하다고 판단했기 때문이다.
그리고 DataSource를 제외하면 유동적으로 도입할 수 있는 요소가 없기도 했다ㅎ
❓이런 결정은 적합했을까?
클린 아키텍처 책 또한 유연한 운용을 위해 개발자가 고려해야 할 여러 추상적인 내용들을 담고 있다.
그 중 하나를 빌려보자면,
아키텍처 경계는 어디에나 존재한다.
경계를 구현하려면 비용이 많이 들어가며, 경계가 무시되었다면 나중에 다시 추가하는 비용 또한 크다.
나는 data 계층 내부의 경계를 간소화시켰고, 이건 비즈니스 로직의 규모가 작은 애플리케이션에서
이미 클린 아키텍처를 적용한 것부터 오버 엔지니어링의 가능성이 있기 때문에 적용의 정도를 완화시키고자 결정했다.
4. Domain 계층을 유연하게, 해도 될까?
클린 아키텍처의 핵심은 고수준 계층인 Domain 계층이며, 이는 우리가 개발로써 풀어내야 할 비즈니스 로직들이 존재하는 계층이다.
비즈니스 로직의 규모에 따라 간소화시켜도 될까? 아니면 구글의 권장 아키텍처처럼, 클린 아키텍처도 Domain 계층을 선택적으로 도입해도 될까? 그럼 클린 아키텍처라고 부를 수 있을까?
그 중에서, Domain 계층의 컴포넌트 중에서 시스템의 규모에 따라 도입 여부를 유동적으로 가져갈 수 있는 요소는 내 개인적인 견해로는 UseCase가 유일했다.
❓UseCase는 선택적인 요소일까?
원론적으로는 클린 아키텍처의 UseCase는 핵심적인 요소이다. 비즈니스 로직의 최소 단위로, 사용자에게 제공되는 기능의 최소 단위를 캡슐화한다. Presentation 계층에서 Domain 계층의 비즈니스 로직을 사용할 때, UseCase를 통해 그 과정이 이루어진다.
책에서는 이를 “아키텍처는 시스템의 의도를 지원해야 한다"고 표현한다.
시스템의 행위를 명확히 정의하고 외부에 드러냄으로써 시스템의 의도를 아키텍처 수준에서 알아볼 수 있도록 해야 한다는 것이다. 그래서 UseCase는 시스템의 의도를 나타내며, 의도가 러츠하개 드로남으로써 문서의 역할도 수행하게 된다.
아키텍처 수준에서 시스템의 행위들을 확인하고, 그 행위들로써 이 시스템이 가지는 의도를 파악할 수 있기 때문이다.
❓시스템의 규모가 작은 경우
하지만 시스템의 규모가 작아 아키텍처 수준에서 의도를 표현하지 않아도 된다면 어떨까?
핵심적인 요소이고 좋은 아키텍처가 필수적으로 지원해야 하는 "시스템의 유스케이스"라고 해도,
도메인의 규모에 따라 "필수적"이지 않을 수도 있겠다는 생각을 해본다.
액터가 다양하지 않은 단순한 목적을 가지는 시스템은 UseCase를 도입함으로써 얻는 효과보다, 그로 인해 개발자가 추가적으로 리소스를 투자하는 것이 가져오는 디메리트가 더 클 가능성이 높기 때문이다.
이처럼 클린 아키텍처는 "핵심적인 추상적 개념"이 중요하며, 구현 시에 고려해야 할 것들은 그 개념들을 아키텍트가 자유롭게 선택할 수 있도록 가이드라인을 제시해준다.
개발자는 시스템의 개발 기간, 확장 가능성 등을 고려해서 유연하게 적용하면 된다.
하지만 주어진 개발 기간이 지나치게 짧거나 소규모 프로젝트(기능이 거의 없는)가 아니라면, 대부분 엄격하게 모든 요소들을 활용하는 편이 좋을 것이다.
시스템을 완성한 뒤에 유지보수성과 테스트용이성을 챙기고자 하면 초기 도입 비용보다 훨씬 비싼 값을 치뤄야 하기 때문이다.
⭐️ 잘하는 개발자에 대한 아티클을 읽었다
나는 정기적으로 여러 뉴스레터들을 읽는 걸 좋아한다.
Kotlin weekly, Android weekly, Medium, Flab을 구독해서 받아보고 있는데, 그 중에서 인상적인 아티클이 있었다.
언젠가는 일해보고 싶은 회사인 라인의 개발자 분이 작성하신 아티클이였는데, 제목이 인상적이었다.
보통은 “좋은 개발자란 무엇인가”에 대해서 고민하는 경우가 많은데, 이 분은 “잘하는 개발자란 어떤 개발자인가”라는 주제로 작성하셨다.
글에 따르면, “요구사항에 따라 힘을 빼거나 줄 줄 아는 개발자”가 잘하는 개발자라고 하셨다.
나는 여러 원리나 추상적인 개념들에 대한 호기심이 많은데, 정작 그런 공부를 하는 이유 또한 추상적이여서 이 공부의 구체적으로 어떤 도움이 될까?라는 고민을 계속 해오고 있었다.
그리고 그 답이 저 아티클에 적혀있었던 것 같다. 어떤 것을 사용하기만 할 줄 아는 사람은, 여러 상황에 대응하여 최선의 대처를 하기 어렵기때문이다.
포스팅을 다 작성했을 때쯤 저 아티클이 생각난 이유도 마찬가지이다. 힘을 빡 주기도, 다 빼보기도 해야 완급을 조절할 수 있다고 생각하기 때문이다.
'개발' 카테고리의 다른 글
클린 아키텍처와 SOLID (1) | 2024.07.04 |
---|---|
RxJava를 알아보자 (0) | 2022.10.12 |

약 1년 이상의 기간동안 회사에서 진행했던, 또는 사이드 프로젝트 팀에서 진행한 프로젝트들에 로버트 마틴의 클린 아키텍처를 적용해서 개발을 하고 있다.
사실 진행한 여러 프로젝트들 중 굳이 클린 아키텍처를 적용할 필요가 없는 것들도 있었지만, 클린 아키텍처의 장단점을 지속적으로 경험함으로써 클린 아키텍처라는 개념을 딱딱하게 가져가기보다는 핵심 개념을 개발 과정에서 체득하기 위함이였다.
그렇게, 클린 아키텍처는 파고 들어갈수록 어떤 구체화된 하나의 아키텍처가 아니라, 더 유연하고 확장성 있는 개발을 위한 추상적인 개념들의 집합체로써 받아들이게 되었다.
내가 클린 아키텍처를 좋아하는 이유도 어떤 고정적 구조를 가지는 이상적인 아키텍처라서 그렇다기보다는, 주니어 개발자인 나에게는 구조적 이점을 가져감으로써 소프트웨어의 장기적인 건강(유지보수성, 확장성)을 향상시키는 것에 대해 깨우쳐주었기 때문이다.
1. 구글의 권장 아키텍처 vs 클린 아키텍처

구글의 권장 아키텍처가 Domain 레이어를 사용하는 목적은, Ui 레이어와 Data 레이어의 상호작용을 최소화하고 재사용하기 위함이다. 게다가 Domain 레이어를 필요에 따라 "선택적"으로 사용하는 것을 권장한다.
반면 로버트 마틴의 클린 아키텍처는 Ui 계층과 Data 계층 간의 상호 작용이 Domain 계층에 의존해서 이루어진다.
구글 권장 아키텍처에서 계층 간 DIP를 적용해서 의존성을 역전시킴으로써 Domain 계층의 비즈니스 정책으로부터 모든 구체적인 사항들이 결정되는 구조로 변경했다.
나는 이에 대해서 "개념적인 요소를 구조적으로 녹여냈다"고 생각하는데, 이는 "개발자는 현실의 문제를 개발로써 풀어내는 사람"이라는 문장에 기인한다.
현실의 문제(비즈니스적 요구사항)는 추상적이며, 그것을 해결하는 방법은 구체적이기 때문이다.
A: 알림 페이지에서 (최신순, 오래된순으로 정렬)해서 (알림 목록)을 보여줘야 하는데, (알림을 클릭했는지 여부에 따라) 해당 알림이 (읽음, 안 읽음으로 상태가 변경)되어야 해요
위와 같은 요구사항을 풀어내야 한다고 가정해 보자.
개발자는 비즈니스 정책에 따라서 구체적인 구현을 결정하지, 개발자의 구현 방식이 비즈니스 정책에 영향을 미쳐서는 안된다.
하지만 이건 현실 세계에서 너무나 당연한 관계지만, 소프트웨어에서는 의존 관계에 따라 이 규약을 어기게 될 수 있다.
만약 비즈니스 정책들의 집합체인 Domain 계층이 data 계층이나 presentation 계층에 의존성을 가지게 된다면 이는 곧 비즈니스 정책이 외부 요인에 따라 변경될 수 있다는 것을 의미하기 때문이다.
2. 클린 아키텍처의 핵심

클린 아키텍처의 핵심은 "의존성 규칙"이다.
모듈 레벨에서 의존성을 엄격하게 분리하고, 클래스 레벨에서도 변동성이 적은 것에 의존하도록 구현함으로써 핵심 비즈니스 로직이 외부에 영향을 받지 않고, 결과적으로 유지보수성과 테스트용이성이 크게 향상된다.
이처럼 로버트 마틴의 클린 아키텍처는 현실 세계에서의 "비즈니스 정책과 그것을 풀어내는 방법"의 관계를 아키텍처 수준에 적용했다.
그래서 안드로이드에서 클린 아키텍처를 적용할 때, Domain 계층은 순수 Kotlin 모듈로 그 어떤 프레임워크나 외부 계층에 대한 의존성이 없는 고수준 모듈로 구성되어, data 관련 로직과 ui 관련 로직은 domain 계층에 의존적으로 구현된다.
3. Data 계층을 유연하게

초기 도입 단계에서는 보통 이 구조를 고정적으로 가져가는 경우가 많은데, 오늘은 내가 여러 프로젝트에 적용하며 유동
적으로 변경했던 것들에 대해 설명하고자 한다.
난 위 사진의 구조에서 Data 계층에 DataSource 인터페이스와 구현체를 추가한 형태로 적용했는데, 구현 과정에서 DataSource의 목적에 대해 생각해보게 되었다.
❓Repository 구현체의 책임의 범위
클린 아키텍처에서는 고수준 계층인 Domain 계층이 외부의 영향을 받지 않도록 DIP를 적용한다.
이를 위해 Domain 계층에서 Repository 인터페이스를 작성하고 Data 계층에서 구현체를 작성하는데,
이 구조에서 Repository 구현체의 역할은 Data 계층과 Domain 계층의 연결이라는 것에 집중해야 한다.
DataSource가 없으면 Repository 구현체에서 Api 호출이나 로컬 DB 접근 로직을 작성해야 하고,
이는 단일 책임 원칙을 위배하게 되어 유지보수성과 테스트 용이성을 저하시키는 구조가 된다.
❓로컬 DB를 사용하지 않는 경우
LocalDB를 사용하지 않는 경우에도 DataSource 계층을 추가해야 할까?
만약 DataStore를 사용한다고 해도 이 정도 리소스를 들일 필요가 있을까?
다른 데이터 호출 원천이 추가되지 않는다는 것이 거의 확실한 상황에서, DataSource를 사용하지 않는 것이 Repository의 유지보수성을 저하시킬까?
사실 데이터의 원천이 다양하지 않다면 리포지토리 패턴 자체의 사용 의미가 무색해지지만, 클린 아키텍처에서 리포지토리는 디자인 패턴으로서의 역할을 넘어 모듈간 의존성 역전의 매개체 역할도 수행하기 때문에 이 부분은 고려하지 않았다.

위와 같은 고려사항들이 많았지만, 클린 아키텍처를 적용한 첫 프로젝트에서는 DataSource를 두지 않고 Api 호출부를 Repository 구현체에 작성했다.
Domain 계층의 비즈니스 로직의 규모가 작은 경우에는 DataSource 추가보다는 Repository 구현체의 책임 범위를 확대하는 것이 더 적합하다고 판단했기 때문이다.
그리고 DataSource를 제외하면 유동적으로 도입할 수 있는 요소가 없기도 했다ㅎ
❓이런 결정은 적합했을까?
클린 아키텍처 책 또한 유연한 운용을 위해 개발자가 고려해야 할 여러 추상적인 내용들을 담고 있다.
그 중 하나를 빌려보자면,
아키텍처 경계는 어디에나 존재한다.
경계를 구현하려면 비용이 많이 들어가며, 경계가 무시되었다면 나중에 다시 추가하는 비용 또한 크다.
나는 data 계층 내부의 경계를 간소화시켰고, 이건 비즈니스 로직의 규모가 작은 애플리케이션에서
이미 클린 아키텍처를 적용한 것부터 오버 엔지니어링의 가능성이 있기 때문에 적용의 정도를 완화시키고자 결정했다.
4. Domain 계층을 유연하게, 해도 될까?
클린 아키텍처의 핵심은 고수준 계층인 Domain 계층이며, 이는 우리가 개발로써 풀어내야 할 비즈니스 로직들이 존재하는 계층이다.
비즈니스 로직의 규모에 따라 간소화시켜도 될까? 아니면 구글의 권장 아키텍처처럼, 클린 아키텍처도 Domain 계층을 선택적으로 도입해도 될까? 그럼 클린 아키텍처라고 부를 수 있을까?
그 중에서, Domain 계층의 컴포넌트 중에서 시스템의 규모에 따라 도입 여부를 유동적으로 가져갈 수 있는 요소는 내 개인적인 견해로는 UseCase가 유일했다.
❓UseCase는 선택적인 요소일까?
원론적으로는 클린 아키텍처의 UseCase는 핵심적인 요소이다. 비즈니스 로직의 최소 단위로, 사용자에게 제공되는 기능의 최소 단위를 캡슐화한다. Presentation 계층에서 Domain 계층의 비즈니스 로직을 사용할 때, UseCase를 통해 그 과정이 이루어진다.
책에서는 이를 “아키텍처는 시스템의 의도를 지원해야 한다"고 표현한다.
시스템의 행위를 명확히 정의하고 외부에 드러냄으로써 시스템의 의도를 아키텍처 수준에서 알아볼 수 있도록 해야 한다는 것이다. 그래서 UseCase는 시스템의 의도를 나타내며, 의도가 러츠하개 드로남으로써 문서의 역할도 수행하게 된다.
아키텍처 수준에서 시스템의 행위들을 확인하고, 그 행위들로써 이 시스템이 가지는 의도를 파악할 수 있기 때문이다.
❓시스템의 규모가 작은 경우
하지만 시스템의 규모가 작아 아키텍처 수준에서 의도를 표현하지 않아도 된다면 어떨까?
핵심적인 요소이고 좋은 아키텍처가 필수적으로 지원해야 하는 "시스템의 유스케이스"라고 해도,
도메인의 규모에 따라 "필수적"이지 않을 수도 있겠다는 생각을 해본다.
액터가 다양하지 않은 단순한 목적을 가지는 시스템은 UseCase를 도입함으로써 얻는 효과보다, 그로 인해 개발자가 추가적으로 리소스를 투자하는 것이 가져오는 디메리트가 더 클 가능성이 높기 때문이다.
이처럼 클린 아키텍처는 "핵심적인 추상적 개념"이 중요하며, 구현 시에 고려해야 할 것들은 그 개념들을 아키텍트가 자유롭게 선택할 수 있도록 가이드라인을 제시해준다.
개발자는 시스템의 개발 기간, 확장 가능성 등을 고려해서 유연하게 적용하면 된다.
하지만 주어진 개발 기간이 지나치게 짧거나 소규모 프로젝트(기능이 거의 없는)가 아니라면, 대부분 엄격하게 모든 요소들을 활용하는 편이 좋을 것이다.
시스템을 완성한 뒤에 유지보수성과 테스트용이성을 챙기고자 하면 초기 도입 비용보다 훨씬 비싼 값을 치뤄야 하기 때문이다.
⭐️ 잘하는 개발자에 대한 아티클을 읽었다
나는 정기적으로 여러 뉴스레터들을 읽는 걸 좋아한다.
Kotlin weekly, Android weekly, Medium, Flab을 구독해서 받아보고 있는데, 그 중에서 인상적인 아티클이 있었다.
언젠가는 일해보고 싶은 회사인 라인의 개발자 분이 작성하신 아티클이였는데, 제목이 인상적이었다.
보통은 “좋은 개발자란 무엇인가”에 대해서 고민하는 경우가 많은데, 이 분은 “잘하는 개발자란 어떤 개발자인가”라는 주제로 작성하셨다.
글에 따르면, “요구사항에 따라 힘을 빼거나 줄 줄 아는 개발자”가 잘하는 개발자라고 하셨다.
나는 여러 원리나 추상적인 개념들에 대한 호기심이 많은데, 정작 그런 공부를 하는 이유 또한 추상적이여서 이 공부의 구체적으로 어떤 도움이 될까?라는 고민을 계속 해오고 있었다.
그리고 그 답이 저 아티클에 적혀있었던 것 같다. 어떤 것을 사용하기만 할 줄 아는 사람은, 여러 상황에 대응하여 최선의 대처를 하기 어렵기때문이다.
포스팅을 다 작성했을 때쯤 저 아티클이 생각난 이유도 마찬가지이다. 힘을 빡 주기도, 다 빼보기도 해야 완급을 조절할 수 있다고 생각하기 때문이다.
'개발' 카테고리의 다른 글
클린 아키텍처와 SOLID (1) | 2024.07.04 |
---|---|
RxJava를 알아보자 (0) | 2022.10.12 |