-
Notifications
You must be signed in to change notification settings - Fork 1
프로젝트 구조 개선
Choi Jeongmin edited this page Jan 23, 2025
·
2 revisions
기존 프로젝트 폴더 구조는 Feature-Sliced Design를 어느정도 차용한 상태로 진행했으나, 확장 과정에서 복잡해지면서 유지보수 및 확장성이 저하되는 문제가 발생했습니다.
이를 해결하기 위해 FSD를 엄격하게 적용하고, 역할과 책임에 따라 폴더 구조를 재설계함으로써 높은 응집도와 낮은 결합도를 달성하였습니다.
이 문서는 프로젝트 구조 개선 과정을 기록하고, 이를 통해 얻은 인사이트와 성과를 공유합니다.
-
프로젝트 확장으로 인한 복잡성 증가
프로젝트가 빠르게 성장하면서, 기존 폴더 구조는 점차 모호해지고 중복되는 기능이나 위치가 생기는 문제가 발생했습니다.
-
일관성 부족
유사한 기능임에도 폴더 위치나 구조가 상이해 혼동이 잦았고, 유지보수가 어려워졌습니다.
-
역할 구분 모호
동일하거나 유사한 기능이 여러 군데에서 산발적으로 구현되어, 재사용성이 낮고 코드 충돌 가능성이 높았습니다.
-
효율성 및 확장성 확보
기능을 분담하고 빠른 대응이 가능한 구조가 필요하다고 판단했습니다. 특히 앞으로 추가될 AI 기능이나 요구사항 변경에 유연하게 대응하기 위한 구조적 정비가 절실했습니다.
- 기존 구조
- 장점: 초기 개발 속도가 빠르고, 작게 시작할 때는 직관적
- 단점: 기능별로 모듈화되지 않고 레이어가 뒤섞여, 확장 시 충돌 잦음
- FSD 구조
- 장점: 기능(Feature) 단위로 모델, UI, 비즈니스 로직(api 등)을 엄격히 구분해 높은 응집도와 낮은 결합도 달성
- 단점: 구조적 설계가 미흡할 경우 오히려 복잡도가 증가할 우려가 있음
- 레이어드 아키텍처를 적용해 데이터(layer)와 행위(기능) 레이어를 분리하고, 이를 상위에서 조합하는 방식을 채택했습니다.
- 예시
- app 레이어: 앱 전역 설정 (라우팅, 전역 상태 등)
- entities 레이어: 핵심 엔티티의 데이터 모델과 UI
- features 레이어: 기능(Feature) 별 세부 구현(모델, api, ui)
- shared 레이어: 공통 모듈 및 재사용 가능한 컴포넌트
- 폴더 구조 분석: 기존에
components
,features
,pages
등이 중첩되면서, 어디에 어떤 책임이 있는지 모호하다고 판단. - 재설계 원칙
- 역할 단위 분리
- 규칙의 일관성 유지
- 기능 내 완결성
아래는 개선된 구조 예시입니다.
perl
복사
apps/client/src/
├── app
│ └── config
├── entities
│ └── session
│ ├── model
│ └── ui
├── features
│ ├── auth
│ │ ├── api
│ │ ├── model
│ │ └── ui
│ ├── close-question
│ │ └── api
... 생략 ...
│ ├── terminate-session
│ │ ├── api
│ │ └── ui
│ └── update-session-host
│ └── api
├── pages
│ ├── home
│ │ └── ui
│ ├── my
│ │ └── ui
│ └── session
│ ├── model
│ └── ui
├── routes
│ └── session
│ └── $sessionId
│ └── $questionId
├── shared
│ ├── model
│ │ └── validation-status
│ └── ui
│ ├── InputField
│ ├── button
│ ├── modal
│ └── toast
│ ├── model
│ └── ui
└── widgets
├── chatting-list
├── header
├── question-list
│ └── ui
└── reply-list
└── ui
-
app
: 앱을 실행하는 모든 것 - 라우팅, 진입점, 전역 스타일, 프로바이더. -
pages
: 전체 페이지 또는 중첩 라우팅에서 페이지의 주요 부분. -
widgets
: 독립적으로 작동하는 대규모 기능 또는 UI 컴포넌트, 보통 하나의 완전한 기능. -
features
: 서비스 전반에 걸쳐 재사용되는 기능 구현체로, 사용자에게 실질적인 비즈니스 가치를 제공하는 동작. -
entities
: 프로젝트가 다루는 비즈니스 엔티티. -
shared
: 재사용 가능한 기능, 특히 프로젝트/비즈니스의 특성과 분리되어 있을 때.
- 폴더 이동: 기존
components
와features
폴더에 산재해있던 로직을 FSD 구조로 재배치. - 중복 제거: 여러 폴더에 흩어져 있던 모달, 토스트 등 공통 컴포넌트를
shared/ui
로 통합. - UI/Model/API 분리: 기능 내에서 어떤 부분이 비즈니스 로직(model), 네트워크 통신(api), UI인지 명확히 분리해 가독성 개선.
- 유지보수성 향상
- 기능을 기준으로 코드를 분리함으로써, 해당 기능에 필요한 로직이 한 곳에 모이도록 구조화되었습니다.
- 따라서, 문제가 발생했을 때 어디서 해결해야 하는지가 명확해져, 디버깅과 수정 작업이 훨씬 수월해질 것으로 기대합니다.
- 높은 응집도와 낮은 결합도
- 각 기능 내에서 관련된 로직만 모아두어 응집도가 높아졌으며, 다른 기능과의 의존성은 필요한 최소 수준으로 관리됩니다.
- 기능 변경이 다른 부분에 미치는 영향을 최소화하여 유지보수 부담을 줄였습니다.
- 확장성 및 규모 확장 용이
- 새 기능을 추가할 때 독립된 슬라이스를 생성하면 되므로, 기존 코드에 대한 대규모 수정 없이 기능 확장이 가능합니다.
- 기능을 나누어 개발하기에도 용이해 충돌이 줄어들고, 확장 요구 사항에 유연하게 대응할 수 있습니다.
- 예컨대, AI 기능을 새롭게 추가해야 할 때도 기존 코드를 대폭 수정할 필요 없이 손쉽게 확장할 수 있습니다.
- 코드 가독성 및 구조화 향상
- 기능 별로 코드가 명확히 분리되어 있어 설계 의도가 직관적으로 드러납니다.
- 재사용성 증대
-
shared
레이어에 공통 로직(예: 유틸 함수, 공통 컴포넌트 등)을 모아놓아, 여러 기능에서 손쉽게 활용할 수 있습니다. - 반복되는 코드를 각 기능으로부터 분리함으로써, 관리 효율이 높아지고 중복 구현을 예방합니다.
-