-
Notifications
You must be signed in to change notification settings - Fork 47
[2팀 고다솜] Chapter3-2. 디자인 패턴과 함수형 프로그래밍 그리고 상태 관리 설계 #32
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
Open
ds92ko
wants to merge
72
commits into
hanghae-plus:main
Choose a base branch
from
ds92ko:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- isAdmin과 같은 단일 boolean 플래그 -> pageType 기반 설계로 변경
- showForm을 위한 useToggle 커스텀훅 추가 - useForm 커스텀훅 추가 - 쿠폰 관련 타입 및 상수 추가
- 직관적인 네이밍을 위해 constraints -> validation rules로 변경 - 확장성을 위해 discount -> coupon으로 변경
- CartSection: 사용하지 않는 addNotification props 제거 - ProductSection: 사용하지 않는 addNotification props 제거 - StorePage: 불필요한 props 전달 제거 - Props Drilling 감소 및 코드 간결성 향상 - README 원칙 준수: 실용적 판단력을 통한 개선
- CartSection의 map 내부 로직을 CartItem 컴포넌트로 분리 - 각 컴포넌트의 책임 명확화 및 가독성 향상 - README 원칙 준수: 적절한 컴포넌트 분리
- CartItem 타입 import 경로를 ../../../../types에서 ../../../types/carts로 변경 - import 순서 정리로 가독성 향상 - 코드 일관성 유지
- hasCartItems를 totalItemCount > 0로 대체하여 중복 제거 - 불필요한 useMemo 제거 및 import 정리 - 코드 간결성 향상
- CartItem에서 직접 calculateItemTotal을 import하여 사용 - CartSection의 calculateItemTotal prop 제거로 Props Drilling 감소 - StorePage의 불필요한 useMemo 제거 - README 원칙 준수: Props Drilling 감소 및 컴포넌트 자율성 향상
- handleSwitchToAdmin과 handleSwitchToStore의 의존성 배열에서 상수 제거 - admin과 store는 상수이므로 의존성 배열에 포함할 필요 없음 - 코드 품질 향상
- StorePage와 CartSection에 totalItemCount prop 추가 - cart.length > 0을 totalItemCount > 0로 변경 - cart.length === 0을 totalItemCount === 0로 변경 - useCart에서 제공하는 totalItemCount 활용으로 일관성 향상 - README 원칙 준수: 단일 책임 원칙 및 데이터 일관성
- 컴포넌트 내부에서만 사용되는 이벤트 핸들러의 useCallback 제거 - useCallback 사용 기준 명확화: * 다른 hook의 dependency array에 포함되는 경우만 유지 * 자식 컴포넌트에 전달되지만 React.memo로 최적화되지 않은 경우 제거
- 컴포넌트 내부 이벤트 핸들러의 useCallback 제거 - useCallback은 다른 hook의 dependency나 외부 노출 함수에만 사용 - useEffect 의존성 배열 최적화 (안정적인 함수 제외)
- CouponForm의 options와 App의 nav/page 객체 최적화
- 상태 업데이트를 함수형 패턴으로 변경 (setForm) - calculateCartTotal을 reduce로 리팩토링 - 불필요한 props 제거
- Coupon, Product 관련 함수들을 utils에서 models로 이동 - 빈 utils 파일들 삭제 - 엔티티를 다루는 함수는 모두 models로 분리 완료
심화과제 작업을 위해 basic 폴더의 리팩토링된 코드를 advanced 폴더로 복사
- useState 기반 로컬 상태에서 Zustand store로 전환 - Props drilling 제거, 각 컴포넌트가 직접 store 사용 - Toast 컴포넌트가 store에서 직접 notifications 구독
- useLocalStorage 기반 useCart hook → zustand persist 스토어로 교체 - 전역 상태 관리로 Props drilling 제거
- useLocalStorage 기반 useProducts hook → zustand persist 스토어로 교체 - 전역 상태 관리로 Props drilling 완전 제거
- useLocalStorage 기반 useCoupons hook → zustand persist 스토어로 교체 - 전역 상태 관리로 Props drilling 완전 제거
- discountTypeOptions useMemo 제거 (상수 기반 계산이므로 불필요)
zustand persist 기본 구조 대신 배열만 저장하도록 커스텀 PersistStorage 구현하여 basic 버전과 동일한 localStorage 구조로 통일
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
배포 링크
과제의 핵심취지
과제에서 꼭 알아가길 바라는 점
기본과제
Component에서 비즈니스 로직을 분리하기
비즈니스 로직에서 특정 엔티티만 다루는 계산을 분리하기
뷰데이터와 엔티티데이터의 분리에 대한 이해
entities -> features -> UI 계층에 대한 이해
Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?
주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?
계산함수는 순수함수로 작성이 되었나요?
Component에서 사용되는 Data가 아닌 로직들은 hook으로 옮겨졌나요?
주어진 hook의 책임에 맞도록 코드가 분리가 되었나요?
계산함수는 순수함수로 작성이 되었나요?
특정 Entitiy만 다루는 함수는 분리되어 있나요?
특정 Entitiy만 다루는 Component와 UI를 다루는 Component는 분리되어 있나요?
데이터 흐름에 맞는 계층구조를 이루고 의존성이 맞게 작성이 되었나요?
심화과제
이번 심화과제는 Context나 Jotai를 사용해서 Props drilling을 없애는 것입니다.
어떤 props는 남겨야 하는지, 어떤 props는 제거해야 하는지에 대한 기준을 세워보세요.
Context나 Jotai를 사용하여 상태를 관리하는 방법을 익히고, 이를 통해 컴포넌트 간의 데이터 전달을 효율적으로 처리할 수 있습니다.
Context나 Jotai를 사용해서 전역상태관리를 구축했나요?
전역상태관리를 통해 domain custom hook을 적절하게 리팩토링 했나요?
도메인 컴포넌트에 도메인 props는 남기고 props drilling을 유발하는 불필요한 props는 잘 제거했나요?
전체적으로 분리와 재조립이 더 수월해진 결합도가 낮아진 코드가 되었나요?
과제 셀프회고
이번 과제를 시작하기 전까지 저는 함수형 프로그래밍(FP)에 대해 다음과 같은 오해를 가지고 있었습니다.
오해 1: FP는 OOP와 상반되는 개념이다.
FP는 객체의 상태 변경을 지양하고 순수 함수와 불변성에 중점을 두기 때문에, OOP의 핵심인 캡슐화와 Mutation을 부정한다고 생각했습니다.
오해 2: FP는 모든 것을 순수 함수로만 만들어야 한다.
실제 애플리케이션의 부수 효과(Side Effect), 즉 네트워크 통신, 상태 변경, 콘솔 출력 같은 필수적인 동작을 FP가 어떻게 다룰 수 있는지에 대한 이해가 부족했습니다.
오해 3: FP는 실무의 복잡한 비즈니스 로직을 구현하기에는 너무 이론적이다.
단순한
map,filter,reduce이상의 복잡한 로직을 FP 방식으로 구조화하는 것이 비효율적이라고 생각했습니다.하지만 이번 과제를 통해 FP의 목표와 실용적 가치를 깊이 이해하게 되었습니다.
FP의 목표는 OOP의 대안이 아닌 보완
FP는 OOP를 대체하는 것이 아니라, "어떻게 하면 더 안전하게 데이터를 다룰 수 있을까?" 에 초점을 맞춥니다.
Product엔티티처럼 데이터와 관련된 행위(메서드)를 캡슐화하여 도메인의 관심사를 효과적으로 분리합니다.calculateCartTotal)처럼 데이터를 변경하지 않는 순수한 계산은 컴포넌트나 객체의 내부 상태에 묶어두지 않고, 순수 함수(Pure Function)로 분리하여 예측 불가능한 부수 효과를 제거하는 데 활용됩니다.결국, 이번 과제에서 저는 OOP가 담당해야 할 엔티티 캡슐화와 FP가 담당해야 할 계산의 순수성을
models/폴더 분리를 통해 동시에 확보할 수 있었습니다.핵심은 순수 함수 최대화와 부수 효과 캡슐화
FP는 모든 것을 순수하게 만들라는 것이 아니라, 순수 함수를 최대한 늘리고, 부수 효과(Side Effect)는 의도된 경계에 모아 관리하라는 철학임을 깨달았습니다.
calculateCartTotal과 같은 계산 로직은models/에 순수 함수로 분리되었습니다.addToCart나handleNotificationAdd같은 함수는 Custom Hook이나 Zustand Store의 Action에 캡슐화하여 부수 효과가 발생하는 지점을 명확히 통제했습니다.이러한 Action / Calculation / Data 분리를 통해, 순수하지 않은 코드는 격리시키고 핵심 비즈니스 로직은 예측 가능하게 만들 수 있었습니다.
FP는 복잡성 관리의 강력한 도구
복잡한 할인 계산 로직을
getMaxDiscountRate,hasBulkPurchase등 작은 순수 함수들로 쪼개고 이를 조합하는 함수 합성 방식을 적용해보니, 복잡한 로직을 마치 레고 블록처럼 쉽게 이해하고 테스트하며 확장할 수 있었습니다.로직이 변경되더라도 전체 시스템이 아닌 특정 작은 함수 블록만 수정하면 되므로, 유지보수성과 확장성 측면에서 FP가 실무에 얼마나 실용적인 아키텍처 원칙인지 깊이 체감할 수 있었습니다.
과제를 하면서 내가 알게된 점, 좋았던 점은 무엇인가요?
기본 과제
초기 1,123줄의
App.tsx코드를 리팩토링하면서, 단순히 코드를 분할하는 것을 넘어 관심사 분리와 FP 사고를 적용하는 것의 가치를 체감했습니다.함수형 프로그래밍 원칙 적용
기존 코드에서는
calculateCartTotal()같은 함수가 컴포넌트 내부 변수를 클로저로 참조하여 외부 상태에 의존했습니다.이는 함수형 프로그래밍의 핵심 원칙인 순수 함수(Pure Function)를 위반하는 패턴이었습니다.
순수 함수와 부수 효과 제거:
그 외에도
불변성을 통한 안전한 데이터 조작:
filter, map과 같은 배열 메서드를 사용해 새 배열을 반환하거나, 스프레드 연산자로 새 배열을 반환하도록 처리했습니다.
함수 합성으로 복잡한 로직 구현:
작은 순수 함수들을 합성하여 복잡한 계산을 수행하도록 처리했습니다.
고차 함수와 선언적 프로그래밍: 기존의 명령형 방식을 선언적 방식으로 리팩토링
이렇게 변경하면서 함수형 프로그래밍의 핵심 원칙들을 적용할 수 있었습니다:
덕분에 테스트 코드 작성과 버그를 발견하고 예방하기 용이한 코드로 리팩토링이 가능했습니다.
또한 이 로직을 다른 컴포넌트나 모듈에서 재사용할 수 있어 유지보수와 확장성 측면에서도 큰 도움이 됐습니다.
코드 구조 개선과 관심사 분리를 통한 유지보수성 극대화
초기 App.tsx는 1,123줄에 달하며 모든 로직이 한 곳에 섞여 있었습니다.
이는 디버깅과 기능 수정 등에 엄청난 비효율을 발생시키게 됩니다.
해결 방법:
models/(도메인 로직)와utils/(범용 유틸리티) 폴더로 분리하여 부수 효과 없는 계산 로직 관리이를 적용하자, 코드를 읽고 이해하는 시간이 획기적으로 단축되었으며, 컴포넌트는 오직 View 렌더링 역할에 집중하게 되었습니다.
특히 함수형 프로그래밍 원칙에 따라 순수 함수로 분리된 계산 로직은 예측 가능하고 테스트하기 쉬워졌습니다.
이를 통해 모듈화된 아키텍처와 함수형 프로그래밍이 대규모 애플리케이션의 유지보수성과 협업 효율에 얼마나 필수적인 요소인지 깊이 체감했습니다.
심화과제
상태 관리 라이브러리(Zustand)와 영속화(Persist) 기능을 적용하며 전역 상태 관리의 심화 패턴을 학습했습니다.
Zustand 전역 상태의 특성 이해
useNotifications를 전역 상태로 변경하는 과정에서 이전 테스트의 알림이 다음 테스트에 영향을 주며 기존 테스트가 깨지는 문제가 발생했습니다.useState는 렌더링마다 새로운 상태를 생성하므로 상태가 독립적이지만, Zustand store는 전역 싱글톤으로 메모리에 유지됩니다.이 때문에 테스트 환경에서 이전 테스트의 데이터가 다음 테스트에 남아 예상치 못한 오류를 일으킬 수 있음을 알게 되었습니다.
전역 상태 관리 환경에서는 테스트 간 상태 간섭을 막기 위해 명시적 초기화가 필수적이라는 점을 체득했습니다.
persist 미들웨어 동작 원리 파악
persist를 적용하면서, persist store가 스토어 생성 시 localStorage에서 상태를 읽어와 초기 상태로 복원하기 때문에 단순히 localStorage를 지우는 것만으로는 충분하지 않고, 스토어 상태와 localStorage를 동시에 초기화해야 함을 알게 되었습니다.
beforeEach(() => { // localStorage 초기화 localStorage.clear(); + // store 초기화 + useCart.getState().actions.clearCart(); ... });이를 통해 persist store가 localStorage와 메모리 상태를 어떻게 복원하고 동기화하는지 직접 경험하며, 전역 상태 관리 + 영속화(store persist) 동작 원리를 이해할 수 있었습니다.
이번 과제에서 내가 제일 신경 쓴 부분은 무엇인가요?
기본과제
PageType 기반 설계로 확장성 확보
기존에는
isAdmin같은 boolean 플래그로 페이지를 구분했기 때문에 페이지가 늘어날수록 플래그와 분기문이 함께 증가하는 구조적 문제가 있었습니다.예를 들어 마이페이지가 추가되면 다음과 같이 새로운 플래그와 조건이 계속 붙습니다.
이는 다음과 같은 문제를 만들어 냅니다.
이 문제를 해결하기 위해 페이지 구분 방식을 boolean 기반이 아닌 PageType 기반의 단일 책임 구조로 전환했습니다.
이 방식으로 페이지를 관리할 경우, 새로운 페이지를 추가할 때 PAGES만 확장하면 되고 기존 로직은 수정할 필요가 없습니다.
export const PAGES = { store: 'store', admin: 'admin', + mypage: 'mypage' } as const;확장성, 가독성, 타입 안정성 모두 확보할 수 있는 구조로 개선했습니다.
Compound Component 패턴과 Context 구성
Tabs UI는 여러 하위 컴포넌트가 상호작용해야 하는 구조입니다.
이런 구조는 Compound Component 패턴의 장점을 그대로 가져갈 수 있는 대표적인 케이스입니다.
이 패턴을 선택한 이유는 다음과 같습니다
선언적 UI 구성
사용자가
<Tabs>컴포넌트를 구성할 때, "어떻게 동작하는지"가 아니라 "어떤 UI가 필요한지"만 표현하면 됩니다.내부 통신 구조 단일화
TabList, TabPanel은 서로 다른 레벨의 컴포넌트이지만 하나의 Tabs 상태를 공유해야 합니다.
이를 위해 private Context를 사용했고, 이는 Tabs 내부에서만 쓰이기 때문에 분리하지 않았습니다.
→ 응집도가 높아지고, 외부 노출도 방지되며 책임 범위가 명확해집니다.
로직의 재사용성 확보
상태 제어 로직은 UI와 분리할 필요가 있었기 때문에 useTabs를 별도 hook으로 만들어 범용적으로 활용할 수 있게 했습니다.
아이콘 네이밍 기준 결정
Icon 컴포넌트를 추출하면서 네이밍을 용도 기반(close, delete, add 등)으로 할지 모양 기반(x, trash, plus 등)으로 할지 고민했습니다.
용도 기반 네이밍의 장점과 한계:
용도 기반 네이밍을 적용하면 아이콘 이름이 명확해집니다.
CloseIconDeleteIconAddIcon이 방식은 어떤 UI 동작을 위한 아이콘인지 직관적으로 이해할 수 있다는 장점이 있습니다.
하지만 같은 모양의 아이콘을 다른 용도로 사용할 때 아이콘 컴포넌트가 중복 생성되는 문제가 발생합니다.
예를 들어 X 모양 아이콘을 생각해보면,
CloseIconDeleteIcon둘다 동일한 X 모양을 사용하지만, 용도가 다르다는 이유만으로 서로 다른 아이콘 컴포넌트를 만들어야 합니다.
이렇게 되면 용도가 변경되거나 새로운 용도가 추가될 때마다 아이콘 컴포넌트를 새로 만들거나 이름을 변경하는 비효율이 생깁니다.
이 문제를 해결하기 위해 모양 기반 네이밍(XIcon, TrashIcon, PlusIcon 등)으로 방향을 정했습니다.
모양 기반 네이밍의 장점:
X 모양 자체는 변하지 않기 때문에, 용도가 달라져도 컴포넌트를 추가로 만들 필요가 없습니다.
이런 점을 종합해볼 때 재사용성·유연성·유지보수성 관점에서 모양 기반 네이밍이 더 적합하다고 판단했습니다.
심화과제
Zustand Persist 호환성 문제 해결을 위한 커스텀 Storage 구현
Zustand persist를 적용하면서 아래와 같은 저장 구조 때문에 문제가 발생했습니다.
advanced 버전은 이 구조를 저장하지만, basic 버전은 배열만 저장하는 단순 구조였습니다.
→ 즉, 기본 저장 구조가 달라서 기존 데이터를 읽지 못하는 호환성 문제가 생김
이를 해결하기 위해 처음에는
partialize로 필요한 부분만 저장하도록 시도했습니다.{ - partialize: ({ context }) => ({ context }) + partialize: ({ context }) => [...context.cart] }하지만 persist의 기본 포맷을 바꿀 수 없었기 때문에, 최종적으로 직접 PersistStorage를 구현해 advanced 버전에서도 basic과 동일한 구조로 저장되도록 만들었습니다.
이 방식으로 basic 버전과 동일한 localStorage 구조를 유지하면서도 zustand persist의 자동 저장·복원 기능을 그대로 활용할 수 있었습니다.
searchTerm 전역 상태 관리 결정
searchTerm은 Header의 검색 인풋과 StorePage의 ProductList처럼 서로 다른 서브트리 컴포넌트들이 공유하는 값입니다.이를 props로 전달하려면 App까지 거슬러 올라가는 구조가 되는데, 검색 기능은 App의 책임이 아니기 때문에 비효율적이고 자연스럽지 않다고 판단했습니다.
또한 두 컴포넌트는 서로 내부 동작을 몰라도 되는 독립된 모듈입니다.
하지만 동일한 검색 상태를 공유해야 하므로 전역 상태가 더 적합하다고 판단했습니다.
그래서 zustand store로 분리해 아래 이점을 확보했습니다.
이번 과제를 통해 앞으로 해보고 싶은게 있다면 알려주세요!
이번 과제에서 관심사 분리와 모듈화의 중요성을 깊이 체감했습니다.
이를 바탕으로 프로젝트의 확장성과 유지보수성을 극대화하기 위해, 코드 구조를 한 단계 더 발전시키는 것에 도전해보고 싶습니다.
기능 중심의 코드 구조 개선
현재 프로젝트는
models/,hooks/,components/,pages/,stores/,storage/등 역할 기반으로 코드가 분산되어 있습니다.이러한 구조는 특정 기능을 수정하거나 확장할 때 관련 코드를 여러 폴더에서 찾아야 하는 비효율성과 기능의 전체 맥락 파악의 어려움을 야기했습니다.
따라서 다음 프로젝트에서는 기능 중심으로 코드를 설계하는 FSD 아키텍처를 도입해보고 싶습니다.
FSD 구조를 적용하면 특정 기능(Feature)에 관련된 모든 코드(모델, 상태, UI, 로직)가 하나의 디렉토리 내에 모여 응집도가 극대화됩니다.
리뷰 받고 싶은 내용이나 궁금한 것에 대한 질문 편하게 남겨주세요 :)
searchTerm 전역 상태 관리 결정에 대한 질문
searchTerm을 전역 상태로 분리하여 관리한 아키텍처적 결정에 대해 리뷰를 받고 싶습니다.searchTerm은 서로 다른 컴포넌트 서브트리(검색 인풋, 상품 목록 등)에서 동시에 참조하고 변경해야 하는 값이었습니다. 이 값을 Props Drilling을 통해 전달할 경우 최상위App컴포넌트가 검색이라는 특정 기능의 책임까지 떠맡게 되어 관심사 분리 원칙에 위배된다고 판단했습니다.따라서 두 모듈이 동일한 검색 상태에 직접 접근하도록 전역 상태 관리 방식을 채택하는 것이 더 적절하다고 판단했는데, 이 선택이 해당 상태의 특성을 고려했을 때 적합한 결정이었을까요?
Compound Component 패턴과 Context 설계에 대한 질문
제네릭 타입 T를 Provider에 전달해야 하는 Compound Component 패턴을 구현하면서, Context 생성 시점에
any를 사용하고useContext를 사용하는 훅에서 타입 단언을 수행하여 타입을 지정하는 방식이 타입 안전성 측면에서 적절한 해결책인지 궁금합니다.Props 유지 기준에 대한 질문
totals와 같이 장바구니 상태를 기반으로 계산되는 결과값을 처리할 때, 다음 두 방식 중 어떤 것이 더 나은 아키텍처적 선택일까요?현재 방식처럼 부모 컴포넌트(예: StorePage)에서 계산 후 Props로 자식 컴포넌트(예: CouponSection, PaymentSection)에 전달하는 방식과 자식 컴포넌트가 Store에서 필요한 상태를 구독하여 각 컴포넌트 내부에서 계산을 수행하는 방식 중 어떤 방식이 더 적절한지 의견을 묻고 듣고싶습니다.
selectedCoupon을 로컬 상태로 두는 것과 전역 상태로 관리하는 것의 기준이 무엇일까요?현재
selectedCoupon을StorePage내에서만 사용하는 로컬 상태로 관리하고 있습니다.이 결정에 대해 다음과 같은 의문이 있습니다.
selectedCoupon이StorePage내부에서만 사용되고 있어 로컬 상태를 유지했는데, 이 판단이 적절했을까요?selectedCoupon을 전역 상태로 분리해야 한다면, 프로젝트의 주요 전역 상태 관리 툴인 Zustand를 사용하는 것이 좋을까요, 아니면 StorePage 컴포넌트 서브트리 내에서만 사용하도록 Context API를 활용하여 부분적인 전역 상태로 관리하는 것이 더 적절한 선택일까요?Zustand에 대한 질문
Zustand selector를 사용하여 상태 객체 전체를 구독하는 대신, 필요한 속성(cart, totalItemCount 등)만 더 세밀하게 구독하는 방식이 실제 렌더링 성능 최적화에 유의미한 이점을 가져다줄까요?
현재
cartContext(),cartActions()와 같이 특정 객체를 반환하는 Selector 함수 패턴을 사용하고 있습니다.이 방식이 Zustand Store에서 context나 actions를 분리하여 사용하는 데 있어 성능(리렌더링) 측면에서 이점이 있는지 궁금합니다.
Basic 버전과의 호환성을 위해
setItem시 배열만 저장하도록 커스텀Storage를 구현했습니다.이러한 버전/호환성 문제가 발생했을 때, 커스텀 Storage 구현 외에 다른 아키텍처적 대안이 있을까요?
이 경우, 오히려 Zustand의 persist 미들웨어를 사용하지 않고 수동으로 localStorage를 관리하는 것이 더 나은 선택이었을까요?
아이콘 네이밍 기준에 대한 질문
아이콘 네이밍을 결정하는 데 있어 재사용성과 유연성을 고려하여 모양 기반 네이밍(예: XIcon, TrashIcon)을 선택했습니다.
하지만 이는 용도 기반 네이밍(예: CloseIcon, DeleteIcon)과 비교했을 때 다음과 같은 의문이 발생했습니다.
디자인 시스템 관점: 장기적인 유지보수와 일관성 측면에서 모양 기반과 용도 기반 중 어떤 네이밍 방식이 더 적합한 선택일까요?
유연성: 모양 기반 네이밍이 재사용성에 유리하다고 판단했으나, 만약 아이콘의 모양 자체가 변경될 경우 네이밍도 함께 수정해야 하는 단점이 발생합니다. 이를 회피할 수 있는, 모양 기반 및 용도 기반 외의 더 나은 네이밍 기준이나 접근 방식이 있을까요?
질문이 많아 죄송합니다! 그리고 감사합니다!