최근 원티드 프리온보딩에서 설계와 구조에 대해서 배우게 되었고, 현재 사용한 프로젝트를 평가하며 내가 생각하는 좋은 구조에 대해서 언급하려고 합니다. 이후 해당 구조를 프로젝트 받은 내용을 언급하면서 마무리 하려고 합니다.
현재 사용한 프로젝트의 폴더 구조
개인 프로젝트에서 Next.js App router를 활용한 프로젝트를 진행했습니다. 이때 fastcampus 최적화 강의 중 youtube 프로젝트에서 사용한 프로젝트 폴더 구조를 참고하며, 왜 그리고 어떻게 하면 좋을까를 생각하며 제 프로젝트에도 비슷한 양식의 폴더구조를 채택했습니다..
완성된 폴더구조는 아래와 같습니다.

기본적인 구조는 크게 app, features, public, shared , remote, store 6가지로 나뉘어 집니다.
1. app은 Next.js의 앱라우터에 의해 관리되고 있기에, 규칙에 따라서 작성했습니다.
2. features : 각각의 페이지에 사용되는 하위 컴퍼넌트는 app 이외의 폴더에서 관리할 필요가 있어서 사용하였습니다.
내부에는 페이지별로 폴더를 만든 후, components, hooks, constants, utils를 폴더별로 따로 관리하였습니다.
3. public : asset을 관리하는 데 사용하였습니다.
내부에서 이미지, 폰트, 3d model(glb파일) 별로 디렉토리를 구분하였습니다.
4. shared : 공유되는 상수,훅, 유틸함수, 스타일(global.css등)을 관리하는데 사용하였습니다.
5. remote : api 통신에 관여하는 함수와 그에 관련된 타입을 관리하는데 사용하였습니다.
6. store : 전역 변수 상태 관리를 하기 위해 zustand로 만든 store를 저장하는 폴더입니다.
내가 생각하는 좋은 폴더 구조
좋은 설계 및 구조에 대해서 생각을 할 때 아래 두 가지 내용이 떠올랐습니다.
"최고의 설계는 트레이드 오프다." - 원티드 7월 프리온보딩
"조직이 설계하는 시스템은 그 조직의 커뮤니케이션 구조를 반영한다." - 콘웨이의 법칙
위 두가지 내용을 바탕으로 제 상황을 고려하여 알맞는 트레이드 오프를 해야 합니다.
현재 제 상황은 아래와 같습니다.
1. 혼자 프로젝트를 하며 디자이너와의 협업이 없기에 컴퍼넌트 UI 설계가 명확하지 않다.
2. 아직 레이어를 명확히 나누지 못하고 조금 유동적으로 바뀐다.
3. Next.js 를 활용하여 프로젝트를 진행했다.
명확한 UI 디자인을 구성하고 프로젝트를 진행하고 있지 않았고, 그렇기에 컴퍼넌트의 재사용성을 정의하기가 애매하다고 느꼈습니다. 따라서 FSD 아키텍처를 그대로 사용하기는 어렵다고 판단했습니다.
그리고 아토믹 패턴의 장점 중 하나는 디자인 시스템 기반의 컴퍼넌트를 사용하기에 소통에 강점이 있다고 생각합니다.
하지만 개인 프로젝트에서 명확한 가이드라인이 나오지도 않았었고 명확한 디자인 시스템을 구축하지 않은 상황에서는 유의미 하지 않다고 판단하였습니다.
따라서 FSD 및 기존 폴더 구성을 참고하여 layer를 사용하되 느슨하게 사용하고, Next.js의 앱라우터를 생각하여 조금 변형하는게 좋을 것이라고 생각합니다.
app
FSD의 page 레이어의 역할은 app 디렉토리가 하고 있다고 생각합니다. 또한 next.js의 라우팅을 활용하기 위해서는 페이지 기반으로 컴퍼넌트를 분류하는 것이 효율적이라고 생각했습니다.
features
유지 보수성을 고려했을 때 page내부에 컴퍼넌트의 관심사를 분리할 필요가 있다고 생각합니다. 따라서 pages의 하위 컴퍼넌트를 관리할 디렉토리가 필요하다 생각해서 생성했습니다. 이때 강의에서도 features기도 했고,, FSD의 widgets와 entity보다는 더 와닿아서 사용했습니다.
페이지 디렉토리 내부에 compoents, hooks, utils를 다시 세분화하여 사용했습니다.
shared
그리고 FSD의 shared에서는 비즈니스로직에 종속되지 않는 재사용되는 컴퍼넌트를 사용하지만 저는 특정 페이지에 종속되지 않는 컴퍼넌트와 유틸리티를 포함하는 용도로 shared 디렉토리를 사용했습니다.
현재 상황에서는 하위 구조로 components, hooks, styles, constants로 분류하였습니다. 하지만 components의 경우 추후 공유될 컴퍼넌트의 종류가 많아진다면 아토믹 패턴을 통해, 컴퍼넌트의 크기에 따라서 분류하여 재사용하기 수월하게 하면 좋을 것 같다고 생각헀습니다.
remote
Next.js 외부의 영역과 소통하는 코드도 따로 관리할 필요가 있다고 생각했습니다. 어쩌면 shared의 일부가 될 수도 있는데, 어떤 데이터를 어떻게 주고 받는지에 대한 정보는 비즈니스 로직에 좀 더 밀접해 있다고 생각했습니다. 따라서 shared 외부에 존재할 필요가 있다고 생각했습니다.
store
전역 변수의 경우 불필요한 props 드릴링을 막으려고 사용한 특정 페이지에 얽메인 값도 있고, 여러 페이지에 공유될 값도 존재할 수 있다고 생각했습니다. 따라서 shared 외부에서 따로 관리하는게 좋을 것이라 판단하였습니다.
public
절대 경로가 간편해지는 이점도 있고, 큰 고민 없이 사용했습니다...
현재 디렉토리에 대한 나의 평가
많은 고민을 했던 부분도 있고 비교적 간단하게 생각하고 사용한 구조도 있지만 비교적으로 만족스러운 구조라고 생각하고 있습니다.. 물론 협업이 늘어나고, 비즈니스가 복잡해지면 아토믹 패턴과 FSD의 장점이 부각되고 상대적으로 허술한 구조가 될 수도 있습니다. 하지만 좋은 구조는 '본인의 상황에 잘 맞는 구조' 라고 생각하고, 그렇기에 저는 현재 디렉토리가 좋은 구조라고 말하고 싶습니다.
아쉬운 점은 파일 수가 적어서 아직 괜찮은데 페이지 기반으로만 분리했기 때문에, 컴퍼넌트의 레이어나 크기에 대해서 명확하지 않습니다. 따라서 추후 더 많은 기능이 추가되거나 레이어가 분할된다면, 추가적인 그룹화가 필요할 것 같습니다.
components라는 폴더에 모든 page의 하위 컴퍼넌트를 담기에는 계층 관계나 규모가 불명확해서, 규모가 큰 organism은
features/(페이지명)에 작성하도록 폴더 구조를 옮겼습니다.
현재 디렉토리에 대한 멘토님의 피드백
wanted 프리온보딩에서 현재 폴더 구조에 대한 피드백을 받을 수 있었습니다.
멘토님께서 제 프로젝트 뿐만 아니라 다른 3가지 프로젝트도 같이 피드백해주셨는데, 공통적으로 생각하면 좋은 내용으로
폴더구조를 생각할 때 아래의 5가지를 추가적으로 고려하면 좋겠다고 하셨습니다.
1. flat vs nested : 펼칠 지 모아둘지
2. colocation vs global : 지역성과 전역성 중 어떤것에 우선순위를 두는지
3. utils vs businesses : 어디서 쓰든 동일하게 사용하면 utils, 특정 페이지나 컴퍼넌트에서 쓰는 기능은 business
4. deep depth : 어느 정도의 폴더 깊이까지 가져갈지 리액트에서는 최대 3~4까지를 권장함
https://legacy.reactjs.org/docs/faq-structure.html#avoid-too-much-nesting
5. dot naming comp1.types.ts 처럼 .을 붙여 파일명 짓는것
이를 바탕으로 피드백하면 저는 파일끼리 뭉치고(nested) nested한 구조를 선호합니다.
따라서 컴퍼넌트를 폴더기반으로 뭉치려고 했습니다. (molecules까지의 작은 컴퍼넌트는 components에 organism은 components 밖에 위치하도록 하였습니다.)

하지만 이러다 보니 depth가 너무 깊어졌습니다.
app/features/luckyshiba/components/background/constants/collision.ts
app내부에 페이지단위로 컴퍼넌트를 넣는 features 하위에 luckyshiba페이지의 components중 background에 존재하는 상수 중 충돌체에 관한 값..
6depth네요.. 관심사를 모은다는 명목하에 많은 폴더를 만들었고 너무 깊은 depth가 생겼네요.. 이를 dot naming을 활용해서 분류했으면 depth를 줄일 수 있었을 것 같습니다. collision.const.tsx 이런식으로...
storybook이나 test코드의 이름에 사용되던 dot naming을 일반 파일에 적용할 생각을 하진 못했었네요..
추가적으로 src가 있는것이 모노레포나 CI/CD를 구축할 때 유리해서 권장한다, remote와 shared의 depth가 같은 것에 대해서도 질문해주셨습니다. 답을 정해주시기 보단 생각을 많이 물어봐주시고 의아하거나 익숙하지 않은 구조에 대한 질문을 해주셨습니다.
피드백에 대해 느낀점
구조라는게 완벽한 정답보다는 취향도 반영되는 느낌이고, 멘토님께서도 답을 정해주시기 보단 질문을 많이 던져주셨습니다. 제 프로젝트뿐만 아니라 다른 프로젝트를 바탕으로 아직 제 경험상으론 좋아보였지만, 멘토님이 본인 경험 바탕으로 안 좋게 될 수 있는 예시들을 설명해주셔서 공감이 갔던 피드백이었습니다.
'프로젝트' 카테고리의 다른 글
시바 컴퍼넌트 관심사 분리하여 결합도 낮추기 (0) | 2024.07.22 |
---|---|
MyPage를 개방폐쇄원칙(OCP) 고려해서 마이페이지 리팩토링 하기 (0) | 2024.07.02 |
Draco를 활용하여 glb파일 압축하여 성능 향상시키기 (0) | 2024.07.01 |
ManulPopup창을 관심사 분리하기 (값,계산,액션, SOLID) (0) | 2024.06.29 |
R3F 및 useCannon에서 시바 조종하기 (최종 이동 로직 구현 및 채택 과정) (0) | 2024.06.28 |