JiHoon-0330 님의 상세페이지[5팀 이지훈] Chapter 2-3. 관심사 분리와 폴더구조

배포링크: https://jihoon-0330.github.io/front_6th_chapter2-3/

과제 체크포인트

기본과제

목표 : 전역상태관리를 이용한 적절한 분리와 계층에 대한 이해를 통한 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 를 실제로 사용한 건 처음이었다. 기대 반 걱정 반으로 사용한 회고를 적어 본다.

FSD 는 최상위에 6개의 계층 폴더가 존재하고, 그 하위에 도메인을 나타내는 폴더들 또 그 하위에 세그먼트 폴더를 두는 구조로 이루어진다. 그래서 불필요한 복잡성을 증가시키지 않나? 라는 생각이 들었다. 과제를 예시로 들면 components/AddPostButton.tsx 으로 만들수 있는 컴포넌트를 features/posts/ui/AddPostButton.tsx 형태로 작성해야 한다. 단순히 폴더 구조만 복잡해 보이는 것이 아니라 AddPostButton.tsx 이라는 컴포넌트를 features 에 둔다는 결정을 해야하고, posts 의 하위에 둔다는 결정을 해야한다. 예시를 볼 땐 간단해 보이지만 막상 작업을 할 땐 Button 컴포넌트를 shared/ui에 따로 분리해야하나? 아니면 엔티티에 둘까? 그냥 분리하지 말까? 이런 고민들을 했다. 이런 고민을 하게 되는 이유는 계층을 인식하기 때문이라 느꼈다. 코끼리를 생각하지 말라고 하면 생각이 나는 것처럼, 계층이란 개념을 접한 상태 + 시각적으로 최상위 폴더에 위치하다 보니 이걸 어떤 게층에 넣어야하지? 굳이 불필요한 분류를 해가면서 각 계층마다 하나씩 넣으려하는 나의 모습을 보게 되었다. 과제를 하면서 FSD 에 대해 감을 잡았다 느낀 순간은 분리에 초점을 둘 수 있는 상태가 되었을때라 생각한다. 계층에 익숙해지면 원래 하던데로 코드를 분리할 수 있게 되는데, 이때 분리한 코드 덩어리를 어디에 넣을지만 생각하면 쉽게 접근이 가능해진다.

이것을 시각적으로 표현해보면

처음 접할 때 사고방식

처음 접할 때 사고방식 코드를 이미 분리한 상태에서 계층에 따라 다시 코드를 분리해야 하나? 를 생각했다.

계층에 대해 익숙해 진 후

계층만 선택 분리한 코드를 어떤 계층에 위치시킬 것인지만 선택한다.

과제를 진행하면서 만든 계층에 대한 기준

FSD 에서 계층은 단방향으로 참조가 가능하다. 따라서 참조를 고려해 계층을 나눠야 한다. 헷갈리는 계층에 대한 기준을 적어봤다.

  • 엔티티: 여러 기능에서 쓰일 코드들 혹은 엔티티를 다루는 함수들이 적절하다. 이유는 피쳐에서 사용할 수 있는 코드는 같은 세그먼트의 코드, 엔티티, 셰어드로 한정 되는데 프로젝트 전체에서 쓰이는 코드가 아니라면 일반적으로 피쳐, 엔티티 두 가지를 고려하게 된다. 이때 여러 기능에서 쓰일 수 있는 코드라면 엔티티에 두는 것이 가장 적절하다.
  • 피쳐: 기능에 대한 코드를 다룬다. 특정 기능에서만 활용하는 코드도 피쳐에 위치하는 것이 좋다. 엔티티에 두는 경우도 피쳐에서 사용 가능하지만 응집도를 높이기 위해 재사용 되지 않는 코드는 피쳐에 두는 것이 좋다고 생각했다. 예외적으로 API 는 하나의 피쳐에서 사용하더라도 엔티티에 뒀는데, 일부 API 는 엔티티에 존재하고, 일부 API 는 피쳐에 존재하면 일관성이 떨어지고 헷갈릴 수 있다고 생각했기 때문이다.
  • 위젯: 여러 피쳐를 조합하거나, 하나의 완전한 컴포넌트를 두는 것이 좋다.

기본과제와 심화과제를 진행하면서 위와 같은 기준이 만들어졌다.

최종과제를 하기 전에 다른 사람들은 어떤 방식으로 과제를 진행했는지 이야기를 나누기도 하고, 블로그 글을 찾아 보기도 했다. 그 중에 시도해 보고 싶다는 생각이 든 기준이 하나 있었는데, 상태를 변경하는 코드와 변경하지 않는 코드를 분류하는 것이었다. 상태를 변경하는 코드는 피쳐를 기준으로 두고, 상태를 변경하지 않는 코드는 엔티티에 두는 전략이다. 2주차에선 비즈니스 로직에 대한 순수 함수를 많이 만들어서 순수 함수의 장점을 알 수 있었다. 이번엔 컴포넌트 또한 state 를 다루는 컴포넌트와 아닌 컴포넌트를 분리하는 것으로 확장된 형태라 볼 수 있을 것 같다.

최종 변경 작업

응집도를 높이기 위해 폴더를 분리하는 방법을 사용했다. features/posts/add-posts/(segments) 이런 식으로 폴더 구조를 만들고 변경/삭제에 대한 코드를 옮겼다. 문제는 feature 를 다른 feature 에서 사용하는 경우 발생했다. 게시글 상세 모달의 경우 댓글 추가/변경/삭제/좋아요 와 같은 동작을 수행할 수 있다. 하지만 폴더 구조로 인해 같은 슬라이스 내의 코드를 가져올 수 없는 문제가 발생했다. (사용중인 fsd 린트 설정상 2 뎁스를 이동할 수 없다.) 대안으로 features/posts/(segments) 구조를 그대로 사용하기로 했다. 동작 별로 나눈 파일을 그대로 옮기니 세그먼터 안에 너무 많은 파일이 존재해 복잡하게 느껴졌다. 그래서 큰 분류로 묶어 하나의 파일에 작성하는 방식으로 변경했다.

- useAddComment.tsx
- useEditComment.tsx
- useDeleteComment.tsx
- ...

이런 구조에서

- useMutation.tsx
- ...

이렇게 바뀌었다.

컴포넌트 또한 아래와 같이 변경했다.

- AddCommentButton.tsx
- AddCommentDialog.tsx
- EditCommentButton.tsx
- EditCommentDialog.tsx
- DeleteCommentButton.tsx
- ...
- AddComment.tsx
- EditComment.tsx
- DeleteComment.tsx
- ...

한 파일에 많은 코드가 작성되는게 단점으로 느껴지기도 했지만, 파일 수를 줄이는 것이 덜 복잡하게 느껴졌다. 폴더의 깊이를 더할 수 없어 파일을 폴더의 역할로 사용하게 되었는데, 기능 별로 응집도를 높이지 못한 것이 아쉬운 것 같다.

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

  • 생각보다 분류할 수 있는 계층이 많이 존재한다.
  • FSD 를 실제로 적용해보니 계층이 더 필요하다 느껴질 때가 있었다. 구조를 잘 못 잡아서 그런 것 같다..
  • 단방향 참조가 생각보다 큰 제약으로 느껴졌다.
  • 삽질을 해보니 왜 FSD 에서 레이어 - 슬라이스 - 세그먼트로 분류 하는지 알 것 같다.

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

  • 폴더 구조를 예측 가능하도록 만들고 싶었다.
  • feature 이외의 파일은 순수 함수처럼 보지 않아도 되는 영역으로 만들고 싶었다.

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

  • features/posts/add-posts/(segments) 구조로 작업했을 때 위젯에서 기능을 props로 받았다면 어땠을지 고민이 된다.
  • FSD 를 사용하면서 add-post 처럼 하나의 기능을 하나의 모듈로 만들 수 있을까?

이번에 배운 내용 중을 통해 앞으로 개발에 어떻게 적용해보고 싶은지 적어주세요.

  • 보지 않아도 되는 안전 영역을 넓힐 수 있도록 폴더 구조를 적용해보고 싶다.
  • 상태를 업데이트 하지 않는 폴더와 상태를 업데이트 하는 폴더로 구분해보기

챕터 셀프회고

클린코드와 아키테쳑 챕터 함께 하느라 고생 많으셨습니다! 지난 3주간의 여정을 돌이켜 볼 수 있도록 준비해보았습니다. 아래에 적힌 질문들은 추억(?)을 회상할 수 있도록 도와주려고 만든 질문이며, 꼭 질문에 대한 대답이 아니어도 좋으니 내가 느꼈던 인사이트들을 자유롭게 적어주세요.

클린코드: 읽기 좋고 유지보수하기 좋은 코드 만들기

  • 더티코드를 접했을 때 어떤 기분이었나요? ^^; 클린코드의 중요성, 읽기 좋은 코드란 무엇인지, 유지보수하기 쉬운 코드란 무엇인지에 대한 생각을 공유해주세요

읽기 좋은 코드란, 코드 수정을 위해 어떤 코드를 봐야 하는지 쉽게 찾을 수 있는 코드라고 생각한다.

  • 선언적인 코드를 작성하기
  • 의미 있는 변수명 사용하기
  • 순수 함수 사용하기
  • 일관된 형태로 에러 처리하기
  • 예측 가능한 폴더 구조 만들기

같은 것들이 영향을 준다고 생각한다.

결합도 낮추기: 디자인 패턴, 순수함수, 컴포넌트 분리, 전역상태 관리

  • 거대한 단일 컴포넌트를 봤을때의 느낌! 처음엔 막막했던 상태관리, 디자인 패턴이라는 말이 어렵게만 느껴졌던 시절, 순수함수로 분리하면서 "아하!"했던 순간, 컴포넌트가 독립적이 되어가는 과정에서의 깨달음을 들려주세요

코드의 응집도가 적어서 해당 코드가 어떤 역할을 하는지 파악하기 어려웠다. 컴포넌트를 분리하고, 상태를 분리하는 것 만으로도 코드를 읽기 쉬워졌다. 이후 함수들을 순수 함수로 분리하면서 테스트 하기 쉬운 구조, 유지보수에 유리한 구조를 생각해 볼 수 있었다.

응집도 높이기: 서버상태관리, 폴더 구조

  • "이 코드는 대체 어디에 둬야 하지?"라고 고민했던 시간, FSD를 적용해보면서의 느낌, 나만의 구조를 만들어가는 과정, TanStack Query로 서버 상태를 분리하면서 느낀 해방감(?)등을 공유해주세요

플랫한 폴더 구조에서는 하지 않았던 고민을 할 수 있어서 의미가 있었던 것 같다. 앞으로 다시 플랫한 폴더 구조를 사용하더라도 계층을 고려하는 시각을 가질 수 있을 것 같다.

종합적으로 클린코드 챕터를 진행하면서 어려웠던 점들이 많았다. 평소 하지 않았던 고민들을 많이 하게 되었고, 고민을 하는 과정에서 평소에 이런 것들을 고려하지 않았다는걸 느끼게 되었다. 덕분에 막연하게 느껴졌던 클린코드에 대한 생각이 조금은 뚜렷해진 것 같다.

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

코치님은 현재 어떤 폴더 구조를 사용하고 계신지 궁금합니다. 사용중인 폴더 구조에서 장점과 단점은 어떤게 있나요? 질문의 의도는 단순히 사용중인 폴더 구조가 궁금한 것과 폴더 구조를 다룰때 어떤걸 더 중요하게 생각 하시는지 궁금합니다.

과제 피드백

회고에 있는 그림이 엄청 직관적이네요ㅋㅋㅋㅋ덕분에 어떤 과정을 거치셨는지 잘 이해할 수 있었습니다. 고생하셨습니다 지훈님. 전반적으로 핵심적인 부분들을 잘 이해하고 적용해주신 거 같아요! 탠스택 쿼리를 현재는 entity에 속해있는 경우가 있는데, 이 부분도 해석하는 사람마다 다르겠지만 단순히 해당 엔티티에 대한 페칭이 아닌 여러 액션을 담고 있는 부분이 있어 각 피처에서 다뤄야 한다는 얘기가 많이 있긴해요! 지금의 구조가 단순히 데이터를 조회하는 맥락이라면 엔티티의 위치도 좋지만 상태에 대한게 함께 전달이 되니 이렇게 되면 왔다갔다 하니까 규칙을 아예 만들어버리는 경우도 있구요 ㅎㅎ

코치님은 현재 어떤 폴더 구조를 사용하고 계신지 궁금합니다. 사용중인 폴더 구조에서 장점과 단점은 어떤게 있나요? 질문의 의도는 단순히 사용중인 폴더 구조가 궁금한 것과 폴더 구조를 다룰때 어떤걸 더 중요하게 생각 하시는지 궁금합니다.

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

장기적인 관점에서 커뮤니케이션 비용이 가장 적은것, 새로운 사람이 아무 정보없이 봤을 때 온보딩이 가장 쉬운 방식들을 사용하려는 편인것 같아요!

고생하셨고 다음주차 과제도 화이팅입니다~~