Yangs1s 님의 상세페이지[5팀 양성진] Chapter 2-3. 관심사 🦍분리와 폴더구조

과제 체크포인트

https://yangs1s.github.io/front_6th_chapter2-3/?limit=10&sortOrder=asc

기본과제

목표 : 전역상태관리를 이용한 적절한 분리와 계층에 대한 이해를 통한 FSD 폴더 구조 적용하기

  • 전역상태관리를 사용해서 상태를 분리하고 관리하는 방법에 대한 이해
  • Context API, Jotai, Zustand 등 상태관리 라이브러리 사용하기
  • FSD(Feature-Sliced Design)에 대한 이해
  • FSD를 통한 관심사의 분리에 대한 이해
  • 단일책임과 역할이란 무엇인가?
  • 관심사를 하나만 가지고 있는가?
  • 어디에 무엇을 넣어야 하는가?

체크포인트

  • 전역상태관리를 사용해서 상태를 분리하고 관리했나요?
  • Props Drilling을 최소화했나요?
  • shared 공통 컴포넌트를 분리했나요?
  • shared 공통 로직을 분리했나요?
  • entities를 중심으로 type을 정의하고 model을 분리했나요?
  • entities를 중심으로 ui를 분리했나요?
  • entities를 중심으로 api를 분리했나요?
  • feature를 중심으로 사용자행동(이벤트 처리)를 분리했나요?
  • feature를 중심으로 ui를 분리했나요?
  • feature를 중심으로 api를 분리했나요?
  • widget을 중심으로 데이터를 재사용가능한 형태로 분리했나요?

심화과제

목표: 서버상태관리 도구인 TanstackQuery를 이용하여 비동기코드를 선언적인 함수형 프로그래밍으로 작성하기

  • TanstackQuery의 사용법에 대한 이해
  • TanstackQuery를 이용한 비동기 코드 작성에 대한 이해
  • 비동기 코드를 선언적인 함수형 프로그래밍으로 작성하는 방법에 대한 이해

체크포인트

  • 모든 API 호출이 TanStack Query의 useQuery와 useMutation으로 대체되었는가?
  • 쿼리 키가 적절히 설정되었는가?
  • fetch와 useState가 아닌 선언적인 함수형 프로그래밍이 적절히 적용되었는가?
  • 캐싱과 리프레시 전략이 올바르게 구현되었는가?
  • 낙관적인 업데이트가 적용되었는가?
  • 에러 핸들링이 적절히 구현되었는가?
  • 서버 상태와 클라이언트 상태가 명확히 분리되었는가?
  • 코드가 간결하고 유지보수가 용이한 구조로 작성되었는가?
  • TanStack Query의 Devtools가 정상적으로 작동하는가?

최종과제

  • 폴더구조와 나의 멘탈모데일이 일치하나요?
  • 다른 사람이 봐도 이해하기 쉬운 구조인가요?

과제 셀프회고

이번 과제를 통해 이전에 비해 새롭게 알게 된 점이 있다면 적어주세요.

  • 아키텍처 ≠ 단순한 폴더 구조 처음에는 FSD를 단순히 "정해진 규칙에 따라 폴더를 나누는 방법"으로 생각했는데, 실제로 적용해보니 관심사의 분리와 의존성 관리라는 더 깊은 개념이었습니다.

  • 의존성 방향의 중요성

app > processes > pages > widgets > features > entities > shared

상위 레이어가 하위 레이어에만 의존할 수 있다는 규칙과 Public API를 통해서만 외부 노출한다는 원칙이 코드 결합도를 낮추고 유지보수성을 높이는 핵심이라는 걸 깨달았다.

  • UI 분리 vs 로직 분리의 난이도 차이

또한 UI 분리보다 비즈니스 로직 분리가 훨씬 어렵다는 점도 새로운 발견이었습니다. 컴포넌트를 나누는 것은 비교적 직관적이여서 나누는데 어려움은 없었는데, 어떤 로직이 entities에 들어가야 하고 어떤 것이 features에 들어가야 하는지 판단하는 것은 생각보다 복잡했습니다.

본인이 과제를 하면서 가장 애쓰려고 노력했던 부분은 무엇인가요?

  • Features와 Entities의 경계를 명확히 하려고 가장 많이 고민했습니다. 특히 카트 기능을 구현할 때, 카트 데이터 자체는 entities에 두어야 하는지, 아니면 카트에 상품을 추가/삭제하는 비즈니스 로직이 features에 들어가야 하는지 계속 고민했습니다. 이 과정에서 비즈니스 로직이 뭔지 기준을 세우려고 노력했고, 엔티티는 데이터와 기본 조작, 피처는 사용자가 실제 수행하는 작업으로 구분하려고 했습니다. 또한 post-filter 같은 복합적인 기능에서 언제 Widget으로 분리하고 언제 Page에 둘지도 많이 고민했습니다. 여러 features를 조합하되 재사용성이 없는 경우의 판단 기준을 세우려고 애썼습니다.

  • 페어 코딩으로 같이 의견을 나누고 기본적인 프로젝트 세팅을 같이 가져가봤습니다. 이 내용은 같이 의견을 나누면서 서로 본인들이 생각하기엔 좋은 폴더구조를 어떻게 가져갈까가 어떻게 나눌까 이런 생각들을 계속 공유하는거에 있어서 가장 핵심이라고 느껴졌습니다. 페어보단 쉐어에 가까웠지만, 그래도 fsd-lint을 세팅하고 프리티어를 같이 세팅하고, 어떤 폴더 구조식으로 가져갈지 한번 트라이 해봤습니다.

  • 우선 둘다 처음이다 보니까 위 언급 내용인 언제 features인지 엔티티인지 계속해서 얘기를 나눴고, 지금의 프로젝트 구조를 약간 가지게 된 초석이 되었던거 같습니다. 후에는 서로 같이 할 타이밍이 안되서 조금씩 바꿔나갔지만, 이런 의견을 나누고 , 다른사람들과 소통을 하면서 제가 생각한 프로젝트의 구조를 가져가보려고 노력했습니다.


    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ['**/*.{ts,tsx,css}'],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    plugins: {
      'react-hooks': reactHooks,
      'react-refresh': reactRefresh,
      'fsd': fsdPlugin,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      'react-refresh/only-export-components': [
        'warn',
        { allowConstantExport: true },
      ],
      // Enforces FSD layer import rules (e.g., features cannot import pages)
      'fsd/forbidden-imports': 'error',

      // Disallows relative imports between slices/layers, use aliases (@)
      // Allows relative imports within the same slice by default (configurable)
      'fsd/no-relative-imports': [
        'error',
        {
          allowSameSlice: true,
        },
      ],

      // Enforces importing only via public API (index files)
      // 'fsd/no-public-api-sidestep': 'error',

      // Prevents direct imports between slices in the same layer
      // 'fsd/no-cross-slice-dependency': 'error',

      // Prevents UI imports in business logic layers (e.g., entities)
      // 'fsd/no-ui-in-business-logic': 'error',

      // Forbids direct import of the global store
      // 'fsd/no-global-store-imports': 'error',

      // Enforces import order based on FSD layers (disabled due to prettier conflict)
      // 'fsd/ordered-imports': 'warn',

같이 작성한 eslint,

아쉬운점은 네이밍 컨벤션같은걸 좀 미리 정해놓고 해보면 더 좋은 시너지와 시간 절약이 가능할거라고 생각했습니다.

아직은 막연하다거나 더 고민이 필요한 부분을 적어주세요.

  • 정확하게 이게 좋은 구조인지는 저는 고민이 있습니다.
  1. 코드구조가 되게 깔끔해지고 좋지만, 처음이기도 해서 개발 속도도 느렸던거 같고, 초기 생산성이 너무 낮은거 같아요. 러닝커브도 높고. 이런 점은 솔직히 너무 막연하게 느껴집니다. 2.작은 프로젝트여서 그런걸수도 있겠지만, 임포트 해오는 과정에서 같은 계층은 임포트를 못하다 보니 엄격함에서 오는 장벽이 있습니다. 3.barrel export을 통해서 public api를 정의하는데 이걸 이용하다 보니까 파일 수가 많아지고 번거로움이 많아졌던거 같아요

챕터 셀프회고

클린코드, 리팩토링, 아키텍처, 디자인패턴 이런 건 확실히 코드를 단순하게만 잘 분리하고, 나누는 건만이 아니라는 걸 좀 알게 되는 챕터였어요.

🔍 핵심 깨달음들

1. 클린코드와 리팩토링의 진짜 의미

단순히 코드만 깔끔하게 쓰는 게 아니라, 설계 원칙을 지키면서 관심사를 분리하는 게 진짜 클린코드라는 걸 깨달았다. 이전에는 "함수 이름 잘 짓고, 주석 잘 달면 클린코드"라고 생각했는데 완전히 다른 차원의 얘기였다.

2. 응집도, 결합도 고려의 중요성

단순히 분리한다고 되는 게 아니라 높은 응집도와 낮은 결합도를 유지할 수 있도록, 단일 설계 원칙을 따르면서 해야 한다는 것. 이전 과제에서 엔티티 기준 계층 분리를 해봤던 경험이 도움이 됐다.

3. 관심사별 분류의 효과

props drilling에 대한 과제에서 전역상태가 아니어도, 관심사별로 분류하면 오히려 더 직관적으로 눈에 잘 들어온다는 게 가장 재밌고 흥미로웠던 경험이었던 것 같습니다. 특히 준일 코치님 멘토링 시간에 같은 페어팀인 휘린의 질문에서도 말해주시고 실시간으로 코딩을 해서 보여주셨던 게 가장 크게 와닿았던 인사이트였습니다.

4. useContext는 전역상태관리가 아니다

이건 발제 때 처음 듣고 가장 놀랐습니다.

5. Props Drilling 제거의 효과

코드가 깔끔해지는 걸 체감하는 건 이전부터 알았지만, 관심사별로 그룹화하며 상태를 이용하면 코드 자체가 굉장히 깔끔해진다는 걸 알 수 있었습니다.

6. FSD 아키텍처

이번 과제를 통해서 FSD의 단점을 가장 크게 느꼈지만, 좋았던 건 도메인 로직과 공유 로직의 계층분리가 정확하다는 점. 배치 자체도 명확하니까 찾아가서 보기가 쉽다는 점, 맥락파악이 용이하다는 게 가장 큰 장점이라고 생각했고, 단점들은 위에 언급했듯이 진입장벽이 높고, import가 ### FSD 레이어 규칙에 의해 어렵다는 점. 전체적으로 총평은 기대보다는 정말 많은 걸 알게 되었다. 하지만 알게 된 거에 비해서는 깊이감 있게 다가오지는 못했던 것 같아요. 시간도 저는 좀 짧다고 느껴지기도 했어서 아쉬웠고, 그리고 다른 사람들은 어떤 리액트 프로젝트 구조를 가지고 일을 하고 경험해봤는지 서로의 생각과 내용을 공유할 수 있는 게 가장 좋았고, 가장 큰 인사이트라고 생각합니다.

💼 실무 경험과의 연결


내가 일했던 경험에서 이번 챕터는 많은 깨달음을 줬습니다.

저는 항상 클린코드나 리팩토링은 잘 분리하고 이름 잘 짓고, 단순한 업무의 반복이라고 생각을 했습니다. 이번 챕터를 겪어보면서 거대한 단일함수를 분리하고 나눌 때마다 항상 이상하게 느껴지고 분리하니까 더 불편해지고, 나눠도 나눈 게 또 너무 지저분하고 가독성도 떨어지고, 점점 유지보수하기 어렵게 되어버렸다는 점입니다.

실제 경험

코드가 없지만 예전에 엑셀처럼 셀이 수정이 되고 키보드로 왔다 갔다 하고 이런 복잡한 기능을 가진 데이터 테이블을 만든 적이 있는데, 이 당시 기능들을 전체적으로 한곳에 다 넣다 보니 테이블만 템플릿 코드까지 합쳐서 1000줄 가까이 가진 적이 있었습니다. 그때, 잠시 짬이 나기에 이 코드를 정리하자 해서, 단순하게 어떤 기능의 이름만 붙이고 나누는 식으로 하다 보니까 파일은 많아지고, 이름도 헷갈리고 분리도 관심사별로... 테이블 안에는 각각의 도메인들이 다른 데이터들이 있는데 이런 거 싹 무시하고 단순하게만 나누다 보니 완전히 엉키고 기능이 이상해지는 경우도 많아서 다시 되돌리고 다른 작업 진행하고 항상 이런 악순환의 반복이었습니다.

깨달음

이번 챕터를 통해서 "아, 내가 너무 단순하게 생각했던 것이 생각보다는 더 복잡하고 체계적인 내용과 패턴이 존재했었구나"라고 생각하게 되는 계기가 되었고, 그러면서 이런 부분에서 깨달음을 알게 되는 3주였던 것 같습니다. 생각을 하고 머리를 짜내는 건 정말 고통스럽고 어렵고 힘들었지만, 그 고통만큼 값졌던 순간도 많았다고 생각이 듭니다.

리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문

  1. 저는 이번에 fsd 아키텍쳐를 해보면서 너무 진입장벽이 높고 각각의 레이어들의 역할과 뭔가 feature나,widget내에서 어떤 컴퍼넌트는 어디로 들어가는지 이런 부분이 각자 토론도 하고 의견이 많이 갈렸고, 저도 이 과정에서 헷갈렸던 부분이 많았습니다. 그래서 오히려 이게 좋은 구조인가 라는 의구심도 가지게 되었습니다. fsd아키텍쳐에 대해서 코치님도 어떤 생각을 가지고 있는지 좀 궁금합니다.!!

과제 피드백

성진님 고생하셨어요! 회고를 보니까 이번주는 정말 고민이 많았던것 같은데요 ㅎㅎ 전반적으로 잘 작성해주셨고 필요한 FSD규칙들에 대해서도 잘 정리해주신것 같아요.다만 규칙을 지키지 않고 엔티티에서 피처로 접근하거나, 피처에서 피처로 접근하는 경우가 있는 것 같네요! 이 레이어를 넘나드는 부분에 대해서는 정말 피치못할 상황이 아니라면 레이어를 끌어올려 처리하는게 좋을것 같아요.

저는 이번에 fsd 아키텍쳐를 해보면서 너무 진입장벽이 높고 각각의 레이어들의 역할과 뭔가 feature나,widget내에서 어떤 컴퍼넌트는 어디로 들어가는지 이런 부분이 각자 토론도 하고 의견이 많이 갈렸고, 저도 이 과정에서 헷갈렸던 부분이 많았습니다. 그래서 오히려 이게 좋은 구조인가 라는 의구심도 가지게 되었습니다. fsd아키텍쳐에 대해서 코치님도 어떤 생각을 가지고 있는지 좀 궁금합니다.!!

저희는 회사에서 이 규칙을 적용하고 있는데요. 사실 지금의 토론이 많이 갈리는 주제이겠지만 생각을 바꿔보면 저런 규칙이 없이 코드를 작성하다 보면 각자의 생각이 그냥 아무런 제약없이 녹여진다 라고 볼 수 있을 것 같아요. 그러다 보면 리뷰를 할 때 서로의 의견이 들어가다보니 반복적이게 논의를 해야 하는 경우도 많아지고 주제들이 프로젝트를 진행하면서 점점 산발적이게 생길것 같아요. 그럼 이 프로젝트를 운영하는 장기적 관점에서 이전에 논의했던것들은 자연스럽게 잊혀지고 결국 엉망진창 레거시 코드가 탄생하는 것 같아요. 하지만 FSD는 팀 내에서 미리 논의되어야 하는 주제거리를 던져 합의를 하게 하고 추후에 새로 들어오는 인원들은 별도의 논의 없이 이 규칙을 지키게 할 수 있게 되는거죠. 참여하고 있는 사람들도 '내 맘에는 안들지 몰라도' 적어도 프로젝트 자체가 잘 운영이되도록 코드가 작성되는것은 반박할 수 없을거에요. 그런 관점에서 접근을 한다면 나쁘지 않은 주제다!라고 생각할 수 있지 않을까요? ㅎㅎ(개발에 일가견 있는 분들끼리 저런거 하나하나 주제잡고 정하는건 늘 어렵고 빡센 일이니까요)

고생하셨고 다음주차도 화이팅입니다!