Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[11팀 박근백] [Chapter 2-2] 디자인 패턴과 함수형 프로그래밍 #12

Open
wants to merge 60 commits into
base: main
Choose a base branch
from

Conversation

Geunbaek
Copy link

@Geunbaek Geunbaek commented Jan 14, 2025

과제 체크포인트

기본과제

  • React의 hook 이해하기

  • 함수형 프로그래밍에 대한 이해

  • Component에서 비즈니스 로직을 분리하기

  • 비즈니스 로직에서 특정 엔티티만 다루는 계산을 분리하기

  • Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?

  • 주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?

  • 계산함수는 순수함수로 작성이 되었나요?

심화과제

  • 뷰데이터와 엔티티데이터의 분리에 대한 이해

  • 엔티티 -> 리파지토리 -> 유즈케이스 -> UI 계층에 대한 이해

  • Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?

  • 주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?

  • 계산함수는 순수함수로 작성이 되었나요?

  • 특정 Entitiy만 다루는 함수는 분리되어 있나요?

  • 특정 Entitiy만 다루는 Component와 UI를 다루는 Component는 분리되어 있나요?

  • 데이터 흐름에 맞는 계층구조를 이루고 의존성이 맞게 작성이 되었나요?

과제 셀프회고

refactoring

  • 기존 파일구조에서 심화까지 적용해본 버전
refactoring
 ┣ components
 ┃ ┣ cart
 ┃ ┃ ┣ CartItem.tsx
 ┃ ┃ ┣ CartList.tsx
 ┃ ┃ ┗ CartSummary.tsx
 ┃ ┣ coupon
 ┃ ┃ ┣ CouponApply.tsx
 ┃ ┃ ┣ CouponForm.tsx
 ┃ ┃ ┣ CouponList.tsx
 ┃ ┃ ┣ CouponManagement.tsx
 ┃ ┃ ┗ CouponSelect.tsx
 ┃ ┣ product
 ┃ ┃ ┣ ProductAddForm.tsx
 ┃ ┃ ┣ ProductDiscountItem.tsx
 ┃ ┃ ┣ ProductDiscountList.tsx
 ┃ ┃ ┣ ProductEditForm.tsx
 ┃ ┃ ┣ ProductItem.tsx
 ┃ ┃ ┣ ProductList.tsx
 ┃ ┃ ┗ ProductManagement.tsx
 ┃ ┣ shared
 ┃ ┃ ┣ Heading.tsx
 ┃ ┃ ┗ Select.tsx
 ┃ ┣ AdminPage.tsx
 ┃ ┗ CartPage.tsx
 ┣ hooks
 ┃ ┣ index.ts
 ┃ ┣ useCart.ts
 ┃ ┣ useCoupon.ts
 ┃ ┗ useProduct.ts
 ┣ models
 ┃ ┗ cart.ts
 ┣ App.tsx
 ┗ main.tsx

advanced

  • FSD 의 파일구조를 적용한 버전
  • msw 를 사용해 api 를 모킹 + tanstack query 를 사용해 서버상태와 클라이언트 상태를 분리
advanced
 ┣ __tests__
 ┃ ┗ advanced.test.tsx
 ┣ app
 ┃ ┣ App.tsx
 ┃ ┣ AppRouter.tsx
 ┃ ┗ main.tsx
 ┣ entities
 ┃ ┣ coupon
 ┃ ┃ ┣ api
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┣ model
 ┃ ┃ ┃ ┣ index.ts
 ┃ ┃ ┃ ┗ types.ts
 ┃ ┃ ┗ index.ts
 ┃ ┗ product
 ┃ ┃ ┣ api
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┣ lib
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┣ model
 ┃ ┃ ┃ ┣ index.ts
 ┃ ┃ ┃ ┗ types.ts
 ┃ ┃ ┣ ui
 ┃ ┃ ┃ ┣ ProductDiscountItem.tsx
 ┃ ┃ ┃ ┣ ProductDiscountList.tsx
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┗ index.ts
 ┣ features
 ┃ ┣ cart
 ┃ ┃ ┣ lib
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┣ model
 ┃ ┃ ┃ ┣ index.ts
 ┃ ┃ ┃ ┣ types.ts
 ┃ ┃ ┃ ┗ useCart.ts
 ┃ ┃ ┣ ui
 ┃ ┃ ┃ ┣ AddToCartButton.tsx
 ┃ ┃ ┃ ┣ CartItem.tsx
 ┃ ┃ ┃ ┣ CartList.tsx
 ┃ ┃ ┃ ┣ CartSummary.tsx
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┗ index.ts
 ┃ ┣ coupon
 ┃ ┃ ┣ model
 ┃ ┃ ┃ ┣ index.ts
 ┃ ┃ ┃ ┗ useCoupon.ts
 ┃ ┃ ┣ ui
 ┃ ┃ ┃ ┣ CouponForm.tsx
 ┃ ┃ ┃ ┣ CouponList.tsx
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┗ index.ts
 ┃ ┗ product
 ┃ ┃ ┣ model
 ┃ ┃ ┃ ┣ index.ts
 ┃ ┃ ┃ ┗ useProduct.ts
 ┃ ┃ ┣ ui
 ┃ ┃ ┃ ┣ ProductAddForm.tsx
 ┃ ┃ ┃ ┣ ProductEditForm.tsx
 ┃ ┃ ┃ ┣ ProductManagementItem.tsx
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┗ index.ts
 ┣ pages
 ┃ ┣ admin
 ┃ ┃ ┣ ui
 ┃ ┃ ┃ ┣ AdminPage.tsx
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┗ index.ts
 ┃ ┗ cart
 ┃ ┃ ┣ ui
 ┃ ┃ ┃ ┣ CartPage.tsx
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┗ index.ts
 ┣ shared
 ┃ ┣ lib
 ┃ ┃ ┗ index.ts
 ┃ ┗ ui
 ┃ ┃ ┣ Heading.tsx
 ┃ ┃ ┣ Input.tsx
 ┃ ┃ ┣ Select.tsx
 ┃ ┃ ┗ index.ts
 ┗ widgets
 ┃ ┣ cart
 ┃ ┃ ┣ ui
 ┃ ┃ ┃ ┣ CartDetail.tsx
 ┃ ┃ ┃ ┣ CouponApply.tsx
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┗ index.ts
 ┃ ┣ coupon
 ┃ ┃ ┣ ui
 ┃ ┃ ┃ ┣ CouponManagement.tsx
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┗ index.ts
 ┃ ┣ layout
 ┃ ┃ ┣ ui
 ┃ ┃ ┃ ┣ Header.tsx
 ┃ ┃ ┃ ┣ RootLayout.tsx
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┗ index.ts
 ┃ ┗ product
 ┃ ┃ ┣ ui
 ┃ ┃ ┃ ┣ ProductItem.tsx
 ┃ ┃ ┃ ┣ ProductList.tsx
 ┃ ┃ ┃ ┣ ProductManagement.tsx
 ┃ ┃ ┃ ┣ ProductStock.tsx
 ┃ ┃ ┃ ┗ index.ts
 ┃ ┃ ┗ **index.ts**
  • app : 애플리케이션 전반적인 설정

    • router
    • 전역 스타일
  • pages : 하위 레이어들을 조합하여 페이지를 완성시키는 레이어

  • widgets : 하위 features 와 entities 레이어에서 정의된 기능을 모으는 레이어

    • 하위 레이어에서 다른 도메인에서 정의된 훅이나 서로 다른 도메인에서 정의된 훅들을 조합해 ui를 그리는 컴포넌트
    • 하위 레이어에서의 훅들을 조합한 훅
  • features : 프로젝트가 다루는 기능들 ( 상태와 관련된 기능들 )

    • 변경되는 데이터의 타입
    • entities 에서 정의된 fetch 함수를 이용한 tanstack query 훅들
    • 변경되는 데이터들을 가공하는 계산함수
    • 해당 도메인에서 정의된 훅을 사용해 ui를 그리는 컴포넌트
  • entities : 프로젝트가 다루는 데이터 영역 ( 서버에서 받아오는 데이터, 클라이언트에서 변함이 없는 데이터 )

    • 변하지 않는 데이터의 타입
    • 데이터를 가공하는 계산 함수
    • 데이터를 인자로 받아 ui만 그리는 컴포넌트
  • shared : 앱 전체 영역에서 사용할 수 있는 도메인 없이도 사용할 수 있는 기능들의 집합

과제에서 좋았던 부분

과제를 하면서 새롭게 알게된 점

과제를 진행하면서 아직 애매하게 잘 모르겠다 하는 점, 혹은 뭔가 잘 안되서 아쉬운 것들

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

제가 가진 기준들 + fsd 의 규칙에 따라 최대한 컴포넌트를 나누고 적절한 위치로 분류시켜보았는데요.
컴포넌트를 분리하면 분리할수록 뭔가 해당 컴포넌트가 어디있을지 예측하는것이 힘들어졌는데요...
아직 데이터를 기준으로 분류하는 것이 어색해서일까요? 아니면 분류 기준을 좀 더 명확하게 구분하지 않아서일까요?

컴포넌트를 계속해서 분리하다보니 상태가 변경될 때마다 해당 상태를 구독하고 있는 작은 단위의 컴포넌트만 리렌더링 되도록 구성이 되었는데 혹시 이렇게 컴포넌트를 잘게잘게 나누는것도 과한 최적화라고 봐야할까요? 아니면 프론트엔드 개발자로서 추구해야하는 목표일까요?

@Geunbaek Geunbaek marked this pull request as draft January 14, 2025 11:34
@Geunbaek Geunbaek marked this pull request as ready for review January 17, 2025 08:31
@Geunbaek Geunbaek changed the title [WIP][11팀 박근백] [Chapter 2-2] 디자인 패턴과 함수형 프로그래밍 [11팀 박근백] [Chapter 2-2] 디자인 패턴과 함수형 프로그래밍 Jan 17, 2025
Comment on lines +1 to +2
export * from './model';
export { ProductAddForm, ProductEditForm, ProductManagementItem } from './ui';

Choose a reason for hiding this comment

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

저번에 Slice에서도 한 번 더 배럴 파일을 사용하신다고 한 게 이거였군요!

Comment on lines +6 to +25
const router = createBrowserRouter(
[
{
path: '/',
element: <RootLayout />,
children: [
{ index: true, element: <CartPage /> },
{
path: '/admin',
element: <AdminPage />,
},
],
},
],
{ basename: '/index.advanced.html' },
);

export function AppRouter() {
return <RouterProvider router={router} />;
}

Choose a reason for hiding this comment

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

오 저는 왜 라우터를 활용할 방법을 생각 못 했을까요?!👍

Copy link
Author

Choose a reason for hiding this comment

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

그런데 index.advanced.html 을 실행하는거라 라우팅 하는게 쉽진 않네요 /admin 경로에서 새로고침을 하면 계속 페이지를 찾을수 없다고 나오는데 혹시 해결방법을 아신다면 공유해주시면 감사합니다 !!

Comment on lines +5 to +17
async function enableMocking() {
if (process.env.NODE_ENV !== 'development') {
return;
}

// eslint-disable-next-line import/no-internal-modules
const { worker } = await import('../../mocks/browser.ts');

return worker.start();
}

await enableMocking();

Choose a reason for hiding this comment

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

이번 과제에도 모킹서버?를 적용하시다니!👍

Copy link
Author

Choose a reason for hiding this comment

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

entities 에 들어가는 데이터라는 느낌을 확주기 위해 모킹을 했습니다.

@wonjung-jang
Copy link

오 근백님이 적용하신 FSD를 보니까 제가 적용한 FSD가 부끄러워지네요.
근백님의 기준을 제가 나름 정리해보면

  1. widgetspage에 들어가는 구역들의 ui 컴포넌트만.
  2. pages에는 페이지 컴포넌트만.
  3. features에서 실행되는 api 함수들을 model에 두고 내부에서 사용하는 로직은 entities의 함수들을 가져와서 사용한다.

라고 봐도 될까요?

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.

2 participants