|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "[ADR][가상] 아키텍처 의사 결정 기록: 도메인 단위의 API 코드를 모듈로 분리하기" |
| 4 | +tags: [ADR] |
| 5 | +--- |
| 6 | +{% include JB/setup %} |
| 7 | + |
| 8 | +Contents: |
| 9 | + |
| 10 | +* [상태](#status) |
| 11 | +* [배경](#context) |
| 12 | +* [결정](#decisions) |
| 13 | + * [이유](#rationale) |
| 14 | +* [결과](#consequences) |
| 15 | +* [예상되는 리스크 및 대응책](#risks_and_mitigation) |
| 16 | +* [구현 계획](#Implementation_Plan) |
| 17 | +* [비용 및 이점](#Costs_and_Benefits) |
| 18 | +* [결정 후 모니터링](#Monitoring_after_Decision) |
| 19 | + |
| 20 | +## 도메인 단위의 API 코드를 모듈로 분리하기 |
| 21 | + |
| 22 | +작성일 : 2025-09-16 |
| 23 | + |
| 24 | +작성자 : 안정민 |
| 25 | + |
| 26 | +<h2 id="status">상태</h2> |
| 27 | + |
| 28 | +* 수락됨(Accepted) |
| 29 | + |
| 30 | +<h2 id="context">배경</h2> |
| 31 | + |
| 32 | +현재 우리 앱의 모든 도메인(예: 사용자, 상품, 주문) 네트워크 API는 단일 모듈 내에서 관리되고 있습니다. 초기에는 모든 API를 한 곳에서 관리하여 의존성 추가가 간편하다는 장점이 있었습니다. |
| 33 | + |
| 34 | +하지만 서비스 규모가 확장되고 API의 수가 급격히 증가함에 따라 다음과 같은 문제들이 발생하고 있습니다. |
| 35 | + |
| 36 | +* **빌드 시간 증가**: 프로젝트 규모가 커지면서 전체 API 모듈을 빌드하는 데 소요되는 시간이 증가했습니다. 특정 기능 개발 시 일부 API만 필요함에도 불구하고, 전체 코드를 컴파일해야 하므로 개발 생산성이 저하되고 있습니다. |
| 37 | + |
| 38 | +* **강한 결합도(High Coupling)**: 특정 도메인에서만 사용되어야 할 모델(Response DTO 등)이 다른 도메인에서 무분별하게 참조되거나, 공통 모델 수정 시 연관 없는 도메인까지 영향을 받는 사례가 발생하고 있습니다. 이는 코드의 예측 가능성을 떨어트리고 유지보수 비용을 증가시키는 주요 원인입니다. |
| 39 | + |
| 40 | +* **낮은 응집도(Low Cohesion)**: 단일 모듈 내에 여러 도메인이 혼재하여 관련 없는 코드들이 물리적으로 함께 위치하게 됩니다. 이로 인해 특정 도메인의 기능을 파악하고 수정하기가 점점 더 어려워지고 있습니다. |
| 41 | + |
| 42 | +이러한 문제들은 결국 개발 속도 저하와 잠재적인 버그 발생 가능성 증가로 이어져, 프로젝트의 장기적인 확장성과 안정성을 저해하고 있습니다. |
| 43 | + |
| 44 | +<h2 id="decisions">결정</h2> |
| 45 | + |
| 46 | +**하나의 프로젝트(NetworkFeatureAPI)에서 각 도메인별 API 코드를 별도의 프레임워크 타겟(NetworkDomainAPI)으로 분리하여 모듈화합니다.** |
| 47 | + |
| 48 | +예를 들어, 기존 NetworkAPI 모듈을 UserAPI, ProductAPI, OrderAPI 등과 같이 도메인 경계를 기준으로 명확하게 분리합니다. 각 Feature 모듈은 자신이 직접적으로 사용하는 API 모듈에만 의존하게 됩니다. 또한, 개수가 적은 도메인 API는 MiscAPI 모듈로 통합 관리합니다. |
| 49 | + |
| 50 | +<h4 id="rationale">결정 이유</h4> |
| 51 | + |
| 52 | +이 아키텍처 결정의 핵심적인 이유는 '배경' 섹션에서 제기된 빌드 시간, 결합도, 응집도 문제를 근본적으로 해결하기 위함입니다. |
| 53 | + |
| 54 | +* **독립적인 빌드**: 각 도메인 API를 별도의 프레임워크로 분리하면, 특정 기능을 개발할 때 관련된 모듈만 선택적으로 빌드할 수 있습니다. 이는 전체 프로젝트의 증분 빌드 시간을 획기적으로 단축시켜 개발 사이클을 가속화합니다. |
| 55 | + |
| 56 | +* **명확한 경계 설정**: 모듈화는 각 도메인 간에 물리적인 경계를 설정합니다. Swift의 접근 제어(Access Control)를 통해 모듈 외부로 노출할 코드를 명시적으로 관리할 수 있으며, 이는 다른 도메인의 모델이나 로직을 부주의하게 참조하는 것을 원천적으로 방지하여 결합도를 낮춥니다. |
| 57 | + |
| 58 | +* **관심사의 분리**: 하나의 모듈은 하나의 도메인에만 집중하게 됩니다. 이를 통해 관련 있는 코드들이 한곳에 모여 응집도가 높아지고, 코드의 가독성, 유지보수성, 그리고 테스트 용이성이 향상됩니다. |
| 59 | + |
| 60 | +<h2 id="consequences">결과</h2> |
| 61 | + |
| 62 | +이 결정을 통해 다음과 같은 긍정적, 부정적 결과를 예상합니다. |
| 63 | + |
| 64 | +* **긍정적 영향** |
| 65 | + * **빌드 시간 단축**: Feature 개발 시 필요한 도메인 API 모듈만 빌드하게 되므로, 전체 프로젝트의 컴파일 시간이 의미 있게 감소합니다. |
| 66 | + |
| 67 | + * **의존성 관리 개선**: 모듈 간 접근 제어를 통해 불필요한 상호 참조를 원천적으로 차단할 수 있습니다. 이는 코드의 결합도를 낮추고, 각 모듈의 독립성을 보장합니다. |
| 68 | + |
| 69 | + * **코드 재사용성 및 응집도 향상**: 각 도메인 API 모듈 내에서 관련된 enum, struct, 유틸리티 등을 함께 관리하게 되므로 코드의 응집도가 높아지고, 해당 도메인 내에서의 재사용성이 극대화됩니다. |
| 70 | + |
| 71 | + * **명확한 책임 분리**: 각 팀이나 개발자가 특정 도메인 API에 대한 소유권을 가지고 책임감 있게 코드를 관리할 수 있는 환경이 조성됩니다. |
| 72 | + |
| 73 | +* **부정적 영향** |
| 74 | + * **초기 설정 및 마이그레이션 비용**: 기존 코드를 새로운 모듈 구조로 분리하고, CI/CD 파이프라인을 수정하는 데 초기 리소스가 투입됩니다. |
| 75 | + |
| 76 | + * **API 탐색의 어려움**: API 모듈의 수가 증가함에 따라, 신규 입사자나 다른 도메인 개발자가 특정 API가 어느 모듈에 위치하는지 파악하는 데 약간의 시간이 걸릴 수 있습니다. |
| 77 | + |
| 78 | +<h2 id="risks_and_mitigation">예상되는 리스크 및 대응책</h2> |
| 79 | + |
| 80 | +* **리스크 1**: 여러 도메인에서 공통으로 사용해야 하는 모델(예: AccountInfo, UserInfo) 처리의 어려움. |
| 81 | + * **대응책**: APICommon 또는 APIShareDTO와 같은 공용 모듈을 별도로 생성합니다. 이 모듈에 여러 도메인에서 공유되어야 하는 최소한의 데이터 모델과 로직을 배치하여 중복을 방지합니다. |
| 82 | + |
| 83 | +* **리스크 2**: 모듈 수가 많아져 API를 찾기 어려워지는 문제 (언급된 부정적 영향). |
| 84 | + * **대응책**: |
| 85 | + * 명확한 네이밍 컨벤션 수립: 모듈과 파일, 타입 이름에 대한 명확한 규칙을 정립합니다. (예: \[DomainName\]API, \[DomainName\]Request) |
| 86 | + * API 모듈 맵(Map) 문서화: 어떤 모듈이 어떤 책임을 가지는지 정리한 간단한 문서를 Confluence 등에 작성하여 팀 전체가 참고할 수 있도록 합니다. |
| 87 | + |
| 88 | +* **리스크 3**: 순환 참조(Circular Dependency) 발생 가능성. |
| 89 | + * **대응책**: 모듈 설계 시 의존성 방향을 단방향(예: Feature -> API)으로 유지하는 원칙을 수립하고, 코드 리뷰 시 이를 철저히 검토합니다. |
| 90 | + |
| 91 | +<h2 id="Implementation_Plan">구현 계획</h2> |
| 92 | + |
| 93 | +본 계획은 점진적으로 진행하여 안정성을 확보합니다. |
| 94 | + |
| 95 | +* **1단계: 기반 설정** |
| 96 | + * APICommon 공용 모듈 타겟 생성 및 공통 모델 이전. |
| 97 | + * 새로운 API 모듈을 위한 Xcode 프로젝트 템플릿 및 가이드라인 문서 작성. |
| 98 | + * CI/CD 설정에 신규 모듈 타겟을 추가하는 방식 테스트. |
| 99 | +* **2단계: 파일럿 마이그레이션** |
| 100 | + * 의존성이 비교적 적고 영향 범위가 작은 1~2개의 도메인(예: NoticeAPI)을 선정하여 신규 모듈로 분리합니다. |
| 101 | + * 이 과정에서 발생하는 문제점을 기록하고 해결책을 가이드라인에 반영합니다. |
| 102 | +* **3단계: 전체 마이그레이션** |
| 103 | + * 나머지 도메인들을 병렬적으로 또는 순차적으로 신규 모듈로 이전합니다. |
| 104 | + * 각 Feature 모듈의 의존성을 기존 단일 모듈에서 신규 도메인 모듈들로 교체합니다. |
| 105 | +* **4단계: 안정화 및 정리** |
| 106 | + * 기존의 단일 NetworkAPI 모듈을 완전히 제거합니다. |
| 107 | + * 최종적으로 빌드 시간 및 프로젝트 구조 개선 효과를 측정하고 회고를 진행합니다. |
| 108 | + |
| 109 | +<h2 id="Costs_and_Benefits">비용 및 이점</h2> |
| 110 | + |
| 111 | +**비용** |
| 112 | + * 개발 시간: 마이그레이션 및 안정화 기간 동안 투입되는 개발 리소스. |
| 113 | + * 학습 곡선: 팀원들이 새로운 모듈 구조와 의존성 규칙에 적응하는 데 필요한 시간. |
| 114 | + |
| 115 | +**이점** |
| 116 | + * **생산성 향상**: 빌드 시간 단축으로 인해 개발 및 테스트 주기가 빨라져 장기적인 개발 생산성이 크게 향상됩니다. |
| 117 | + * **품질 향상**: 낮은 결합도는 코드 변경 시 사이드 이펙트를 줄여주어 앱의 안정성을 높입니다. |
| 118 | + * **확장성 확보**: 신규 도메인 추가 시 독립된 모듈로 개발할 수 있어, 프로젝트가 커져도 복잡도가 급격히 증가하는 것을 방지합니다. |
| 119 | + |
| 120 | +<h2 id="Monitoring_after_Decision">결정 후 모니터링</h2> |
| 121 | + |
| 122 | +이 결정의 성공 여부를 측정하기 위해 다음 지표를 지속적으로 모니터링합니다. |
| 123 | +* **정량적 지표**: |
| 124 | + * **클린 빌드 시간**: 마이그레이션 전후의 Xcode 클린 빌드 시간을 측정하여 비교. |
| 125 | + * **증분 빌드 시간**: 주 기능 개발 시 코드 변경 후 소요되는 빌드 시간을 측정. |
| 126 | +* **정성적 지표**: |
| 127 | + * **개발자 만족도 설문**: 분기별로 새로운 구조에 대한 개발자들의 만족도와 불편 사항에 대한 설문을 진행. |
| 128 | + * **코드 리뷰**: 코드 리뷰 시 불필요한 의존성 추가나 아키텍처 원칙 위반 사례가 줄어드는지 확인. |
0 commit comments