회사에서 오픈소스 프로젝트를 기반으로 자사 솔루션을 개발하면서, 많은 프로젝트가 클린 아키텍처로 설계된 것을 발견했다. 그래서 애자일을 창시한 로버트 C. 마틴의 '클린 아키텍처'를 읽고 깊이 이해하려 노력했다. 이를 바탕으로 클린 아키텍처의 폴더 구조를 혼자 설계하게 되었고, 덕분에 업무 시 코드 구조를 빠르게 파악할 수 있게 되었다. 이 경험을 바탕으로 클린 아키텍처에 대해 공유하고자 한다.
로버트 C. 마틴의 클린아키텍처에서 서술하기를, 기능은 구조에 의지한다는것이다. 이 점을 이해하기 위해서는 코딩이라는 행위에 담겨져 있는 내재적 관점을 살펴 봐야 된다. 우리가 회사에 들어가서 하는 행위는 코딩 이다. 코딩의 목적성을 생각해 보면 다음과 같다.
코딩의 목적
컴퓨터에게 원하는 일(기능)을
시키기 위한것 이다.
즉, 우리는 코드를 읽고, 이해 하고, 코드 수정/ 추가 하는 일을 많이 하게 되는것이다. 따라서 위와 같은 행위들을 할때, 우리는 제일 먼저 프로젝트의 구조를 먼저 파악 하는것이 우선적이게 되며, 이는 아키텍처와도 연관성을 가지게 된다. 잘 정돈된 방에서 물건을 찾을때와, 어지럽혀진 방에서 물건을 찾을때 그 속도의 차이가 많이 나는것과 같은것 이다.
우리가 회사에 입사하는 행위는 회사에 이익을 창출하기 위해서 이다. 회사의 입장에서는 최소한의 인력으로 최대의 이익을 창출해야되며 이는 소프트웨어 아키텍처의 목표인 '필요한 시스템을 만들고 유지보수하는 데 투입되는 인력을 최소화하는 것'과 상응하게 된다.
로버트 C. 마틴이 제안한 방법으로 관심사를 확실히 분리하여 효율적으로 재사용성이 높은 컴포넌트를 구현 할수있게끔 만들수 있는 아키텍처 이다. 즉 최소한의 노력으로 최대의 효율을 얻게 해주는 것이다.
클린아키텍처 구조의 이해
나는 클린아키텍처의 구조를 벤다이어그램과 비슷하다고 생각하였고, 벤다이어그램 형식으로 이해하였다. 아래의 그림과 같이 a집합은 모든 집합의 구성요소에 대해 알고 있다. b집합은 c,d집합의 구성요소에 대하여 알고있지만, a집합의 전체 구성요소를 알수 없다. 이와 같은 원리로 의존성에 대입하게 되면 클린아키텍처는 가장 안쪽으로 들어갈수록 의존성이 줄어 들게 되며 가장 안쪽에 있는 엔티티 영역에는 의존성이 없는 구성요소만 남게 되는것 이다.
클린 아키텍처 구조
클린아키텍처의 구조는 아래 사진과 같다. 구조는 위에서 말한 벤다이어그램 구조와 비슷하지만 다른점이 있다. 가장 바깥쪽에 있는 영역과 안쪽의 영역(core영역)을 이어주는 adapter영역(controller)영역이 추가되는것이다. 각각의 역할들은 아래에 정리해 보았다.
나는 위에서 설명한 이론을 토대로 아래와 같이 폴더구조를 구성해 보았다. 클린 아키텍처는 정형화된 패턴이 없기 때문에 개발자에 따라 구조가 달라질수 있다.
core 영역
entities, useCasese 폴더가 위치한 영역.
entities: 의존성에 영향 받지 않는 영역으로 typescript의 type들을 정의한 폴더가 포함되어 있다.
useCasese: 어플리케이션의 비즈니스 로직을 수행하는 영역으로 api 통신하는데 있어 중간다리 하는 역할을 하는 폴더로 구분 지었다. 가장 바깥쪽 영역에 있는 db 영역에 종속되면 안된다. 예) 사용자 로그인, 로그아웃, 비밀번호 재설정 등과 같은 인증 관련 로직을 처리, 사용자 정보의 CRUD (생성, 읽기, 업데이트, 삭제) 작업을 처리
controller 영역
core 영역과 가장 바깥쪽 영역을 연결해 주는 영역
pages 폴더, custom hook 폴더를 이영역에 포함 시켰다.
가장 바깥쪽 영역 (웹, db, ui, 외부 인터페이스 등등)
세부 사항 영역으로 가장 변동이 심한 영역
infrastructure(파이어 베이스(db)) , interfaces폴더 (useCasese 폴더에 종속 하면서 변동이 있는 영역으로 설계 하였다.) tests 폴더(컴포넌트 및 공통 함수 테스트), components폴더(공통 컴포넌트)
├─ src
│ ├─ App.css
│ ├─ App.tsx
│ ├─ assets
│ │ └─ react.svg
│ ├─ components
│ │ └─ Button
│ │ └─ index.tsx
│ ├─ core
│ │ ├─ entities
│ │ │ └─ User.entites.ts
│ │ └─ useCases
│ │ ├─ authentication.ts
│ │ └─ userManagement.ts
│ ├─ hooks
│ ├─ index.css
│ ├─ infrastructure
│ │ ├─ firebase
│ │ │ └─ index.ts
│ │ ├─ services
│ │ │ └─ index.tsx
│ │ └─ utilities
│ │ └─ index.tsx
│ ├─ interfaces
│ │ ├─ api
│ │ │ └─ index.tsx
│ │ └─ store
│ │ └─ index.tsx
│ ├─ main.tsx
│ ├─ pages
│ │ └─ index.tsx
│ ├─ utils
│ └─ vite-env.d.ts
├─ tests