크루끼리 신나는 밤을 보냈다~
MT 이후로 처음인데 너무 즐겁게 놀았다 😊🎶
오늘 아침에 테오의 폴더구조의 변화로 이해하는 프론트엔드 멘탈모델 변천사 글을 읽고, 그동안 은은하게 느껴왔던 폴더 구조의 불편함과 그 이유가 조금 명확해졌다.
지금까지는 역할 중심의 구조(components, hooks, services...)로 프로젝트를 구성해왔는데, 미션이 점점 복잡해지고 커지면서 다음과 같은 문제를 마주하게 됐다.
/src
├── api # API 호출
├── assets # 이미지 등 정적 리소스
├── components
│ ├── common # 공통 UI 컴포넌트
│ ├── layout # 레이아웃 관련 컴포넌트
│ └── shoppingCart # 장바구니 도메인 컴포넌트
├── contexts # Context API 상태관리 훅
├── hooks # 커스텀 훅
├── pages # 전체 페이지
├── router.tsx # 경로 설정 파일
├── types # 타입 선언
└── utils # 유틸리티 함수
시간이 지나며 여러 컴포넌트에서 사용된다는 이유로 common 폴더에 도메인 로직이 들어오기 시작했다.
이름은 '공통'이지만 실제로는 특정 도메인에 종속적인 컴포넌트들이 섞여 있는 상황이 되었다.
현재는 shoppingCart만 도메인 폴더로 분리되어 있고,
사실상 order, product 등으로도 나눠야 하는 도메인 로직이
모두 shoppingCart 폴더 안에 뭉뚱그려져 있다.
도메인 간 책임이 섞이면서 구조적으로 확장성과 가독성이 떨어지는 상황이었다.
router.tsx 같은 설정 파일이 상위에 놓이면서,
프로젝트가 커질수록 파일들이 얕고 넓게 퍼질 위험이 있었다.
폴더 구조를 역할 기반 → 도메인 중심으로 확장한다면?
공통 UI 컴포넌트는 도메인 의존성을 제거한다.
→ components/ui에는 도메인과 무관한 순수 UI 요소만 위치시킨다.
(이때 아토믹 디자인 패턴을 이용해서 계층을 구분해봐도 좋을 것 같다.)
hooks, services, store 등도 도메인 단위로 분리한다
→ 관련 파일을 한 폴더 안에 모아 응집도를 높이고 탐색을 단순화한다.
router.tsx 등 설정 파일도 관련 구조 하위로 재배치한다
→ 페이지 중심 구조(pages 또는 app) 하위에서 경로를 관리한다.
/src
/pages (또는 /app) # 라우팅 진입점
index.tsx
about.tsx
/products
index.tsx
[id].tsx
/cart
index.tsx
checkout.tsx
/auth
login.tsx
register.tsx
/components # UI 컴포넌트
/ui # 순수 UI (도메인 무관)
Button.tsx
Modal.tsx
Card.tsx
Input.tsx
/product # 제품 도메인
ProductCard.tsx
ProductList.tsx
/cart # 장바구니 도메인
CartItem.tsx
CartSummary.tsx
/layout # 레이아웃 컴포넌트
Header.tsx
Footer.tsx
Sidebar.tsx
/hooks # 커스텀 훅
/ui
useModal.ts
useDebounce.ts
/product
useProducts.ts
useProductDetail.ts
/cart
useCart.ts
/auth
useAuth.ts
usePermissions.ts
/services # API 레이어
/api
client.ts
interceptors.ts
/product
productApi.ts
/cart
cartApi.ts
/auth
authApi.ts
/store # 상태 관리
/slices
productSlice.ts
cartSlice.ts
authSlice.ts
store.ts
/utils # 유틸리티
/common
formatters.ts
validators.ts
constants.ts
/product
priceCalculator.ts
/date
dateHelpers.ts
/types # TypeScript 타입 정의
/models
product.ts
user.ts
cart.ts
/api
responses.ts
requests.ts
/styles # 스타일 파일
/globals
reset.css
variables.css
/components
button.module.css
/assets # 정적 리소스
/images
/fonts
/icons
헤먼드가 잭슨의 PR에서 남긴 피드백이 인상 깊었다,
일단 응집도에 대한 답변에 이어서 제가 또 질문을 드려보자면,
응집도가 높은 상태가 이전 단계의 미션처럼 "하나의 모듈로 만들어서 배포한다" 고 생각해보시면 어떨까요!?
말씀해주신 product, cart, error 를 각각의 모듈로 만들어서 배포하기 쉬운 구조일까요?
지금은 모든 내용이 다 파편화 되어있어요.
product에 대한 내용을 추가하거나 수정하고 싶으면 거의 모든 폴더를 들춰봐야 알 수 있죠.
이걸 응집도가 높은 상태라고 하긴 어려울 것 같아요.
현재 내가 개선한 폴더 구조는 역할별 구조에서 도메인별 구조로의 확장이지만,
아직도 아래처럼 여러 폴더를 오가며 작업해야 하는 점은 완전히 해결되지 않았다.
/components/cart/ # 장바구니 UI 컴포넌트
/hooks/cart/ # 장바구니 로직 훅
/services/cart/ # 장바구니 API 호출
/store/cart/ # 장바구니 상태 관리
즉, 도메인별로 잘 나뉘어 있긴 하지만 관련 로직이 분산되어 있어
실제로는 하나의 변경을 위해 여러 위치를 탐색해야 하는 번거로움이 여전히 존재한다.
게다가 이 구조에서는 product, cart 같은 도메인을 하나의 모듈로 묶어 배포하기도 쉽지 않다.
그래서 더 나아가 도메인 중심 → 역할 내부 정리가 아니라
도메인 자체를 루트로 올리는 구조도 고려해볼 수 있을 것 같다.
이런 방식은 아래처럼 구성된다.
/src
/Product # 제품 도메인
/components # 제품 관련 컴포넌트
/hooks # 제품 관련 훅
/services # 제품 관련 API
/utils # 제품 관련 유틸리티
/Cart # 장바구니 도메인
/components # 장바구니 관련 컴포넌트
/hooks # 장바구니 관련 훅
/services # 장바구니 관련 API
/store # 장바구니 관련 상태
/User # 사용자 도메인
/components
/hooks
/services
/store
/shared # 공통 코드
/components # 공통 UI 컴포넌트
/hooks # 공통 훅
/utils # 공통 유틸리티
이렇게 구성하면, product 도메인 하나에 대한 관련 책임이 아래로 모이게 된다.
이 구조를 DDD(도메인 주도 설계)라고 하나?
물론, 아직까지는 내 프로젝트에서 위와 같은 구조가 인지 부하를 일으킬 정도로 크진 않다.
하지만 도메인이 늘어나고 팀원이 많아지는 상황이라면 하나의 도메인을 하나의 모듈처럼 관리하고 배포할 수 있는 구조를 선택할 수 있을 것 같다.
더 나아가 현재처럼 구현하지 않고
'행동'을 기반으로 기능 응집 구조를 하는 방법도 있는 것 같은데,
이것도 아직까지 이 구조가 인지부화를 일으키지 않아서 다음에 필요할 때 시도해봐야겠다.
이렇게 정리하고 보니, 어떻게 하면 관련된 것을 잘 모아서 책임을 모아놓고 변화가 생길 때 인지부화없이 최소한으로 작업할 수 있을까를 좀 고민하게 된 것 같다.
결국 폴더 구조는 나의 멘탈 모델이기 때문에, 뭔가의 기준으로 응집되어 있을 때 이해하기 쉬워지는 것 같다.
우테코에 온 지 벌써 119일 🎉
기념으로 써보는 호감 가는 사람의 특징 호호
나도 이런 사람이 되야지 ~ (◕‿◕)
레벨 1부터 interface를 '계약서'처럼, 클래스의 형태를 정의하는 용도로 사용해왔다.
이런 관점이 이어져서, 지금은 다음과 같은 기준에 따라 interface와 type을 구분해서 사용하고 있다.
그런데 수업을 들으면서 자연스럽게 interface를 어떻게 구현할지가 중요한 주제로 다뤄졌고,
"인터페이스를 어떻게 작성할까?"에 대해 더 고민하게 됐다.
이때 등장한 두 가지 접근 방식.
레벨 3 팀 프로젝트는 실무는 크게 다르지 않다고 한다.
그래서 팀에서 내가 지속적으로 기여할 수 있는 (내가 좋아하는) 방법을 찾아볼 수 있는 기회라는 생각이 든다. 예를 들어, 라이브러리 코드를 뜯어보는 것이 될 수 있다.
나는 지금까지 주로 리더 역할을 맡아왔다. 동아리 회장, 졸업작품 팀장, 해커톤에서도 팀장을 맡았고, 성실한 이미지 때문인지 자연스럽게 앞에 서게 되었다.
효율적인 협업을 위해 스크럼, 피그잼, 뽀모도로, 코어타임 등 다양한 방식을 도입해봤다. 팀원들이 부담 없이 의견을 나눌 수 있도록 협업 구조를 계속 개선해왔다. 이런 경험은 나를 자연스럽게 '사람'과 '팀'에 대한 고민으로 이끌었다. 『비폭력 대화』, 『함께 자라기』, 『상자 밖의 사람들』 같은 책들을 읽고, 작게나마 팀 내 대화 방식에 적용해보기도 했다.
그런데 아이러니하게도, 그 모든 과정을 겪으며 느낀 건 "나는 리더보다 팔로워가 더 잘 맞는다"는 사실이었다. 가장 큰 이유는, 모든 걸 혼자 짊어지기엔 벅찼기 때문이다. 서브 리더가 있었으면 좋았겠지만, 대부분 "개발에만 집중하고 싶다"는 입장이었고, 그만큼 팀장의 고충을 나누기 어려운 환경이기도 했다.
팀장으로서 나는 기술과 소프트스킬 모두를 혼자 먼저 실험해보고, 괜찮은 방법을 팀에 제안하고 도입하는 역할을 맡았다. 그래서 개인 개발 이외에 일로 더 바쁘기도 했다.
그래서 이제는 팔로워가 되려 한다. 늘 앞에서 방향을 잡고, 분위기를 조율하고, 문제를 해결하던 역할에서 한 발 물러나, 좋은 팀장을 지지하고, 더 나은 팀워크를 만들어가는 사람이 되고 싶다.
팔로워로 있을 때는 리더가 겪는 부담과 맥락을 이해하고,
주도적으로 협력하는 방법을 익힐 수 있다고 생각한다.
레벨 2가 얼마 남지 않았다.
마지막 미션은 정말 정신없고, 체력적으로도 꽤 힘들었다.
특히 테스트는 어떻게 짜야 할지 도무지 감이 안 와서 머리가 어지러울 정도였다.
그래도... 곧 끝이 난다.
마지막까지 리뷰 잘 반영하면서,
끝까지 화이팅팅 ~ !