Skip to content

[2팀 이진희] Chapter 2-3. 관심사 분리와 폴더구조#25

Open
bebusl wants to merge 37 commits intohanghae-plus:mainfrom
bebusl:main
Open

[2팀 이진희] Chapter 2-3. 관심사 분리와 폴더구조#25
bebusl wants to merge 37 commits intohanghae-plus:mainfrom
bebusl:main

Conversation

@bebusl
Copy link

@bebusl bebusl commented Aug 11, 2025

과제 체크포인트

기본과제

목표 : 전역상태관리를 이용한 적절한 분리와 계층에 대한 이해를 통한 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가 정상적으로 작동하는가?

최종과제

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

과제 셀프회고

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

  • Jotai를 활용한 전역 상태 관리의 효율성: 기존에 복잡하게 관리되던 UI 상태(특히 모달의 열림/닫힘,
    데이터 등)를 Jotai의 아톰(atom)을 활용하여 훨씬 간결하고 직관적으로 관리할 수 있게 되었습니다. 각
    컴포넌트가 필요한 상태만 구독하고 업데이트함으로써 불필요한 리렌더링을 줄이고 성능을 최적화하는
    방법을 체감했습니다.
  • TanStack Query를 통한 서버 상태 관리의 해방감: 데이터 페칭, 캐싱, 동기화, 에러 처리 등 서버 상태
    관리에 필요한 복잡한 로직들을 TanStack Query가 대신 처리해주면서, 비동기 데이터 관리에 대한 부담을
    크게 줄일 수 있었습니다. useQuery, useMutation 훅을 통해 서버와의 상호작용을 선언적으로 관리하는
    방식이 매우 강력하다는 것을 깨달았습니다.
  • UI 컴포넌트의 재사용성과 모듈화: 모달과 같은 재사용 가능한 UI 요소들을 widgets 및 features/ui
    디렉토리로 분리하는 과정을 통해, 컴포넌트의 책임과 역할을 명확히 하고 재사용성을 극대화하는 방법을
    익혔습니다. 이는 코드의 응집도를 높이고 유지보수를 용이하게 하는 데 크게 기여했습니다.

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

  • 코드의 모듈화 및 관심사 분리: 특히 모달 관련 로직과 UI를 분리하고, 게시물 추가/수정 기능의 로직을
    캡슐화하는 등 각 기능의 책임 범위를 명확히 하려고 노력했습니다. 이를 통해 특정 기능의 변경이 다른
    부분에 미치는 영향을 최소화하고, 코드의 가독성과 유지보수성을 높이고자 했습니다.
  • 상태 관리 라이브러리(Jotai, TanStack Query)의 적절한 활용: 어떤 상태를 전역으로 관리하고, 어떤
    상태를 서버 상태로 관리할지 고민하며 각 라이브러리의 장점을 최대한 활용하려고 애썼습니다. 특히
    Jotai를 이용해 UI 상태를 세밀하게 제어하고, TanStack Query로 서버 데이터를 효율적으로 관리하는 데
    집중했습니다.

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

  • Jotai 아톰의 세분화 및 의존성 관리: 아톰을 너무 세분화할 경우 발생할 수 있는 관리의 복잡성이나, 아톰
    간의 의존성이 커질 때의 문제점에 대해 더 고민이 필요합니다. 어떤 단위로 아톰을 정의하는 것이 가장
    효율적인지에 대한 기준을 명확히 하고 싶습니다.
  • FSD(Feature-Sliced Design)와 같은 아키텍처 패턴의 깊이 있는 이해 및 적용: 현재 프로젝트 구조가 FSD와
    유사한 형태를 띠고 있지만, 각 레이어(entities, features, widgets, pages, shared) 간의 명확한 역할과
    상호작용 원칙에 대해 더 깊이 이해하고 실제 프로젝트에 완벽하게 적용하는 연습이 필요하다고 생각합니다.

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

  • 새로운 프로젝트 시작 시 Jotai와 TanStack Query 조합 적극 활용: 이번 과제를 통해 두 라이브러리의
    강력함을 체감했으므로, 앞으로 진행할 프론트엔드 프로젝트에서 이 조합을 기본 상태 관리 스택으로
    적극적으로 도입하고 싶습니다.
  • 재사용 가능한 UI 컴포넌트 라이브러리 구축: 모달과 같이 반복적으로 사용되는 UI 요소들을 shared/ui나
    widgets와 같은 형태로 분리하여 재사용성을 높이는 경험을 바탕으로, 나아가 프로젝트 전반에 걸쳐 재사용
    가능한 컴포넌트 라이브러리를 구축하는 연습을 해보고 싶습니다.
  • 클린 아키텍처 원칙 적용: 이번에 경험한 모듈화 및 관심사 분리 노력을 바탕으로, 앞으로는 더 큰 규모의
    프로젝트에서도 클린 아키텍처 원칙을 적용하여 견고하고 확장 가능한 코드베이스를 구축하는 데 집중할
    것입니다.

챕터 셀프회고

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

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

  • 더티코드를 접했을 때 어떤 기분이었나요? ^^; 클린코드의 중요성, 읽기 좋고 유지보수하기 쉬운 코드란
    무엇인지에 대한 생각을 공유해주세요
  • 더티코드를 접했을 때의 경험: 처음에는 기능 구현에 급급하여 코드를 작성하다 보니, 나중에 다시 보거나
    수정해야 할 때 어디를 건드려야 할지 막막하고, 작은 수정이 예상치 못한 버그로 이어지는 경험을 자주
    했습니다. 특히 거대한 함수나 컴포넌트 안에서 여러 책임이 뒤섞여 있을 때의 답답함은 이루 말할 수
    없었습니다.
  • 클린코드의 중요성: 클린코드는 단순히 코드를 예쁘게 만드는 것을 넘어, 개발 생산성과 팀 협업의
    핵심이라는 것을 깨달았습니다. 읽기 좋은 코드는 디버깅 시간을 단축시키고, 새로운 기능 추가를 용이하게
    하며, 동료 개발자들이 코드를 이해하고 기여하는 데 큰 도움을 줍니다.
  • 읽기 좋고 유지보수하기 쉬운 코드란:
    • 명확한 이름 짓기: 변수, 함수, 클래스 이름만으로도 그 역할과 목적을 유추할 수 있어야 합니다.
    • 단일 책임 원칙(SRP) 준수: 하나의 함수나 컴포넌트는 하나의 책임만 가져야 합니다. 이를 통해 변경의
      파급 효과를 줄일 수 있습니다.
    • 작고 응집된 함수/컴포넌트: 코드를 작은 단위로 쪼개어 각 단위가 명확한 역할을 수행하도록 합니다.
    • 불필요한 주석 제거 및 자가 설명적인 코드 작성: 코드가 스스로를 설명하도록 작성하고, 주석은 '왜'
      그렇게 했는지에 대한 이유를 설명하는 데 사용합니다.

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

  • 거대한 단일 컴포넌트를 봤을때의 느낌! 처음엔 막막했던 상태관리, 디자인 패턴이라는 말이 어렵게만
    느껴졌던 시절, 순수함수로 분리하면서 "아하!"했던 순간, 컴포넌트가 독립적이 되어가는 과정에서의
    깨달음을 들려주세요
  • 거대한 단일 컴포넌트의 문제점: 모든 로직과 UI가 한 컴포넌트에 몰려있는 경우, 코드를 이해하는 데
    시간이 오래 걸리고, 특정 기능을 수정하려 할 때 다른 기능에 영향을 줄까 봐 두려웠습니다. 재사용은
    꿈도 꾸기 어려웠습니다.
  • 상태 관리의 막막함과 해결: 초기에는 useState와 useContext만으로 복잡한 전역 상태를 관리하는 것이
    어렵게 느껴졌습니다. 특히 모달의 열림/닫힘 상태나 사용자 정보와 같은 전역적으로 필요한 데이터들을
    어떻게 효율적으로 전달하고 업데이트할지 고민이 많았습니다. 하지만 Jotai와 같은 전역 상태 관리
    라이브러리를 도입하면서, 상태를 아톰 단위로 분리하고 필요한 컴포넌트에서만 구독하는 방식이 훨씬
    깔끔하고 성능에도 이점을 준다는 것을 깨달았습니다.
  • 순수 함수와 컴포넌트 분리의 "아하!" 모먼트: 특정 로직을 순수 함수로 분리하거나, UI와 로직을 분리하여
    컴포넌트를 독립적으로 만드는 과정에서 코드의 테스트 용이성이 높아지고, 재사용성이 극대화되는 것을
    경험했습니다. 특히 모달 컴포넌트들을 widgets로 분리하고, 각 모달 내부의 상태 관리 로직을 Jotai
    아톰으로 캡슐화하면서, 컴포넌트가 훨씬 독립적이고 재사용 가능한 단위가 되는 것을 보며 큰 깨달음을
    얻었습니다. 이는 결합도를 낮추는 실질적인 방법임을 체감했습니다.

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

  • "이 코드는 대체 어디에 둬야 하지?"라고 고민했던 시간, FSD를 적용해보면서의 느낌, 나만의 구조를
    만들어가는 과정, TanStack Query로 서버 상태를 분리하면서 느낀 해방감(?)등을 공유해주세요
  • 코드 위치에 대한 고민: 프로젝트 초기에는 어떤 코드를 어디에 두어야 할지 항상 고민이었습니다. 특히
    API 호출 로직, UI 컴포넌트, 비즈니스 로직 등이 뒤섞여 있어 파일 구조가 점점 복잡해지는 경향이
    있었습니다.
  • FSD 적용 경험: entities, features, widgets, pages, shared와 같은 폴더 구조를 적용하면서, 각 코드의
    책임과 위치가 명확해지는 것을 느꼈습니다. "이 코드는 대체 어디에 둬야 하지?"라는 고민이 줄어들고,
    새로운 기능을 추가하거나 기존 기능을 수정할 때 해당 기능과 관련된 파일들을 한눈에 파악하기
    쉬워졌습니다. 이는 코드의 응집도를 높이는 데 매우 효과적인 방법이었습니다.
  • TanStack Query를 통한 서버 상태 분리의 해방감: 이전에는 useEffect와 useState를 조합하여 직접 서버
    데이터를 관리하고, 로딩, 에러, 캐싱 등을 수동으로 처리해야 했습니다. 이 과정에서 많은 보일러플레이트
    코드가 발생하고, 복잡성이 증가했습니다. 하지만 TanStack Query를 도입하면서, 서버 상태와 클라이언트
    상태를 명확히 분리하고, 데이터 페칭 및 동기화에 대한 모든 복잡성을 라이브러리에 위임할 수 있게
    되었습니다. 이는 마치 무거운 짐을 내려놓은 듯한 '해방감'을 주었으며, 개발자가 비즈니스 로직에 더
    집중할 수 있게 해주었습니다.

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

  • 모달 관리를 어떻게 하시나요? - 개인적으로 모달을 전역상태관리 라이브러리를 이용해 관리하는 게 베스트 프랙티스인지 잘 모르겠습니다.
    • 현재 프로젝트에서는 Jotai 아톰을 활용하여 각 모달의 열림/닫힘 상태와 모달에 전달될 데이터를
      관리하고 있습니다. 예를 들어, addPostModalAtom과 같은 아톰을 만들어 모달의 가시성을 제어하고,
      postDetailModalDataAtom과 같이 모달에 필요한 데이터를 담는 아톰을 별도로 두어 관리합니다.
    • 모달을 띄우는 컴포넌트에서는 해당 모달 아톰의 상태를 업데이트하여 모달을 열고, 모달 내부에서는
      닫기 버튼 클릭 시 아톰 상태를 초기화하여 모달을 닫는 방식입니다.
    • 이러한 방식이 모달 관리에 있어 가장 효율적이고 확장 가능한 방법인지, 혹은 여러 종류의 모달이
      중첩되거나, 모달 간의 복잡한 상호작용이 필요할 때의 베스트 프랙티스가 궁금합니다.

bebusl added 30 commits August 11, 2025 21:05
- TanStack Query를 사용한 데이터 페칭 및 뮤테이션 로직을
  각 feature의 model 디렉토리로 분리하여 재사용성을 높임.
- usePosts, useComments, useAddPost 등 관련 훅 생성.
@JunilHwang JunilHwang requested a review from Copilot August 15, 2025 03:01

This comment was marked as resolved.

Copy link
Contributor

@JunilHwang JunilHwang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요, 이진희 님! 5주차 과제 잘 진행해주셨네요. 고생하셨습니다 👍🏻👍🏻
현재 남기는 코멘트는 GPT-5-mini model을 사용하여 AI가 남기는 피드백입니다 🤖
과제 피드백과는 별개이므로 참고해주세요!

1. 🏗️ FSD 아키텍처

💡 개념 정의

Feature-Sliced Design(FSD)은 애플리케이션을 명확한 관심사 단위(app/pages/widgets/features/entities/shared)로 분리해 책임을 한 곳에 집중시키는 아키텍처 원칙입니다. 하위 레이어(entities/shared)는 상위 레이어(features/pages)에서 참조하지만 반대는 허용되지 않습니다.

⚡ 중요성

FSD 준수는 변경에 대한 영향을 최소화하고, 팀 간 경계를 명확히 하며 모듈화/독립적 테스트/패키지 분리(모노레포 전환 등)를 용이하게 합니다.

📊 현재 상황 분석

AS-IS: pages/posts-manager contains heavy business logic + direct queries (getPosts) and multiple mutation implementations. There is also an existing feature hook (features/posts-management/model/usePosts.ts) that implements similar behavior, but pages still implements its own queries, causing duplication and violating single responsibility for layers.

📝 상세 피드백

전체적으로 Feature-Sliced Design(FSD)을 염두에 둔 폴더 구조와 레이어 분리가 잘 시도되어 있습니다. entities에 순수한 API와 타입/모델을 두고, features에 행동(훅, 모달 상태 관리), widgets에 모달 등 재사 용 UI를 둔 점은 긍정적입니다. 다만 페이지 레이어(src/pages/posts-manager/index.tsx)에 비즈니스 로직(게시물/유저 조합, 쿼리 전략)이 중복으로 존재해 FSD의 역할 분리가 완전히 지켜지지 않는 부분이 있습니 다. 결과적으로 새로운 기능 추가(예: 서버 API 변경, 페이징 로직 변경) 시 수정 범위가 넓어집니다.

❌ 현재 구조 (AS-IS)

src/pages/posts-manager/index.tsx: getPosts 함수가 searchPostsApi, fetchPostsByTagApi, fetchPostsApi, fetchUsersApi를 직접 호출하여 postsWithUsers를 구성하고 useQuery를 페이지에서 직접 사용함.

✅ 권장 구조 (TO-BE)

TO-BE: pages에서는 feature (usePosts ) 호출해 결과만 렌더링. 모든 데이터 조합(: posts + author 병합) feature 레이어에서 제공:
// features/posts-management/api/index.ts (또는 model/usePosts.ts)
export const usePosts = (params) => useQuery({ queryKey: queryKeys.posts(params), queryFn: () => postsService.getPostsWithAuthors(params) })
// pages: const { data } = usePosts(params); render table only.

🔄 변경 시나리오별 영향도

  1. 기술 스택 변화(예: 상태관리 라이브러리) 시: pages가 직접 Jotai 사용과 쿼리를 관리하므로 전환 비용이 커짐 (여러 파일 수정 필요).
  2. 아키텍처 변화(예: 모노레포로 패키지 분리) 시: pages에 비즈니스 로직이 섞여 있으면 도메인 패키지로 추출하기 어려움.
  3. 기능 추가(예: 다국어 타이틀 표시) 시: 페이지 내부에 로직이 산재하면 여러 위치에서 중복 수정 필요.

🚀 개선 단계

  • 1단계: 단기(1-2일): pages/posts-manager에서 직접 사용중인 getPosts 로직을 features/posts-management/model/usePosts로 위임. 페이지는 파라미터 관리 및 렌더링만 담당하게 리팩토링.
  • 2단계: 중기(2-4일): features 레이어에 queryKeys와 서비스를 도입(queryKeys/posts, postsService.getPostsWithAuthors). pages가 직접 엔티티 API를 사용하지 않도록 정리.
  • 3단계: 장기(1주): 레이어 경계(문서화 + lint 규칙)를 도입해 import 규칙을 강제(app → pages → widgets → features → entities → shared). CI에서 FSD-import 검사 스크립트 추가.

2. 🔄 TanStack Query

💡 개념 정의

TanStack Query는 서버 상태(fetching, caching, synchronization)를 선언적으로 관리해주는 라이브러리로, queryKey 패턴, queryFn 분리, staleTime/cacheTime, 에러/로딩 상태 처리, optimistic update 등을 활용 할 수 있습니다.

⚡ 중요성

일관된 queryKey 패턴과 API 계층 분리는 API 변경, 새로운 데이터 소스 추가, 에러 전략 변경 시 수정 범위를 줄여 유지보수성을 높입니다.

📊 현재 상황 분석

AS-IS: queryKey가 분산되어 있고 중앙화되지 않음. 일부 훅은 API 호출을 직접 사용(예: AddCommentForm에서 addCommentApi 직접 호출)하여 react-query의 일관된 패턴을 훼손. optimistic update, onError 사용자 알림, 캐싱 정책 미정의 등.

📝 상세 피드백

TanStack Query를 전반적으로 잘 활용하고 있습니다: 대부분의 API 호출이 useQuery/useMutation으로 래핑되어 있고, QueryClientProvider가 전역에 적용되어 있습니다. 그러나 쿼리 키 관리와 캐싱 전략, 에러/UX 핸들링, 중복 로직 제거 측면에서 개선 여지가 있습니다.

❌ 현재 구조 (AS-IS)

AS-IS: usePosts uses queryKey: ['posts', { skip, limit, searchQuery, ... }] directly and getPosts composes multiple entity apis inside the hook; AddCommentForm calls addCommentApi directly with useState instead of using useAddComment.

✅ 권장 구조 (TO-BE)

TO-BE: 중앙화된 queryKeys 모듈 + 서비스 계층 + feature  사용:
// shared/api/queryKeys.ts
export const queryKeys = { posts: (params) => ['posts', JSON.stringify(params)] as const, post: (id) => [...queryKeys.posts({}), id] }
// features/posts/model/usePosts.ts
export const usePosts = (params) => useQuery(queryKeys.posts(params), () => postsService.getPostsWithAuthors(params), { staleTime: 1000 * 60 * 2, keepPreviousData: true })
// AddCommentForm -> useAddComment.mutateAsync(...) to get react-query benefits (invalidate, onSuccess centralized).

🔄 변경 시나리오별 영향도

  1. API 엔드포인트가 변경되면: 현재 entities/apis가 fetchClient를 사용하므로 엔티티 레이어만 수정하면 됨. 그러나 페이지 내 중복 로직을 수정해야 할 가능성(중복된 getPosts)이 존재.
  2. 새로운 데이터 소스 추가(예: socket 실시간) 시: 쿼리 키 패턴과 데이터 조합이 흩어져 있으면 기존 쿼리와의 통합 비용 증가.
  3. 에러 처리 방식 변경(글로벌 에러 UI 도입) 시: 각 useMutation/onError가 console.error로 처리하므로 모든 훅을 수정해야 함.

🚀 개선 단계

  • 1단계: 단기(반나절~1일): QueryClient 생성 시 기본 옵션(staleTime, cacheTime, defaultOptions.queries) 설정하고 React Query Devtools를 추가.
  • 2단계: 단기(1-2일): queryKeys 모듈(shared/api/queryKeys.ts) 도입, 기존 코드의 queryKey를 이 모듈로 교체(자동화 스크립트 권장).
  • 3단계: 중기(1-3일): 모든 API 호출을 entities/api (순수 CRUD)와 features/hooks (비즈니스 로직)로 분리. AddCommentForm 등은 useAddComment 훅으로 대체.
  • 4단계: 중기(2-4일): 에러/성공 메시지 전략 도입 (toasts 또는 ErrorBoundary 연동), optimistic update가 필요한 mutation에 대해 구현 및 rollback 전략 수립.

3. 🎯 응집도 (Cohesion)

💡 개념 정의

응집도(Cohesion)는 같은 모듈 내 요소들이 얼마나 관련이 깊은지를 나타내며, 관련 변경이 한 곳에 집중되면 높은 응집도로 평가됩니다.

⚡ 중요성

높은 응집도는 유지보수 비용을 낮추고 모듈 단위 테스트 및 패키지 전환(모노레포) 시 유리합니다.

📊 현재 상황 분석

AS-IS: 특정 기능(게시물 조회 + author 병합)이 features/usePosts와 pages 내부에서 중복되어 있어 어느 부분이 진짜 책임인지 불명확. UI 컴포넌트와 로직이 섞인 부분도 존재(예: AddCommentForm 주석에 'TODO: hook으로 분리' 명시).

📝 상세 피드백

응집도는 일부 도메인에서 매우 좋으나(entities 내부의 api/types 분리, features의 model/ui 분리) pages에 비즈니스 로직이 혼재되어 있어 응집도가 떨어지는 영역이 있습니다. 또한 AddCommentForm이 feature 훅을 사용하지 않고 직접 API를 호출해 모듈화가 약화되어 있습니다.

❌ 현재 구조 (AS-IS)

AS-IS: src/features/add-comment/ui/AddCommentForm.tsx 직접 addCommentApi 호출  로컬 useState 사용.

✅ 권장 구조 (TO-BE)

TO-BE: AddCommentForm은 순수한 presentational component로 변환하고 비즈니스 로직은 useAddComment 훅에 위임:
const AddCommentForm = ({onSuccess}) => { const { mutate } = useAddComment(); return <Form onSubmit={() => mutate({body, postId})} /> }
useAddComment에서 onSuccess/invalidate 처리.

🔄 변경 시나리오별 영향도

  1. 새 필드(예: 게시물에 요약 필드 추가) 추가 시 현재 구조: pages와 feature 훅 둘 다 수정해야 할 수 있음(약 68개 파일). 개선 구조: feature 서비스 1곳만 수정하면 됨(12개 파일).
  2. 패키지 분리 시: 높은 응집도의 모듈은 쉽게 떼어낼 수 있지만, 페이지에 섞인 로직은 추출 작업이 복잡해짐.

🚀 개선 단계

  • 1단계: 단기(1일): AddCommentForm 등 UI 컴포넌트에서 API 호출 제거 및 feature 훅으로 대체.
  • 2단계: 중기(2-3일): pages/posts-manager의 데이터 로직을 usePosts(또는 service)로 이동하여 페이지는 렌더링만 담당하게 리팩토링.
  • 3단계: 장기(1주): 도메인별(예: posts, comments, users) 패키지 문서화 및 테스트 케이스 정리로 응집도 검증.

4. 🔗 결합도 (Coupling)

💡 개념 정의

결합도(Coupling)는 모듈이 다른 모듈의 구체적 구현에 얼마나 의존하는지를 의미합니다. 낮은 결합은 모듈 교체와 테스트 용이성을 높입니다.

⚡ 중요성

낮은 결합은 기술 스택 변경(axios→fetch, Jotai→Zustand 등) 시 수정 범위를 최소화합니다.

📊 현재 상황 분석

AS-IS: 많은 컴포넌트가 useSetAtom/useAtomValue 같은 Jotai API를 직접 사용하여 상태를 소비하고 있어 상태관리 라이브러리 교체 시 전환 비용이 큼(원시적으로 전역 atom에 묶여 있음). fetchClient 한 곳만 바 꾸면 HTTP 클라이언트 변경 비용은 작음.

📝 상세 피드백

대체로 모듈 간 결합은 인터페이스(함수/훅)를 통해 이루어지고 있으나, 일부 직접 의존성과 Radix/lucide 같은 외부 라이브러리에 대한 노출이 결합도를 높입니다. 또한 pages에서 entities API를 직접 호출하는 등 레이어 간 경계가 느슨해지는 부분이 있습니다.

❌ 현재 구조 (AS-IS)

AS-IS: src/widgets/post-detail-modal/index.tsx: import { DialogTitle } from "@radix-ui/react-dialog"  shared/Dialog의 추상화를 우회하고 Radix API에 직접 결합되어 있음.

✅ 권장 구조 (TO-BE)

TO-BE: 모든 위젯은 shared/ui의 Dialog(혹은 wrapper) API만 사용:
// widgets/post-detail-modal/index.tsx
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '../../shared/ui'
// 더 이상 Radix 직접 import 없음.

🔄 변경 시나리오별 영향도

  1. HTTP 클라이언트 교체(예: fetch → axios): fetchClient 한 파일만 변경하면 됨(1파일).
  2. 상태관리 라이브러리 교체(Jotai → Zustand): atom을 사용하는 모든 파일(대략 25-30개 파일)에 hook/adapter 레이어가 없을 경우 큰 리팩토링(약 25~30개 파일 변경 필요).
  3. UI 라이브러리 변경(Radix/Icons → 다른 라이브러리): shared/ui의 컴포넌트가 Radix/lucide에 의존하므로 shared/ui 안의 wrapper만 변경하면 되지만, 직접 Radix를 import한 위젯이 있다면 추가 수정을 해야 함.

🚀 개선 단계

  • 1단계: 단기(반나절): 파일에서 직접 외부 라이브러리(Radix, lucide)를 import한 케이스를 탐지해 shared wrapper로 바꾸기. (예: post-detail-modal의 DialogTitle 교체).
  • 2단계: 중기(2-3일): 상태 접근을 직접 atom에 의존하지 않도록 커스텀 훅으로 래핑(useModal(name) 등)해 상태관리 라이브러리 추상화 레이어를 도입.
  • 3단계: 장기(1주): 상태관리 adapter 패턴을 도입하여 Jotai 전용 코드와 앱 로직을 분리(변경 시 adapter만 교체).

5. 🧹 Shared 레이어 순수성

💡 개념 정의

Shared 레이어는 도메인에 독립적인 재사용 가능한 유틸과 UI 컴포넌트를 담아 여러 도메인에서 재사용되어야 합니다. 도메인 로직을 포함하면 재사용성이 떨어집니다.

⚡ 중요성

Shared 레이어가 순수하면 새로운 프로젝트에서 재사용하기 쉽고 디자인 시스템 변경 시 영향 범위가 작습니다.

📊 현재 상황 분석

AS-IS: 많은 UI primitives가 shared에 있음 → 좋음. 그러나 일부 위젯이 shared API를 우회하여 외부 라이브러리를 직접 사용한 사례 존재 → shared의 순수성 훼손.

📝 상세 피드백

shared 레이어에 UI primitives(Button, Dialog, Table 등)와 fetchClient가 잘 모여 있어 재사용성과 도메인 독립성 확보에 유리합니다. 다만 shared/Dialog 구현에서 Radix 및 lucide에 직접 의존하고 있고, 일부 위젯에서 Radix를 직접 import 하는 사례가 있어 shared 레이어를 우회하는 점이 문제입니다. 또한 shared/ui exports에 Footer/Header가 "renamed" 상태로 보이는데 실제 구현이 일관되게 유지되고 있는지 확인 필 요합니다.

❌ 현재 구조 (AS-IS)

AS-IS: widgets/post-detail-modal/index.tsx imports DialogTitle directly from '@radix-ui/react-dialog' instead of shared/ui/Dialog exports.

✅ 권장 구조 (TO-BE)

TO-BE: 모든 UI는 shared/ui의 contract(버튼, dialog, icons wrapper ) 사용. shared/Dialog 내부에서 Radix를 캡슐화하고 위젯은 캡슐화된 API만 사용.

🔄 변경 시나리오별 영향도

  1. 디자인 시스템 변경(Material UI → Chakra UI): shared/ui 내부 컴포넌트만 수정하면 되지만 Radix를 직접 참조한 위젯이 있으면 추가 수정 필요(예: post-detail-modal).
  2. 새 프로젝트에서 재사용: shared는 재사용 가능성이 높음(많은 primitives 포함).

🚀 개선 단계

  • 1단계: 단기(반나절): 프로젝트 전체에서 '@radix-ui/react-dialog' 직접 import한 파일을 식별하고 shared/Dialog로 대체할 수 있는지 점검.
  • 2단계: 단기(1일): shared/ui 내부에 Icons wrapper를 만들고 lucide 직접 import를 캡슐화하여 아이콘 라이브러리 변경 시 영향 최소화.
  • 3단계: 중기(2-3일): shared exports(./shared/ui/index.ts)를 정리해 모든 UI 컴포넌트가 중앙에서 import되도록 강제.

6. 📐 추상화 레벨

💡 개념 정의

추상화는 복잡한 구현 세부사항을 숨기고 재사용 가능한 상위 수준 인터페이스(서비스, 훅)를 제공하는 것입니다.

⚡ 중요성

추상화 수준이 높으면 기술 스택 변경(HTTP 클라이언트, 인증 방식 등) 시 영향 범위를 줄일 수 있고, 테스트와 유지보수성이 향상됩니다.

📊 현재 상황 분석

AS-IS: 혼재된 추상화 레벨으로 인해 동일한 책임이 여러 곳에 존재. 이는 기능 확장 또는 라이브러리 변경 시 중복 수정을 발생시킴.

📝 상세 피드백

비즈니스 로직과 기술적 세부사항의 분리는 일부 잘 되어 있으나 페이지 레이어와 일부 UI가 API 호출/상태 변화를 직접 다루는 경우(예: AddCommentForm, PostsManager)가 있어 추상화 수준을 높일 필요가 있습니다. 서비스 계층/훅으로 추상화하면 재사용과 테스트성이 좋아집니다.

❌ 현재 구조 (AS-IS)

AS-IS: src/features/add-comment/ui/AddCommentForm.tsx uses addCommentApi directly and manages local state; a comment hook already exists (features/add-comment/model/useAddComment.ts).

✅ 권장 구조 (TO-BE)

TO-BE: AddCommentForm becomes a presentational component receiving onSubmit prop; business logic moved to useAddComment hook which internally calls addCommentApi and handles react-query mutations and invalidations.

🔄 변경 시나리오별 영향도

  1. API 인증 방식 변경(OAuth 토큰 형식 변경): fetchClient만 변경하면 되는 경우와 페이지에서 직접 Authorization 헤더를 추가한 경우의 차이.
  2. 상태관리 라이브러리 변경: 컴포넌트들이 atom을 직접 사용하는 경우 adapter 미비로 변경 비용 증가.

🚀 개선 단계

  • 1단계: 단기(반나절): AddCommentForm과 같은 컴포넌트의 API 호출을 feature 훅으로 위임.
  • 2단계: 중기(1-2일): entities 서비스 계층과 features 훅 간에 명확한 역할 문서화(누가 CRUD를 담당하는지)를 작성.
  • 3단계: 장기(1주): Fetch/HTTP, 상태관리(Jotai) 접근을 추상화하는 adapter layer를 도입해 기술 교체 비용을 줄임.

7. 🧪 테스트 용이성

💡 개념 정의

테스트 용이성은 코드가 단위 테스트/통합 테스트로 검증하기 쉬운 정도로, 사이드 이펙트가 분리되고 의존성이 주입 가능한 구조가 바람직합니다.

⚡ 중요성

높은 테스트 용이성은 리팩토링/버그 수정을 안전하게 하고 CI 파이프라인에서의 자동화 커버리지를 향상시킵니다.

📊 현재 상황 분석

AS-IS: 많은 컴포넌트가 UI와 로직을 같이 포함. tests 디렉토리 또는 jest/rtl 설정은 보이지 않음. usePosts 훅은 비즈니스 로직을 분리하려는 시도지만 pages가 직접 유사 로직을 구현해 중복 테스트 지점을 생성함.

📝 상세 피드백

테스트를 고려한 분리는 일부 이루어졌습니다(entities의 순수 API, shared UI 컴포넌트). 그러나 많은 컴포넌트가 내부에서 side-effect(직접 API 호출, useQuery/useMutation 직접 호출, useSetAtom 사용)를 하고 있어 단위 테스트를 쉽게 작성하기 어렵습니다. 순수 컴포넌트 분리 및 훅의 의존성 주입을 권장합니다.

❌ 현재 구조 (AS-IS)

AS-IS: AddCommentForm uses useState + direct addCommentApi call in try/catch making it harder to mock react-query behaviour.

✅ 권장 구조 (TO-BE)

TO-BE: Presentational AddCommentForm only emits submit event; useAddComment hook handles mutation and side effects; tests can mock useAddComment return value.

🔄 변경 시나리오별 영향도

  1. 새로운 외부 API 연동(예: analytics) 시: 컴포넌트 내부에 직접 analytics.track이 있으면 모든 컴포넌트 테스트에서 mocking 필요.
  2. E2E에서 비정상 상태 테스트 시: 모달 상태와 query의 결합 때문에 시나리오 작성이 복잡.

🚀 개선 단계

  • 1단계: 단기(1-2일): presentational/container 패턴 적용 — UI 컴포넌트는 props로 데이터와 콜백을 받고 비즈니스 로직/상태는 훅으로 분리.
  • 2단계: 중기(2-4일): 주요 훅(usePosts, useComments 등)에 대한 단위 테스트 추가 및 mock react-query 환경 구성.
  • 3단계: 장기: CI에 테스트 실행 파이프라인 연결 및 커버리지 목표 설정.

8. ⚛️ 현대적 React 패턴

💡 개념 정의

현대 React 패턴은 Suspense와 Error Boundary를 통한 선언적 로딩/에러 처리, 커스텀 훅을 통한 관심사 분리, 컴포넌트의 단일 책임 원칙 준수를 포함합니다.

⚡ 중요성

이 패턴들은 로딩/에러 UI의 일관성을 확보하고 코드의 가독성을 높이며 디버깅 생산성을 향상시킵니다.

📊 현재 상황 분석

AS-IS: 대부분 훅은 react-query 사용(선언적) 이지만, UI 레벨에서 Suspense/ErrorBoundary를 사용하지 않아 로딩/에러 처리가 분산됨.

📝 상세 피드백

React Query와 커스텀 훅을 활용한 선언적 패턴은 잘 사용하고 있습니다. 다만 Suspense, Error Boundary, React Query의 useErrorBoundary 또는 suspense 옵션을 활용한 선언적 에러/로딩 처리는 미적용 상태이며, 컴포넌트가 여전히 내부에서 명령형 로직(try/catch, useState 관리)을 하는 곳이 존재합니다. 또한 Query Devtools 미적용으로 디버깅 경험 개선 여지가 있습니다.

❌ 현재 구조 (AS-IS)

AS-IS: <PostsManager /> handles loading and error inline (if(postsLoading) return '로딩 중...').

✅ 권장 구조 (TO-BE)

TO-BE: 상위에서 <ErrorBoundary> <Suspense fallback={<Skeleton />}>  PostsManager  :
<ErrorBoundary fallback={<ErrorFallback/>}><Suspense fallback={<PostsSkeleton/>}><PostsManager/></Suspense></ErrorBoundary>

🔄 변경 시나리오별 영향도

  1. 로딩 UX 전략 변경(글로벌 skeleton 적용) 시: Suspense를 도입하면 로딩 UI를 일관되게 적용 가능.
  2. 에러 처리 UX 개선(전체 앱 에러 모달) 시: ErrorBoundary 연동을 통해 중앙 조정이 쉬워짐.

🚀 개선 단계

  • 1단계: 단기(반나절): React Query Devtools 추가 및 QueryClient 옵션으로 suspense/errorBoundary 연동 고려.
  • 2단계: 중기(1-2일): 페이지/위젯에 Suspense + ErrorBoundary 적용해 로딩/에러 UI를 중앙화.
  • 3단계: 중기: 명령형 try/catch가 있는 컴포넌트를 훅으로 분리하여 선언형 패턴으로 전환.

9. 🔧 확장성

💡 개념 정의

확장성은 새로운 기능이나 비기능 요구사항이 생겼을 때 기존 코드를 얼마나 적게 변경하면서 확장할 수 있는지를 말합니다.

⚡ 중요성

프로덕트 성장에 따라 새로운 요구사항(다국어, 실시간, 오프라인 등)을 빠르게 추가하려면 낮은 변경 비용이 필수입니다.

📊 현재 상황 분석

AS-IS: HTTP 클라이언트 변경은 쉽지만 상태관리 또는 UI 라이브러리 변경 시 많은 파일 수정 필요(특히 Jotai atom을 직접 사용하는 컴포넌트들).

📝 상세 피드백

구조적으로 확장 가능성이 높지만(entities/features/widgets 분리), pages에 비즈니스 로직 중복과 direct atom 사용이 있어 새로운 요구사항(예: 낙관적 업데이트, 오프라인 모드, A/B 테스트) 도입 시 리팩토링 비용이 발생할 수 있습니다. 특히 상태관리 교체 시 atom 사용량이 많아 변화 비용이 큽니다.

❌ 현재 구조 (AS-IS)

AS-IS: useLikeComment/useDeleteComment perform onSuccess invalidations; no optimistic update implemented.

✅ 권장 구조 (TO-BE)

TO-BE: useLikeComment implements optimistic update via onMutate -> return rollback function; centralize invalidation logic in hooks.

🔄 변경 시나리오별 영향도

  1. 낙관적 업데이트 도입: 현재 mutation들(onSuccess에서 invalidateQueries) -> 낙관적 업데이트로 전환 시 useMutation의 onMutate/onError/onSettled 로직을 각 훅에서 추가해야 함(여러 훅 수정 가능).
  2. 오프라인 지원 추가: react-query의 persistence를 도입하면 서버 상태는 비교적 적은 수정으로 가능하지만, 클라이언트 state가 atom에 분산되어 있으면 동기화 로직이 복잡해짐.

🚀 개선 단계

  • 1단계: 단기(1-2일): mutation에 대해 optimistic update 가능성을 검토할 주요 훅 식별(useLikeComment 등) 및 설계 문서 작성.
  • 2단계: 중기(3-5일): optimistic update 시나리오를 구현 및 테스트(rollback 포함).
  • 3단계: 장기(1-2주): 오프라인/실시간 확장을 고려한 전체 상태 아키텍처(react-query + indexedDB/persistence, atom 동기화) 설계.

10. 📏 코드 일관성

💡 개념 정의

코드 일관성은 네이밍/파일명/Import/Export 패턴 및 스타일(들여쓰기, 세미콜론 등)이 프로젝트 전반에 일관되게 적용되는 상태를 말합니다.

⚡ 중요성

일관성은 가독성, 자동화 도구 적용(ESLint/Prettier/CI), 팀 협업 속도를 개선합니다.

📊 현재 상황 분석

AS-IS: 혼재된 네이밍과 export 방식이 존재해 신규 기여자에게 학습 비용 증가 및 자동화 검사 실패 가능성이 큼.

📝 상세 피드백

프로젝트 전반에 걸쳐 일관된 스타일 규칙이 일부 지켜지고 있으나 파일명/네이밍/Import 패턴의 혼재와 몇 가지 명백한 실수(중복 export, 잘못된 import)가 관찰됩니다. 코드 일관성 향상은 새로운 개발자 온보딩 과 자동화 도구 적용 시 큰 효과가 있습니다.

❌ 현재 구조 (AS-IS)

AS-IS examples:
- src/features/posts-management/ui/posts-table.tsx (kebab-case file name)
- src/widgets/add-post-modal/index.tsx has duplicated 'export default AddPostModal'
- src/widgets/post-detail-modal/index.tsx imports DialogTitle directly from '@radix-ui/react-dialog'.

✅ 권장 구조 (TO-BE)

TO-BE: 파일명 규칙 적용 (Components  PascalCase), 모든 컴포넌트 named export 권장, shared wrapper만 사용.
- rename posts-table.tsx  PostsTable.tsx
- remove duplicate export in add-post-modal
- replace direct Radix imports with shared/Dialog exports

🔄 변경 시나리오별 영향도

  1. 자동 포맷터/린터 도입 시: 규칙 지정 후 대규모 변경이 필요할 수 있음(파일명 규칙까지 자동 수정 불가).
  2. 팀 확장 시: 규칙 미정이면 PR 스타일 리뷰 부담 증가.

🚀 개선 단계

  • 1단계: 단기(반나절): 린트·포맷 규칙(ESLint, Prettier) 설정과 최소한의 변경(파일명 제외) 적용. PR 템플릿에 네이밍 규칙 포함.
  • 2단계: 단기(1일): 발견된 중복 export/잘못된 import(예: widgets/post-detail-modal의 Radix import) 즉시 수정.
  • 3단계: 중기(2-4일): 파일명 규칙(PascalCase for components, useHook prefix for hooks) 적용 계획 수립 및 점진적 리네이밍(대량 리네이밍 시 Git 히스토리 고려).

🎯 일관성 체크포인트

파일명 규칙

  • features/posts-management/ui/posts-table.tsx (kebab-case) — 프로젝트 컨벤션과 불일치 가능성
  • features/posts-pagination/ui/PostPagination.tsx (PascalCase) vs many kebab-case 파일 혼재

Import/Export 패턴

  • widgets/add-post-modal/index.tsx: duplicate 'export default AddPostModal' (중복 선언)
  • widgets/post-detail-modal/index.tsx: direct Radix import (DialogTitle) — shared wrapper 우회

변수명 규칙

  • 대체로 camelCase 사용중이나 일부 타입/파일 내 혼재 가능성(예: PostDTO vs Post model naming 일관성 점검 필요)

코드 스타일

  • 파일 간 세미콜론 사용 여부 혼재 (일부 파일에는 세미콜론, 일부 파일엔 없음)
  • import order 통일성 부족(외부 라이브러리 > 절대 경로 내부 > 상대경로 순서 권장)

11. 🗃️ 상태 관리

💡 개념 정의

애플리케이션 상태 관리는 전역/지역/서버 상태의 구분과 각 상태의 책임을 명확히 하는 것을 말합니다.

⚡ 중요성

명확한 상태 구분은 디버깅, 성능(불필요한 리렌더 방지), 테스트 용이성에 직접적인 영향을 줍니다.

📊 현재 상황 분석

AS-IS: 서버 상태는 잘 분리되어 있음. 클라이언트 상태는 atom에 과도하게 의존되어 있어 아톰 세분화/cleanup 전략(모달 데이터 초기화 등)을 고민해야 함. 또한 pages 예제에서는 AtomsContext 및 PostsManagerAtoms 인터페이스가 추가되어 있는데 실제 사용과 중복/불일치가 있으므로 정리 필요합니다.

📝 상세 피드백

서버 상태는 TanStack Query로, 클라이언트(UI) 상태는 Jotai로 분리된 점은 매우 좋습니다. 그러나 Jotai atom이 프로젝트 전반에 직접 퍼져 있어 상태관리 라이브러리 교체 시 비용이 큽니다. 모달 관리는 atom 단위로 잘 되어 있으나 atom의 세분화 기준과 의존성 관리(derived atoms 등)에 대한 고민이 필요합니다.

❌ 현재 구조 (AS-IS)

AS-IS: src/features/add-comment/model/atoms.ts defines isAddCommentModalOpenAtom; src/widgets/add-comment-modal uses useAtom to open/close modal. 좋은 점이지만 atom이 전역적으로 프로젝트 여러  파일에 산재해 있음.

✅ 권장 구조 (TO-BE)

TO-BE: modal 관련 상태 접근은 useModal('addPost') 같은 추상화 훅으로 캡슐화해 내부에 atom(혹은 다른 스토어) 숨김. 모달 데이터는 modal props 형태({id, payload}) 관리하면 중첩/스택 관리에  .

🔄 변경 시나리오별 영향도

  1. 상태관리 라이브러리 변경(Jotai → Zustand): atom을 직접 사용하는 컴포넌트가 많아 adapter 미비 시 ~25-30개 파일 수정 필요(추정).
  2. 실시간 동기화 추가: 서버 상태는 react-query의 subscription/invalidations로 확장 가능, 클라이언트 atom의 동기화 전략 필요.

🚀 개선 단계

  • 1단계: 단기(반나절): 모달 관련 atom 목록 문서화(어떤 atom이 어떤 widget/feature에서 사용되는지 목록화).
  • 2단계: 단기(1-2일): useModal(name) 훅 등 간단한 추상화 도입하여 컴포넌트가 atom API에 직접 의존하지 않도록 함.
  • 3단계: 중기(2-4일): atom lifecycle 관리(모달 close 시 관련 atom reset) 규칙 도입 및 util(resetAtom) 적용.

🤔 질문과 답변

질문: "모달 관리를 어떻게 하시나요? Jotai 아톰을 이용한 전역 관리가 베스트 프랙티스인가요?"
답변 요약:

  • 결론: Jotai의 아톰을 이용한 모달 관리는 작고 적은 수의 모달, 간단한 데이터 전달(예: boolean open + optional payload)에서는 매우 실용적입니다. 그러나 모달 종류가 늘어나고 모달 간 상호작용/중첩/스택이 필요하거나 상태관리 라이브러리 교체 가능성을 열어두고 싶다면 추가적인 추상화가 필요합니다.
  • 권장 패턴 (상황별):
    1. 소규모/간단한 앱: 각 모달 별로 isOpenAtom + payloadAtom 형태로 Jotai 사용(현재 구현과 유사). 장점: 간단하고 직관적.
    2. 복잡한 모달 흐름(중첩, 스택, 재입력 유지, 여러 모달 공존): 중앙 Modal Manager 패턴 권장 — 모달 레지스트리(id, component, props)와 스택을 관리하는 하나의 atom 또는 store 사용. UI는 modalRenderer가 registry에서 컴포넌트를 꺼내 렌더.
    3. 라이브러리 교체/테스트를 대비한 안전한 접근: 모달 접근을 직접 atom으로 하지 말고 useModal(name) 훅(또는 ModalService)을 만들고 내부에서 atom을 사용해 캡슐화. 이렇게 하면 이후 상태관리 교체 시 훅 내부만 변경하면 됩니다.
  • 구현 팁 (현재 코드에 바로 적용 가능한 권장사항):
    1. useModal 훅 도입 예시: function useModal(key){ return { open: ()=>set(modalOpenAtom(key), true), close: ()=>set(modalOpenAtom(key), false), setProps: (p)=>set(modalPropsAtom(key), p), props: useAtomValue(modalPropsAtom(key)) }
    2. 모달 데이터의 타입 안정성: 각 modal의 payload 타입을 정의하고 제네릭 useModal로 타입을 강제.
    3. 중첩/스택 필요 시: modalStackAtom: Array<{id, name, props}>를 유지하고 push/pop으로 제어. 중첩모달은 stack top으로 렌더.
    4. cleanup: 모달 close 시 관련 payload atom 초기화(resetAtom)를 호출해 메모리/레거시 데이터 방지.
    5. AtomsContext 및 PostsManagerAtoms 정리: 프로젝트에 Context를 도입할 때는 사용 범위를 명확히 하고 중복된 atom 정의(isUserInfoModalOpenAtom 등) 제거. 한 타입의 atom은 한 위치에서만 소유하도 록 정리.
  • Trade-offs: 단일 아톰 per-modal 방식은 직관적이지만 모달 개수가 늘면 atom 관리가 번거롭습니다. Modal Manager는 초기 설계 비용이 있으나 확장성/중첩 관리에 적합합니다.
  • 결론적 권장 작업: 지금 구현은 학습/작은 규모에 적합. 다음 단계로는 useModal 추상화 도입 및 widgets에서 직접 atom을 참조하지 않도록 리팩토링(점진적), 중첩/스택 요구가 있다면 Modal Manager 도입을 권합니다.

🎯 셀프 회고 & 제안

작성하신 셀프회고에서 얻은 인사이트가 매우 현실적이고 학습 지향적입니다. Jotai와 TanStack Query의 장점을 체감한 경험과 모듈화/관심사 분리에 대한 노력이 잘 드러납니다. 이어서 고민해볼 질문들:

  • 아톰 세분화의 기준은 무엇인가요? (예: UI visibility atom vs domain data atom의 경계와 네이밍 규칙)
  • features와 pages 사이에서 비즈니스 로직의 소유권을 어떻게 명확히 할 것인가요? (누가 posts + author 결합 책임을 가질 것인가?)
  • TanStack Query의 캐싱 전략(staleTime, keepPreviousData, placeholderData)을 현재 UX 요구사항(빠른 페이지 전환, 실시간성 등)과 어떻게 맞출 것인가요?
  • 추상화 수준을 어느 시점까지 끌어올릴 것인가요? 너무 추상화하면 오히려 복잡해질 수 있습니다 — 어떤 지표로 적절한 수준을 판단할 것인가요?
    추가 제안: 다음 과제에서는 아래를 시도해 보세요.
  • usePosts 훅의 기능을 pages로부터 완전히 분리하고 pages는 파라미터와 렌더링만 담당하도록 리팩토링한 후 변경 전/후 파일 수정 수를 계산해보세요(정량적 개선 확인).
  • 한 종류의 mutation(예: likeComment)에 optimistic update를 적용해보고 rollback 케이스를 문서화하세요.

추가 논의가 필요한 부분이 있다면 언제든 코멘트로 남겨주세요!

코드 리뷰를 통해 더 나은 아키텍처로 발전해 나가는 과정이 즐거웠습니다. 🚀

이 피드백이 도움이 되었다면 👍 를 눌러주세요!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants