항해 플러스 프론트엔드 과정을 진행하면서 처음으로 과제를 제출하지 못하게 되었다. 지지난 주 일요일까지만 해도 사이드 프로젝트를 새롭게 시작할 만큼 여유가 있었지만, 평일에 회사의 새로운 릴리즈 건을 처리하느라 과제에 집중할 시간을 확보하지 못했다. 제출 마감일 전날인 목요일까지 최선을 다했으나, 결국 완성하지 못하고 이번 과제를 내려놓아야 했다.
비록 과제 제출은 실패했지만, 테오의 발제 자료를 깊이 있게 공부하며 관심사 분리와 FSD 아키텍처와 필요성에 대한 인사이트를 얻을 수 있었다.
더욱이 현재 우리 회사에서는 기존 폴더 구조를 FSD 아키텍처로 점진적으로 전환하는 작업을 진행 중이다. 과제는 제출하지 못했지만, 이번에 배운 내용을 실무에 즉시 적용해볼 수 있는 기회가 생겼다는 점은 다행이다.
과제를 진행하지 못한만큼, 이번 포스팅은 과제 내용 대신 발제 내용을 중점으로 진행하려고 한다. (이번 글을 작성하는 데 있어 테오의 발제 자료가 큰 도움이 되었다.)
이번 주차에서는 프론트엔드 개발의 핵심 원칙인 관심사 분리와 이를 실현하기 위한 효과적인 폴더 구조 설계 방법론을 학습했다. 특히 많은 프론트엔드 개발자들이 직면하고 있는 관심사 분리 문제를 해결하기 위해 등장한 FSD(Feature-Sliced Design) 아키텍처의 등장 배경과 실무 적용 방안까지 깊이 있게 다룰 수 있었다.
전통적인 웹 개발은 마치 층층이 쌓은 케이크처럼 역할별로 수직적인 층을 이루고 있었다.
[JavaScript 층] - 동작 담당
---------------------
[CSS 층] - 표현 담당
---------------------
[HTML 층] - 구조 담당
이러한 수직적 분리는 각 기술의 역할이 명확했기에 코드의 복잡성을 낮추고 유지보수성을 향상시켰다. 하지만 현대 웹 개발에서는 이러한 단순한 분리만으로는 충분하지 않게 되었다. 예를 들면 단순한 팔로우 버튼을 구현하는데도 다음과 같은 복잡한 요소들이 얽혀 있는 것이다:
이처럼 현대 웹 개발에서는 단순히 기술 스택(HTML/CSS/JS)의 분리를 넘어, 각각의 역할과 책임에 따라 코드를 더욱 세밀하게 분리하고 조직화하는 것이 필요해졌다.
React나 Vue와 같은 현대 프론트엔드 프레임워크에서 가장 중요한 개념인 '컴포넌트'는 특정 UI 요소와 그에 관련된 기능을 하나로 묶어 모듈화한 단위라고 할 수 있다. 컴포넌트는 UI를 재사용 가능한 독립적인 조각들로 나누고, 이 조각들을 조합하여 복잡한 애플리케이션을 구축할 수 있게 해준다
예를 들어, 웹 애플리케이션에서 자주 사용되는 버튼을 컴포넌트로 만든다면 다음과 같다.
const Button = ({ text, onClick, variant = 'primary' }) => {
return (
<button
className={`button ${variant}`}
onClick={onClick}
>
{text}
</button>
);
};
이런 컴포넌트는 어떤 페이지에서든 쉽게 재사용할 수 있고, 일관된 디자인과 동작을 보장한다는 장점이 있다. 그러나 컴포넌트 기반 개발에도 다음과 같은 한계점이 있었다.
컴포넌트는 근본적으로 잘못된 접근이 아니었다. HTML, CSS, JS를 하나의 단위로 묶어 기능 중심의 모듈화를 달성했고, 이는 코드의 재사용성과 유지보수성을 크게 향상시켰다. 하지만 프로젝트가 커지면서 컴포넌트 내부와 컴포넌트 간의 구조를 더 체계적으로 정립할 필요성이 대두되었다.
현대 프론트엔드의 관심사 분리 시도
이러한 문제를 해결하기 위해 프론트엔드 개발은 여러 방향으로 진화했다:
1. UI 컴포넌트의 계층화 (Atomic Design)
단순히 모든 컴포넌트를 하나의 폴더에 넣는 대신, UI 컴포넌트를 역할과 복잡도에 따라 계층적으로 구성하기 시작했다. Atoms, Molecules, Organisms 등의 구분을 통해 UI 요소의 재사용성과 일관성을 확보했다.
2. CSS 의존성 해결
CSS와 HTML 간의 양방향 의존성 문제를 해결하기 위해 CSS-in-JS, CSS Modules 등의 방식이 등장했다. 이는 CSS의 범위를 컴포넌트로 한정하고, 의존성의 방향을 단방향으로 만들어 유지보수성을 높였다.
3. 비즈니스 로직과 뷰 로직의 분리
상태 관리 도구들의 등장으로 데이터 관련 로직을 컴포넌트에서 분리할 수 있게 되었다. 컴포넌트는 UI 렌더링과 이벤트 처리에만 집중하고, 복잡한 비즈니스 로직은 별도의 계층에서 관리하게 되었다.
4. 서버 상태 관리의 특화
React Query, SWR 같은 도구들의 등장으로 서버 상태 관리를 위한 특별한 계층이 만들어졌다. 캐싱, 재시도, 낙관적 업데이트 등 서버 데이터 관리에 특화된 기능들을 별도로 다룰 수 있게 되었다.
이러한 진화 과정에서 프론트엔드 프로젝트는 일반적으로 다음과 같은 폴더 구조를 가지게 되었다:
src/
/api # 백엔드 통신
/components # 공통 컴포넌트
/hooks # 커스텀 훅
/pages # 페이지 컴포넌트
/store # 상태 관리
/utils # 유틸리티 함수
...
이 구조는 역할별로 깔끔하게 분류된 것처럼 보이지만, 실제로는 특정 기능이나 도메인과 관련된 코드들이 여러 폴더에 분산되는 문제가 있었다.
예를 들어 '사용자 프로필' 기능을 구현할 때:
/components/Profile/ProfileCard.tsx
/components/Profile/ProfileImage.tsx
/api/profileApi.ts
/store/profileSlice.ts
/hooks/useProfile.ts
/utils/profileValidation.ts
/types/profile.d.ts
이처럼 하나의 기능이 여러 폴더에 파편화되면서 코드의 응집도가 떨어지고 유지보수가 어려워졌다. 만약 프로필 기능에 수정이 필요하다면, 개발자는 여러 폴더를 돌아다니며 관련 코드를 찾아야 하는 번거로움이 있다.
이러한 문제를 해결하기 위해 FSD(Feature-Sliced Design) 아키텍처가 제안되었다. FSD는 기존의 역할 중심 구조에 기능(Feature) 중심의 관점을 추가해, 코드를 더 효과적으로 구성할 수 있게 한다.
FSD는 세 가지 주요 차원으로 코드를 구조화한다:
1. Layer (수직적 책임 분리)
src/
/app # 프로젝트 초기화, 전역 설정
/pages # 라우팅 페이지
/widgets # 재사용 가능한 복잡한 UI 블록
/features # 특정 비즈니스 기능 담당
/entities # 도메인 모델
/shared # 공통 유틸리티
각 레이어는 명확한 책임을 가지며, 상위 레이어는 하위 레이어에 의존할 수 있지만, 그 반대는 불가능하다.
2. Slice (도메인별 분리)
src/
/entities/
/user/
/post/
/comment/
/features/
/auth/
/post-creation/
/comment-section/
3. Segment (기술적 역할 분리)
src/
/entities/user/
/ui/ # UI 컴포넌트
/model/ # 상태 관리, 비즈니스 로직
/api/ # API 통신
/lib/ # 유틸리티
/config/ # 설정
1. 높은 응집도
2. 명확한 의존성 규칙
Copypages → widgets → features → entities → shared
3. 확장성
사용자 프로필 기능을 FSD로 구현한다면 다음과 같을 것이다:
src/
/entities/user/
/ui/
UserCard.tsx
UserAvatar.tsx
/model/
user.types.ts
user.store.ts
/api/
userApi.ts
/features/user-profile/
/ui/
ProfileForm.tsx
ProfileSettings.tsx
/model/
profile.store.ts
/api/
profileApi.ts
/widgets/user-profile/
UserProfileWidget.tsx
이러한 구조는 관련 코드들을 논리적으로 그룹화하면서도, 각 계층의 책임을 명확히 분리한다.
이처럼 FSD는 단순히 새로운 폴더 구조를 제시하는 것이 아니라, 프론트엔드 애플리케이션의 복잡성을 다루는 체계적인 방법론을 제공한다. 이는 기존의 역할 중심 구조와 기능 중심 구조의 장점을 결합하여, 더 효과적인 코드 구성과 관리를 가능하게 한다.
앞서 들어가는 글에서 말했듯, 우리 회사는 현재 기존 폴더 구조를 FSD 아키텍처로 점진적으로 전환하는 작업을 진행하고 있다. 이 과정에서 FSD 공식 문서를 포함한 다양한 자료들을 참고했지만, 단순히 Layer, Slice, Segment의 개념을 개별적으로 이해하는 것만으로는 그 본질적인 의미를 파악하기 어려웠다. 그러다보니 어떤 요소를 features로 분류하고 어떤 것을 widgets로 구분해야 하는지와 같은 실질적인 분리 작업에 많은 어려움을 겪었다.
하지만 항해 플러스 6주차에서 테오의 발제를 통해 단순한 FSD 개념 학습을 넘어, 관심사 분리의 본질적 의의와 프론트엔드 개발에서의 관심사 분리 시도의 발전 과정을 이해할 수 있었다. 이를 통해 FSD가 등장하게 된 배경과 그 실제적인 적용 방안에 대한 전체적인 맥락을 파악할 수 있었고, 결과적으로 FSD에 대한 이해도가 높아지고 실무 적용도 더욱 수월해졌다.
다음 주차부터는 (이미 진행되었지만) 테스트 코드에 대한 학습이 진행된다. 다음 주차의 학습을 기대하며, 이번에 배운 내용을 토대로 더 나은 프론트엔드 개발자로 성장해 나가고 싶다!
항해 플러스 5기 모집 중입니다 :)
https://hanghae99.spartacodingclub.kr/plus/fe
(추천인 코드 ELPVP6 를 입력하시면 수강료를 20만원 할인받을 수 있습니다)
It seems you had quite a week! Despite the challenge of not submitting your assignment, you've managed to turn it into a valuable learning experience. The insight you've gained from studying FSD architecture and its application to www.homedepot.com survey website real-world projects is impressive. Your detailed explanation of the evolution and benefits of FSD, as well as its practical implementation, shows a deep understanding of front-end development principles. Keep up the great work, and I have no doubt you'll continue to grow as a skilled developer!