최근 기술 면접을 다니면서 공통적으로 많이 받았던 질문이 "FSD를 사용하셨는데 왜 도입하셨고, 어떤 점이 해결되셨나요? 선택했을 때 어려운 점은 없었나요?"였다. 그리고 사전과제나 라이브 코딩을 진행할 때도 왜 이런 폴더구조를 선택했는지를 물어보는 회사가 많았다. 타이밍 좋게 이번 스터디 주제가 '스스로 생각하는 좋은 폴더 구조란 무엇인지'에 대해 다룰 예정이라, 기회 삼아 정리를 해보기로 했다.
결론부터 말하자면 사실 "좋은 프론트엔드 폴더 구조가 뭐야?"라고 말했을 때 정답도 없고 영원한 것도 없다고 생각한다. 실무에서 A라는 폴더 구조를 그 당시에 적합하다 생각하고 적용을 했음에도, 프로젝트 규모가 변하고 시간이 지나면 기존 폴더 구조의 한계가 느껴지고 이에 맞춰서 또 다른 적절한 폴더 구조를 고민하게 되기 때문이다. 때문에 이번 글에서는 그동안 개발을 하면서 폴더 구조에 대해 고민했던 과정들과, 해당 폴더 구조를 검토 혹은 도입했을 때 느꼈던 장단점을 위주로 정리해보려고 한다.
🤔 초기 프로젝트에서 사용한 폴더 구조
약 3년 전 React 학습 초기에, 그리고 현재도 작은 프로젝트를 개발하는 경우 사용하는 폴더 구조는 components, utils 등의 역할을 위주로 나누는 방식이다. 폴더 구조에 대한 깊은 설계를 할 필요 없이 간결하게 사용할 수 있다는 점이 있었고, 기본 투두 리스트 같이 간단한 프로젝트의 경우에는 오히려 별도의 폴더 구조를 들여오는 것이 복잡도를 더 높이는 것처럼 보였기 때문이다.
/src
/components
/utils
/pages
하지만 이 구조의 치명적인 단점은, 규모가 조금만 더 커져도 유지보수가 불편하다는 것이다. components의 크기가 방대해졌을 때 특정 기능을 수정하고 싶을 때도 한 번에 원하는 파일을 찾기가 어려워진다. 아래 이미지는 프론트엔드 개발자로 취업하기 전 만들었던 프로젝트의 components 폴더에 있는 파일들인데, 대충 봐도 어마어마하다. '컴포넌트'라고 생각하는 모든 것들은 다 components에 넣었기 때문에 원하는 파일을 바로 찾기가 어려워졌다. 폴더의 역할은 원하는 파일을 찾기 위한 하나의 경로가 되는 것이라 생각하는데, 해당 프로젝트에서는 결국 폴더가 폴더의 역할을 하지 못했다.
🤔 개선 과정에서 고려한 폴더 구조
폴더 구조 개선에 대한 고민을 하기 시작하니 생각이 끝도 없이 퍼지기 시작했다. 처음에 고민했던 방식은 아토믹 디자인 패턴으로, atoms/molecules/organisms로 나누어 컴포넌트 구조를 변경하는 것을 검토했다. 기존 프로젝트의 구조를 변경하기 위해 atoms/molecules/organisms 각각의 폴더에 들어가는 컴포넌트들을 분리하고자 했으나, 막상 설계를 하려고 하니 각 폴더의 경계를 파악하기가 쉽지 않았다. atoms에 대한 구분은 명확했지만 molecules, organisms로 넘어갈수록 어떤 것까지를 molecules에 넣고 어떤 것까지를 organisms에 넣어야 하는지에 대한 감이 잘 오지 않았다. 그리고 초기에 기준들을 세워놓았음에도 불구하고 다시 보면 또 기준에 대한 회의감이 드는 감이 있었다. 또한 도입을 망설이게 된 또 하나의 이유는 재사용성에 있었다. atoms에 있는 컴포넌트를 제외하면 molecules/organisms를 넣었을 때의 장점이 크게 느껴지지 않았다. 해당 폴더에 있는 컴포넌트들을 재사용할 곳이 많지 않았기 때문에 세분화하는 것이 오히려 복잡도를 높인다고 생각했다.
결국 개선했던 방향은, 기존의 폴더 구조를 유지하면서 세부 폴더를 추가하는 방식을 선택했다. components 하나로만 관리되던 방식을 components 하위에 페이지를 기준으로 세부 폴더를 만드니, 기존 구조에서 유지보수가 불편하다는 점을 많이 개선할 수 있었다. 다만 만약 규모가 더 커진다고 가정했을 때는 페이지를 기준으로 구성하는 것이 더 좋은 방법이라고 생각한다. 특정 페이지마다 기능을 수정할 때, 모든 components, type, service 폴더들을 열어가며 필요한 파일을 찾기보다는 페이지 하위에 components, type 등의 폴더가 있는 것이 더 유지보수 관점에서 편하다고 생각한다. 만약 사이트가 커지거나 변동되는 프로젝트 방향성으로 인해 일부 페이지를 떼어내서 별도로 관리해야 하는 상황이 왔을 때도 더 분리하기 쉽다는 장점이 있다.
components를 나누는 기준을 위주로 이야기했는데, 그 외 고민했던 부분도 아래에 적어보았다.
services vs utils
기존에는 함수 분리에 있어 utils만을 사용했었다. 이 안에는 비즈니스 로직도 포함되었고 날짜/포맷 함수도 포함되었다. 하지만 프로젝트의 개수가 많아지다 보니 현재 프로젝트에서만 사용되는 함수, 그리고 범용적으로 계속 재사용되는 함수를 분리하고자 하는 니즈가 생겼다. 이때 알게 된 것이 services였고, services 내에는 비즈니스 로직과 관련된 함수, utils 내에는 어떤 프로젝트를 사용하든 상관없이 계속해서 재사용될 가능성이 높은 함수들로 구성하여 분리하기 시작했다.
뷰와 비즈니스 로직의 분리
뷰와 비즈니스 로직을 분리하게 된 계기는 Svelte에서 React로 마이그레이션 하는 과정에 있었다. 기존에 Svelte로 관리하던 프로젝트가 규모가 점점 커지며 유지보수에 더 적합한 React로 변경하기로 결정했는데, 이 과정에서 테스트를 작성하려고 하니 테스트 하나를 작성하는데도 너무 많은 시간이 소요되었고 일부 로직만 테스트하고 싶은데도 컴포넌트 안에 있는 로직이다 보니 컴포넌트를 import 해야 했다. CTO이신 '시바'께 이런 문제에 대한 고민을 털어놓은 적이 있었는데, 테스트가 어렵다는 건 근본적인 구조 자체에 문제가 있을 가능성이 있다는 말씀을 주셨고 이 피드백을 듣고 프로젝트 구조에 대한 고민을 하게 되었다.
어떻게 하면 내가 테스트하고 싶은 로직만 간단하게 테스트할 수 있을까? 에 대한 고민을 하다가 결국 뷰 안에 있는 로직들을 분리해야겠다는 결론이 났다. 이 과정에서 본격적으로 사용하기 시작했던 게 바로 커스텀 훅이다. 커스텀 훅을 사용하면 비즈니스 로직을 컴포넌트와 분리하여 관리가 가능하고, 렌더링에 필요한 상태만을 가질 수 있게 되기 때문에 커스텀 훅을 위주로 사용하여 로직을 분리했다. 이렇게 마이그레이션을 진행하니 컴포넌트 전체를 import 하던 방식에서 로직 테스트가 필요한 훅만을 가져와서 상태값의 변화를 보다 간편하게 확인할 수 있었다.
🤔 FSD
최근, 항해 플러스를 통해 FSD를 처음 시도해 보았다. entities/features/widgets 등으로 구분하여 컴포넌트들을 나누고 관리하였는데, 사용하면서 느낀 FSD는, 큰 틀이 정해져 있을 뿐 방법이 정해져 있지는 않다는 것이다. 실제 FSD 공식문서에 있는 Examples만 봐도 폴더 구조를 구성한 방식이 제각각이다. 그래서 좀 혼란스럽기도 했지만, 이 중 내가 기준을 가장 명확하게 세울 수 있는 방법을 여러 예제들을 보면서 찾아나갔고 아래처럼 구조를 짰다. 폴더 구조를 봤을 때 기능별로 분류한 게 직관적이긴 하지만 어떤 측면에서 보면 조금 과할 수 있겠다는 생각은 드는 상태이다. 폴더를 나누는 기준이 명확하지만 따지고 보면 1~2페이지의 분량을 짜는데도 이렇게 많은 폴더들이 나오게 된 것이다 보니 실무에서 더 많은 페이지와 기능이 있는 프로젝트를 다루다 보면 과연 현재 구조가 여전히 괜찮을까?라는 의문이 남았다.
반면에 또 신기하게도 기업 사전과제를 진행할 때 FSD를 적용해서 제출한 적이 있었는데, 이 때는 FSD를 적용함으로써 좀 더 간편한 폴더 구조를 유지할 수 있었다는 생각이 들었다. 동일한 폴더 구조 컨셉이라도 프로젝트마다 효용성이 다르다는 것을 느끼게 된 순간이었다.
🤔 결론
그래서 프론트엔드에서의 좋은 폴더 구조란 무엇인가?를 고민했을 때 내릴 수 있는 결론은, 어느 하나가 정해져 있는 것이 아닌 '현재 프로젝트에서 가장 협업하기 좋은 방식'이라고 생각한다. 아무리 좋은 폴더 구조라 하더라도, 만약 내가 사용하고 있는 프로젝트에 도입했을 때 오히려 복잡도를 올린다거나 협업에 있어 제한적인 방식이라면 도입을 충분히 고민해 보고 때로는 과감하게 포기할 수 있어야 한다고 생각한다. 반면에 구조가 간단하더라도 유지보수에 어려움이 있거나 프로젝트 파악이 어렵다면 더 좋은 폴더 구조를 고민해보아야 한다고 생각한다.
프론트엔드에서 사용하는 다양한 폴더 구조에 대해 이해하고 있되, 단순히 트렌드에 따른 것이 아닌 프로젝트의 어려움을 해결할 수 있는가를 1순위로 보고 적용해야겠다는 생각을 하며 마무리 지어본다!
'개발' 카테고리의 다른 글
[함수형 코딩] 액션, 계산, 데이터란? (5) | 2025.03.12 |
---|---|
[시나브로 자바스크립트] Date, Intl.DateTimeFormat으로 날짜 다루기 (4) | 2025.03.07 |
[시나브로 자바스크립트] 명령형 프로그래밍 vs 선언형 프로그래밍 (7) | 2025.02.21 |
[시나브로 자바스크립트] 1주차 스터디 정리 (0) | 2025.02.12 |
[HTTP 완벽 가이드] 18장 웹 호스팅 (0) | 2025.02.11 |