feat: Wiki-fication of 00_Raw data (Batch #6~#8 - Arch, Refactoring, Debugging, 2025 Standards)
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
# Skybound Enemy Movement Jitter Stabilization
|
||||
|
||||
작성일: 2026-04-26 20:38 KST
|
||||
|
||||
## 요청 요약
|
||||
|
||||
- 특정 적기들이 서로 낀 것처럼 겹친 채 바들바들 떨린다.
|
||||
- 적기 이동 로직을 확인하고 원인을 찾아야 한다.
|
||||
|
||||
## 확인 결과
|
||||
|
||||
문제는 단일 원인이 아니라 세 가지가 겹친 현상으로 판단했다.
|
||||
|
||||
### 1. Striker 계열이 플레이어 한 점으로 수렴
|
||||
|
||||
`updateStrikerAI`는 각 적기의 편대 위치를 유지하지 않고 `player.x`를 향해 계속 이동했다.
|
||||
|
||||
이 때문에 같은 편대로 나온 엘리트/스트라이커들이 시간이 지나면 거의 같은 x 좌표로 모이게 된다.
|
||||
|
||||
### 2. 분리 로직이 강한 위치 보정으로 작동
|
||||
|
||||
`applyEnemySeparation`은 겹친 적을 매 프레임 직접 밀어냈다.
|
||||
|
||||
하지만 직전 AI 로직이 다시 같은 지점으로 끌어당기기 때문에:
|
||||
|
||||
- AI가 모음
|
||||
- separation이 밀어냄
|
||||
- 다음 프레임에 다시 AI가 모음
|
||||
|
||||
이 루프가 반복되며 화면에서는 “끼어서 떠는” 것처럼 보였다.
|
||||
|
||||
### 3. 엔티티 풀링에서 내부 속도 잔여값 가능성
|
||||
|
||||
적 엔티티는 풀링으로 재사용된다.
|
||||
|
||||
그런데 새로 스폰할 때 `vx`, `vy`, 일부 AI 상태값이 명시적으로 초기화되지 않았다.
|
||||
|
||||
이전 적이 gravity, knockback, chase 등으로 얻은 내부 속도가 새 적에게 남을 가능성이 있어 이동 불안정성을 키울 수 있었다.
|
||||
|
||||
## 적용한 해결 방향
|
||||
|
||||
핵심 원칙:
|
||||
|
||||
- 적기가 완전히 같은 목표점으로 몰리지 않게 한다.
|
||||
- 겹침 보정은 강한 튕김이 아니라 작은 안정화 보정으로 한다.
|
||||
- 풀링된 적기는 스폰 시 내부 이동 상태를 반드시 초기화한다.
|
||||
|
||||
## 적용한 변경
|
||||
|
||||
### 적 스폰 상태 초기화
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/EntityManager.ts`
|
||||
|
||||
변경:
|
||||
|
||||
- `spawnEnemy`에서 아래 값을 기본 초기화하도록 추가했다.
|
||||
- `vx`
|
||||
- `vy`
|
||||
- `hit`
|
||||
- `hitTimer`
|
||||
- `stunTimer`
|
||||
- `targetId`
|
||||
- `telegraphFrame`
|
||||
- `telegraphX`
|
||||
- `telegraphY`
|
||||
|
||||
의도:
|
||||
|
||||
- 풀링 재사용으로 이전 적의 내부 이동/AI 상태가 새 적에게 이어지는 것을 방지한다.
|
||||
|
||||
### Striker 편대 lane 유지
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/CombatSystem.ts`
|
||||
|
||||
변경:
|
||||
|
||||
- `updateStrikerAI`가 `player.x`만 추적하지 않고, 스폰 당시 `targetX` 기반의 formation lane을 유지하도록 변경했다.
|
||||
- 같은 편대에서 나온 적들이 플레이어 중심으로 완전히 겹치지 않고 좌우 간격을 유지한다.
|
||||
- 근접 압박 이동도 `player.x` 기준이 아니라 `desiredX` 기준으로 변경했다.
|
||||
|
||||
의도:
|
||||
|
||||
- 엘리트/스트라이커가 “한 점으로 뭉치는” 현상을 줄인다.
|
||||
- 회피할 수 있는 공격 편대처럼 보이게 한다.
|
||||
|
||||
### Enemy separation 안정화
|
||||
|
||||
수정 파일:
|
||||
|
||||
- `/Volumes/Data/project/Antigravity/Skybound/src/features/game/systems/CombatSystem.ts`
|
||||
|
||||
변경:
|
||||
|
||||
- Elite/MiniBoss의 최소 분리 거리를 늘렸다.
|
||||
- 동일 좌표 또는 거의 동일 좌표일 때 deterministic escape vector를 적용했다.
|
||||
- 강한 즉시 위치 보정 대신 작은 보정값을 clamp하여 적용했다.
|
||||
- 분리 적용 시 `vx`, `vy`를 일부 감쇠하여 AI 이동과 separation이 서로 싸우는 힘을 줄였다.
|
||||
|
||||
의도:
|
||||
|
||||
- 겹침은 천천히 풀되, 프레임마다 좌우로 튀는 느낌을 줄인다.
|
||||
- 적기가 낀 듯한 떨림보다 자연스러운 편대 간격 회복으로 보이게 한다.
|
||||
|
||||
## 검증
|
||||
|
||||
- `npm run build` 성공
|
||||
- 출력 디렉터리: `dist/47`
|
||||
|
||||
## 후속 체크 포인트
|
||||
|
||||
- Stage 1에서 엘리트/스트라이커 2기가 겹쳤을 때 떨림이 줄었는지 확인한다.
|
||||
- 적기가 지나치게 벌어져 난이도가 쉬워지지 않는지 확인한다.
|
||||
- Striker가 lane을 유지하면서도 플레이어를 압박하는 느낌이 살아있는지 확인한다.
|
||||
- Chase 계열 일반 적도 같은 문제가 계속 보이면 chase AI에도 lane/flow-field 기반 회피를 추가한다.
|
||||
@@ -0,0 +1,18 @@
|
||||
# [[Frontend Application Debugging]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
프론트엔드 애플리케이션 디버깅은 프로덕션 환경의 런타임 오류, 메모리 누수, 성능 병목 현상 및 복잡한 상태 변화를 식별하고 해결하는 과정입니다 [1-3]. 단순한 `console.log`에 의존하기보다는 브라우저 개발자 도구와 클라우드 옵저버빌리티 도구를 활용하여 체계적으로 접근하는 것이 확장 가능한 최신 프론트엔드 개발의 핵심입니다 [4-6].
|
||||
|
||||
## 📖 Core Content
|
||||
- **메모리 누수 및 성능 디버깅**: Chrome DevTools의 Memory 패널과 힙 스냅샷(Heap Snapshots)을 비교 및 분석하여 메모리 누수를 진단합니다 [7, 8]. 이를 통해 더 이상 필요하지 않지만 자바스크립트 참조로 인해 가비지 컬렉션되지 않은 '분리된 DOM 노드(Detached DOM nodes)', 누적된 이벤트 리스너, 클로저로 유지되는 참조 등을 식별할 수 있습니다 [9-12]. 또한 작업 관리자(Task Manager)와 Performance 패널의 할당 타임라인(Allocation Timeline)을 활용해 실시간으로 JS 힙 메모리 할당 패턴을 시각화하고 잦은 가비지 컬렉션을 추적합니다 [13-16].
|
||||
- **에러 핸들링과 UI 복원**: React 환경에서는 단일 컴포넌트의 렌더링 오류가 전체 화면을 백지화(White screen of death)하는 것을 방지하기 위해 '에러 바운더리(Error Boundaries)'를 도입합니다 [17-19]. 불안정한 서드파티 위젯이나 복잡한 폼 등의 컴포넌트를 에러 바운더리로 개별적으로 감싸면, 런타임 에러 발생 시 앱의 전체 크래시를 막고 안정적인 대체(Fallback) UI를 표시할 수 있습니다 [20-22].
|
||||
- **클라우드 로깅 및 옵저버빌리티 도구**: 축소된(minified) 자바스크립트 번들에서 발생하는 프로덕션 환경의 에러를 파악하기 위해 Sentry, LogRocket, Datadog RUM, SigNoz와 같은 전문 클라우드 플랫폼을 사용합니다 [4, 23]. Sentry는 에러를 지능적으로 그룹화하고 콘솔 로그 및 네트워크 요청 등의 경로(Breadcrumbs)를 제공하며 [24], LogRocket은 사용자의 화면을 녹화하여 Redux/Zustand 상태 변화와 네트워크 폭포를 완벽히 재현함으로써 복잡한 디버깅을 돕습니다 [25-27].
|
||||
- **상태 관리 및 렌더링 디버깅**: 복잡한 상태를 디버깅할 때 Redux DevTools와 같은 도구는 상태 내역 조회, 시간 여행 디버깅(Time-Travel Debugging), 액션 리플레이 기능을 제공하여 비동기 작업의 흐름을 단시간 내에 파악할 수 있게 해줍니다 [28, 29]. 렌더링 성능 이슈의 경우 React DevTools의 Profiler 패널을 사용하여 컴포넌트의 렌더링 소요 시간과 재렌더링의 트리거(prop 또는 state 변경 등)를 정확히 진단합니다 [30, 31].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Error Boundaries]], [[State Management Libraries]], [[Performance Optimization]], [[Memory Leak Detection]]
|
||||
- **Projects/Contexts:** [[Large-scale React Applications]], [[Production Environment Observability]]
|
||||
- **Contradictions/Notes:** 상태 관리 방식에 있어 Redux는 강력한 디버깅 도구를 통해 버그 추적을 용이하게 하지만, React Context API는 상태 내역 관리나 시간 여행 디버깅 기능이 전혀 없어 복잡한 앱에서 원인을 파악하기 매우 어렵다는 특징이 있습니다 [28, 29]. 또한, 클라우드 디버깅 툴의 경우 Datadog은 프론트엔드와 백엔드 간 분산 추적이 가능하여 디버깅에 매우 강력하나, 로그 수집과 검색(Indexing)에 별도로 이중 과금을 하는 복잡한 구조를 가져 대규모 트래픽 환경에서는 가시성과 비용 중 하나를 타협해야 할 수 있습니다 [32-34].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
@@ -0,0 +1,20 @@
|
||||
# [[Frontend Refactoring]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
프론트엔드 리팩토링은 기존 프론트엔드 코드베이스의 외부 동작을 변경하지 않으면서 구조, 유지보수성, 품질을 개선하는 과정입니다 [1]. 이 과정에는 거대한 컴포넌트의 분할, 레거시 코드(예: 클래스형 컴포넌트)의 현대화, 더 나은 상태 관리 및 아키텍처 경계 도입 등이 포함됩니다 [2, 3]. 점진적인 마이그레이션 전략을 사용하고 사전에 테스트를 작성함으로써 개발자는 기술 부채를 안전하게 관리하고 애플리케이션을 확장할 수 있습니다 [1, 4].
|
||||
|
||||
## 📖 Core Content
|
||||
* **사전 준비 및 테스트:** 리팩토링을 시작하기 전에 코드 변경으로 인해 기존 기능이 손상되지 않도록 단위 테스트(Unit Test)나 UI 테스트를 먼저 작성하는 것이 필수적입니다 [4-6]. 또한 본격적인 리팩토링에 앞서 비즈니스 로직, 전역 상태, 라우팅 및 API 호출 구조를 파악하여 프로젝트에 대한 멘탈 모델을 명확히 구축해야 합니다 [7, 8].
|
||||
* **점진적 마이그레이션 (Incremental Migration):** 전면 재작성(Rewrite)의 위험을 피하기 위해 리팩토링은 "재작성하지 말고 리팩토링하라"는 철학에 따라 점진적으로 이루어져야 합니다 [1]. 예를 들어 Context API에서 Zustand로 전환할 때, 전체 코드를 한 번에 바꾸기보다는 알림과 같은 단순한 유틸리티부터 시작해 결제 흐름 같은 복잡한 도메인으로 한 번에 하나의 스토어씩 마이그레이션하는 것이 권장됩니다 [1].
|
||||
* **코드베이스 현대화:** 레거시 React 앱을 리팩토링할 때 수행해야 할 주요 작업으로는 TypeScript로의 전환, 클래스 기반 컴포넌트를 훅(Hooks)을 사용하는 함수형 컴포넌트로 변경, 노후화된 라이브러리를 최신 버전으로 업데이트, 그리고 불필요한 `useEffect` 사용 제거 등이 있습니다 [3]. 또한, 여러 방식이 혼용된 CSS 스타일링(예: 외부 CSS, sx, style 속성 혼용)을 하나의 방식으로 통일하여 표준화해야 합니다 [9-11].
|
||||
* **상태 관리 최적화:** 서버 상태 관리를 위해서는 TanStack Query를 도입하고, 불필요해진 Redux 구현체를 제거하는 것이 좋습니다 [3]. 클라이언트 측 전역 상태는 Context나 Zustand로 관리하되, 로컬 상태는 가능한 한 개별 컴포넌트 내부에 국한시키는 방향으로 상태 관리 구조를 개선해야 합니다 [3].
|
||||
* **커스텀 훅 및 컴포넌트 분할:** 모던 React에서 리팩토링의 가장 중요한 단위는 '커스텀 훅(Custom Hooks)'입니다 [2]. 복잡한 데이터 페칭이나 폼 처리 로직을 `useFetch`나 `useForm` 같은 커스텀 훅으로 추출하면 비즈니스 로직을 UI에서 분리하고 단위 테스트 속도를 높일 수 있습니다 [2]. 더불어 300줄을 초과하거나 책임이 혼재되어 단일 책임 원칙(SRP)을 위반하는 컴포넌트는 작고 명확한 목적을 가진 여러 컴포넌트로 분할해야 합니다 [12, 13].
|
||||
* **원칙 및 린팅 도구 적용:** DRY 및 YAGNI 원칙을 적용하여 무의미한 주석이나 잉여 코드를 제거하고 기술 부채를 줄여야 합니다 [14, 15]. 또한 ESLint와 같은 린팅 도구(eslint-plugin-react 등)를 설정하여 일관된 코딩 표준을 자동으로 강제하고 더 나은 코드 품질을 유지해야 합니다 [14, 16].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Incremental Migration]], [[Custom Hooks]], [[Single Responsibility Principle]], [[Technical Debt]], [[State Management]]
|
||||
- **Projects/Contexts:** [[Legacy React Codebase Modernization]], [[Context API to Zustand Migration]]
|
||||
- **Contradictions/Notes:** 소규모 코드베이스의 경우, 기존 코드를 리팩토링하는 것보다 아예 처음부터 새 앱을 작성하는 것이 더 쉬울 수도 있다는 의견이 존재합니다 [5]. 또한 리팩토링 시 TypeScript로의 전환이 널리 권장되지만[3], 인지적 복잡성을 가중시킬 수 있으므로 한 번에 전면 도입하기보다는 JS에서 TS로 개별 파일을 재작성하며 점진적으로 채택하는 것이 낫다는 시각도 있습니다 [17].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
@@ -0,0 +1,37 @@
|
||||
# [[Frontend System Architecture]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
프론트엔드 시스템 아키텍처는 애플리케이션의 복잡성이 증가함에 따라 확장성, 유지보수성 및 고성능을 보장하기 위해 설계되는 구조적 프레임워크입니다 [1]. 이는 단순한 UI 렌더링을 넘어 모듈식 폴더 구조, 클린 코드 방법론, 효율적인 상태 관리 전략, 빌드 및 런타임 최적화를 포괄합니다 [1]. 현대의 React 환경에서는 비즈니스 로직이 UI 컴포넌트로 누수되는 것을 방지하고 명확한 의존성 경계를 설정하여 시스템이 안전하게 확장되도록 하는 것이 핵심입니다 [2, 3].
|
||||
|
||||
## 📖 Core Content
|
||||
* **아키텍처 패러다임 및 폴더 구조 (Folder Structure):**
|
||||
* 과거의 파일 유형별(기술적 역할별) 폴더 구조는 규모가 커질수록 유지보수가 어려워, 비즈니스 기능(Feature)이나 도메인을 중심으로 코드를 구성하는 구조가 표준으로 자리 잡았습니다 [4, 5].
|
||||
* **Feature-Sliced Design (FSD):** 프론트엔드에 특화된 아키텍처로, 프로젝트를 `app`, `pages`, `widgets`, `features`, `entities`, `shared`라는 명확한 계층(Layer)으로 나눕니다 [6, 7]. 상위 계층은 하위 계층에만 의존할 수 있다는 엄격한 '단방향 의존성' 규칙을 적용하며, 각 모듈은 `index.ts`를 통한 단일 퍼블릭 API(Public API)만을 노출하여 캡슐화를 강제합니다 [6, 8, 9].
|
||||
* **클린 코드 및 소프트웨어 엔지니어링 원칙 (Clean Code Principles):**
|
||||
* **SOLID:** 단일 책임 원칙(SRP)에 따라 300줄 이상의 방대한 컴포넌트는 더 작고 명확한 책임을 가진 컴포넌트로 분리해야 하며, 개방-폐쇄 원칙(OCP)을 위해 컴포넌트 합성(`children` 활용)을 사용하고, 인터페이스 분리 원칙(ISP)을 통해 컴포넌트가 꼭 필요한 Props만 전달받도록 설계해야 합니다 [10-12].
|
||||
* **DRY, KISS, YAGNI:** 커스텀 훅을 통해 코드 반복을 줄이되(DRY), 불필요하고 복잡한 추상화를 피하여 코드를 단순하게 유지하고(KISS), 당장 필요하지 않은 기능은 미리 구현하지 않는(YAGNI) 실용적인 접근이 필요합니다 [13-15].
|
||||
* **네이밍 규칙 및 거버넌스 (Naming Conventions):**
|
||||
* 운영체제 간의 호환성을 위해 파일 및 폴더 이름은 `kebab-case`를 사용합니다 [16-18]. 반면 React 컴포넌트는 HTML 요소와 구분하기 위해 `PascalCase`를, 변수 및 훅(Hooks)은 `camelCase`, 상수는 `UPPER_SNAKE_CASE`를 사용합니다 [19-21].
|
||||
* 이러한 규칙은 ESLint, Prettier, Husky와 같은 도구를 통해 자동화 및 검증되어야 합니다 [19].
|
||||
* **상태 관리 아키텍처 (State Management):**
|
||||
* 현대의 상태 관리는 로컬 컴포넌트 상태, 전역 애플리케이션 상태, 서버 캐시 상태, URL 상태로 역할을 세분화합니다 [22].
|
||||
* 자주 변경되지 않는 설정값(테마 등)은 Context API로 충분하지만, 빈번하게 변경되는 전역 상태는 불필요한 전체 리렌더링을 방지하는 선택자(Selector) 패턴 기반의 Zustand가 유리하며, 복잡한 비동기 작업과 대규모 팀 협업에는 Redux가 권장됩니다 [23-28]. 서버 상태 처리를 위해서는 TanStack Query(React Query)를 사용하여 네트워크 로직을 UI와 분리합니다 [26, 29].
|
||||
* **성능 최적화 (Performance Optimization):**
|
||||
* Vite를 활용한 빌드 환경에서는 `manualChunks`를 통해 무거운 벤더 라이브러리를 분리하고, `React.lazy`와 Suspense를 결합하여 라우트 기반 코드 스플리팅을 적용함으로써 초기 로딩 속도를 크게 향상시킬 수 있습니다 [30-33].
|
||||
* 2025년 기준 React Compiler가 안정화되어 빌드 타임에 자동으로 메모이제이션을 수행하므로 수동적인 `useMemo`, `useCallback`의 남용을 줄일 수 있습니다 [30, 34, 35].
|
||||
* **디버깅 및 회복성 (Debugging & Resilience):**
|
||||
* 애플리케이션 충돌 시 백지 화면이 나오는 것을 막기 위해 React Error Boundaries를 대시보드나 서드파티 위젯 같은 불안정한 섹션에 개별적으로 적용하여 대체 UI를 제공해야 합니다 [36-38].
|
||||
* Chrome DevTools의 Heap Snapshots과 Allocation Timelines를 통해 메모리 누수(예: 분리된 DOM 노드, 해제되지 않은 이벤트 리스너)를 탐지하고 관리합니다 [39-41].
|
||||
* **Git 워크플로우 (Git Workflow):**
|
||||
* 소규모 팀의 경우, 무거운 Git Flow 대신 '수명이 짧은 기능 브랜치(Feature-branch)' 또는 '트렁크 기반(Trunk-based)' 워크플로우를 채택하는 것이 효율적입니다 [42-44].
|
||||
* 추적성을 높이기 위해 브랜치와 커밋 메시지에 티켓 ID를 포함하며, `feat:`, `fix:`와 같은 Conventional Commits 규칙을 따릅니다 [45-48]. PR(Pull Request)을 통한 코드 리뷰 및 CI 테스트는 main 병합 전 필수입니다 [45, 49].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** `[[Feature-Sliced Design]]`, `[[SOLID Principles in React]]`, `[[State Management]]`, `[[React Performance Optimization]]`, `[[Git Workflow]]`, `[[Error Boundaries]]`
|
||||
- **Projects/Contexts:** `[[Modern React Application Development (2025)]]`, `[[Vite Build Tool]]`
|
||||
- **Contradictions/Notes:**
|
||||
- 상태 관리 접근에 있어, 소스들은 Context API가 사용하기 간편하지만 잦은 업데이트가 발생하는 전역 상태의 경우 '전체 구독 컴포넌트 리렌더링'이라는 치명적인 성능 병목을 일으킨다고 지적하며, 이를 해결하기 위해 Zustand나 Redux의 도입을 주장합니다 [24, 26, 50-52].
|
||||
- 성능 최적화와 관련해, React Compiler의 도입으로 `React.memo`나 `useMemo` 같은 수동 메모이제이션의 필요성이 크게 줄어들었으나, 서드파티 라이브러리의 호환성 문제(매 렌더마다 새로운 참조를 반환하는 훅 등)나 규칙을 따르지 않은 레거시 코드에서는 여전히 수동 메모이제이션이 필요할 수 있다고 설명합니다 [35, 53, 54].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
@@ -0,0 +1,22 @@
|
||||
# [[Garbage Collection]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
가비지 컬렉션(Garbage Collection)은 자바스크립트 엔진과 브라우저가 더 이상 필요하지 않은 메모리를 자동으로 회수하는 프로세스입니다 [1, 2]. 페이지의 DOM 트리나 자바스크립트 코드에서 어떠한 참조도 남아있지 않은 객체나 노드만이 가비지 컬렉션의 대상이 됩니다 [2, 3]. 브라우저가 가비지 컬렉션을 수행하는 동안에는 모든 스크립트 실행이 일시 중지되므로, 이 작업이 너무 빈번하게 발생하면 애플리케이션의 잦은 멈춤이나 성능 지연을 유발할 수 있습니다 [1].
|
||||
|
||||
## 📖 Core Content
|
||||
* **가비지 컬렉션과 메모리 누수(Memory Leak):**
|
||||
자바스크립트 애플리케이션에서 가비지 컬렉터는 참조되지 않는 메모리만 회수합니다 [2]. 만약 화면(DOM 트리)에서는 제거되었지만 자바스크립트 변수나 클로저 등에 의해 여전히 참조되고 있는 '분리된 DOM 노드(Detached DOM nodes)'가 있다면, 가비지 컬렉터는 이를 회수할 수 없어 메모리 누수가 발생하게 됩니다 [3, 4].
|
||||
* **성능 문제 식별:**
|
||||
가비지 컬렉션이 진행되는 동안에는 스크립트 실행이 멈추기 때문에 잦은 가비지 컬렉션은 UX에 악영향을 미칩니다 [1]. Chrome 작업 관리자나 타임라인 메모리 기록에서 메모리 사용량이 계속해서 빠르게 오르내리는(rising and falling) 패턴이 나타난다면, 가비지 컬렉션이 너무 자주 발생하고 있다는 신호입니다 [5].
|
||||
* **디버깅 및 모니터링 기법:**
|
||||
Chrome DevTools를 사용하여 메모리 문제를 추적할 때, 기록을 시작하고 끝낼 때 가비지 컬렉션을 강제로 실행하는 것이 좋은 습관입니다 [6]. 메모리 탭에서 '휴지통(Collect garbage)' 아이콘을 클릭하여 가비지 컬렉션을 수동으로 트리거할 수 있으며, Chrome을 `--expose-gc` 플래그와 함께 실행했다면 콘솔에서 `window.gc()`를 호출하여 프로그래밍 방식으로도 강제 실행할 수 있습니다 [6-8].
|
||||
* **예방 및 최적화 전략:**
|
||||
메모리가 정상적으로 가비지 컬렉션되도록 하려면 적절한 자료구조를 선택해야 합니다. 예를 들어, 객체 캐시를 관리할 때는 일반 객체 대신 `WeakMap`을 사용하면 참조가 가비지 컬렉션을 방해하지 않게 하여 메모리 누수를 예방할 수 있습니다 [9].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Memory Leak]], [[Chrome DevTools]], [[Performance Optimization]], [[Detached DOM Nodes]]
|
||||
- **Projects/Contexts:** [[Frontend Debugging]], [[JavaScript Memory Management]]
|
||||
- **Contradictions/Notes:** 소스 간의 모순된 주장은 없으며, 제공된 소스들은 공통적으로 프론트엔드 성능 최적화와 메모리 누수 방지를 위해 가비지 컬렉션 메커니즘을 이해하고 Chrome DevTools를 통해 적극적으로 모니터링할 것을 강조하고 있습니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
@@ -0,0 +1,24 @@
|
||||
# [[Legacy Code Modernization]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
레거시 코드 모더니제이션(Legacy Code Modernization)은 애플리케이션의 기존 동작을 그대로 유지하면서 코드베이스의 구조, 유지보수성 및 확장성을 향상시키기 위해 코드를 재구성하고 업데이트하는 과정입니다 [1]. React 애플리케이션의 경우, 클래스 기반 컴포넌트를 최신 함수형 컴포넌트와 훅(Hooks)으로 마이그레이션하고 오래된 라이브러리를 교체하며 기술 부채를 점진적으로 관리하는 작업이 포함됩니다 [1, 2]. 이 과정은 시스템의 전면적인 재작성(rewrite)을 피하고, 테스트 기반의 점진적인 리팩토링을 통해 안전하게 진행되어야 합니다 [1, 3].
|
||||
|
||||
## 📖 Core Content
|
||||
* **점진적 마이그레이션 전략 (Incremental Migration Strategies):** 기존 아키텍처나 기술(예: Context API에서 Zustand로의 전환)을 마이그레이션할 때, 한 번에 전체를 재작성하는 것은 위험하므로 "재작성이 아닌 리팩토링(refactor, do not rewrite)" 철학을 따라야 합니다 [1]. 한 번에 하나의 상태 스토어나 모듈씩 점진적으로 이동해야 아키텍처를 현대화하는 동안에도 새로운 기능 개발을 지속할 수 있습니다 [1].
|
||||
* **사전 준비 및 테스트:** 리팩토링의 첫 번째 방어선은 유닛 테스트(Unit Test)를 작성하는 것입니다 [3]. 테스트를 작성하면 애플리케이션의 여러 부분이 어떻게 동작하는지 억지로라도 학습하게 되며, 코드를 개선하는 과정에서 발생할 수 있는 회귀(regression) 에러를 방지할 수 있습니다 [3, 4]. 코드를 수정하기 전, 비즈니스 로직의 목적을 파악하고 라우팅, 인증, API 호출 및 전역 상태를 먼저 매핑(mapping)하여 멘탈 모델을 구축하는 것이 필수적입니다 [5, 6].
|
||||
* **React 특화 모더니제이션 핵심 목표 (Quick Wins):**
|
||||
* 기존의 클래스 기반 컴포넌트를 함수형 컴포넌트와 훅(Hooks)으로 전환합니다 [2].
|
||||
* 불필요한 `useEffect` 사용을 식별하고 모두 제거합니다 [2].
|
||||
* 서버 상태(Server state) 관리를 위해 TanStack Query(React Query) 등을 도입하고, 기존의 무거운 Redux 구현체를 덜어냅니다. 남은 클라이언트 전역 상태는 Zustand나 Context로 관리합니다 [2].
|
||||
* JavaScript 코드베이스라면 TypeScript로 마이그레이션하여 타입 안정성을 확보합니다 [2]. (다만, 복잡성을 고려해 점진적으로 도입할 수 있습니다 [7]).
|
||||
* 지원이 중단된(deprecated) 라이브러리를 업데이트하고, 최신 React 버전에 맞춥니다 [2].
|
||||
* **아키텍처 개선 및 커스텀 훅의 활용:** 컴포넌트는 단일 책임 원칙(SRP), DRY, YAGNI 원칙에 기반하여 작고 명확하게 유지되어야 합니다 [8]. 최신 React 환경에서 리팩토링의 주요 단위는 '커스텀 훅'입니다. 거대한 컴포넌트 내부에 혼재된 비즈니스 로직(데이터 페칭, 폼 핸들링 등)을 커스텀 훅으로 추출하여 UI와 로직을 격리하면, 결합도를 낮추고 테스트 용이성을 크게 높일 수 있습니다 [9-11].
|
||||
* **린팅 및 거버넌스 도입:** ESLint(예: `eslint-plugin-react`, `eslint-plugin-react-hooks` 등)를 프로젝트와 IDE에 적용하여 개발 모범 사례를 강제하고 코드 냄새(code smell)를 식별 및 방지해야 합니다 [12].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Refactoring Techniques]], [[Technical Debt Management]], [[Clean Code Principles]], [[Single Responsibility Principle]], [[State Management Migration]]
|
||||
- **Projects/Contexts:** [[React Frontend Development]], [[Feature-Sliced Design]]
|
||||
- **Contradictions/Notes:** 레거시 코드 리팩토링 전략을 구상할 때 Claude Code 등 AI 도구의 도움을 받아 분석과 개선을 진행하라는 추천이 있는 반면 [11, 13, 14], 시스템의 비즈니스 로직과 흐름을 개발자 스스로 완벽히 이해하고 테스트 코드를 보강하는 과정이 선행되지 않으면 의미가 없다는 시각이 함께 존재합니다 [5]. 또한, 상태 관리 리팩토링 시 Context에서 Zustand로의 이전은 쉽지만, 구조화가 덜 된 상태에서 Zustand를 남용하다 나중에 Redux로 마이그레이션해야 할 때는 과정이 매우 고통스러울 수 있다는 점을 유의해야 합니다 [15].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
@@ -0,0 +1,29 @@
|
||||
# [[React Compiler]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
React Compiler(과거 명칭 React Forget)는 Meta에서 개발하여 2025년 10월에 안정화된 React 애플리케이션용 빌드 타임 최적화 도구입니다 [1, 2]. 개발자가 수동으로 작성하던 메모이제이션(`React.memo`, `useMemo`, `useCallback`) 로직을 빌드 단계에서 분석하여 자동으로 삽입함으로써 불필요한 리렌더링을 방지합니다 [1, 3]. 이를 통해 프론트엔드 코드의 가독성을 높이고 유지보수성을 향상시키며, INP(Interaction to Next Paint)와 같은 렌더링 성능 지표를 효과적으로 개선할 수 있습니다 [1, 4, 5].
|
||||
|
||||
## 📖 Core Content
|
||||
|
||||
**작동 원리 및 주요 특징**
|
||||
* **세밀한 자동 최적화:** React Compiler는 전체 컴포넌트를 감싸는 기존 방식과 달리, 개별 JSX 엘리먼트와 내부 계산 로직 등 훨씬 세밀한(Granular) 수준에서 렌더링 결과를 캐싱하여 입력값이 변경되지 않으면 재사용합니다 [4, 6].
|
||||
* **도구 생태계 통합:** Babel 플러그인 형태로 구현되어 Vite, Next.js, Rsbuild와 같은 현대적인 빌드 도구와 쉽게 통합할 수 있습니다 [7, 8]. React 19에 최적화되어 있으나 React 17 및 18 버전에서도 사용할 수 있습니다 [9].
|
||||
* **React Developer Tools 지원:** React Developer Tools (v5.0 이상)의 Components 및 Profiler 탭을 통해 컴파일러가 성공적으로 처리한 컴포넌트에는 'Memo ✨' 배지가 표시되어 동작 여부를 시각적으로 확인할 수 있습니다 [8, 10].
|
||||
|
||||
**주요 장점**
|
||||
* **클린 코드 및 유지보수성 (Clean Code):** 메모이제이션을 위한 불필요한 래퍼(wrapper) 코드를 제거하여 소스 코드가 직관적이고 깔끔해지며, 개발자가 수동으로 종속성 배열을 관리할 때 발생할 수 있는 휴먼 에러를 원천 차단합니다 [3-5, 7].
|
||||
* **입증된 프로덕션 성능:** Meta의 Instagram, Quest Store를 비롯해 Sanity Studio, Wakelet 등의 프로덕션 환경에서 렌더링 성능 향상, 로딩 속도 감소 및 최대 30%에 이르는 INP 개선을 기록했습니다 [5].
|
||||
|
||||
**한계 및 도입 시 고려사항**
|
||||
* **React 규칙(Rules of React)의 엄격한 준수 필요:** 컴파일러는 정적 분석을 기반으로 작동하므로, 상태 불변성이나 렌더링 중 부수 효과 금지 같은 React의 핵심 규칙을 지켜야만 최적화가 이뤄집니다. 이를 강제하기 위해 `eslint-plugin-react-hooks` 사용이 강력히 권장됩니다 [9, 11, 12].
|
||||
* **라이브러리 호환성 문제:** 매 렌더링마다 새로운 객체 참조를 반환하는 일부 서드파티 훅(예: TanStack Query의 `useMutation()`, React Router의 `useLocation()`)을 사용할 경우 메모이제이션 체인이 끊어져 성능 최적화가 제한될 수 있습니다 [12, 13].
|
||||
* **디버깅의 난해함:** 컴파일러가 블랙박스처럼 동작하므로, 의도치 않은 리렌더링 발생 시 소스 코드상에서 원인을 찾기 어려우며 Profiler 도구에 크게 의존해야 합니다 [14].
|
||||
* **레거시 프로젝트의 기술 부채:** React 규칙 위반이 잦은 오래된 대형 코드베이스에 적용하려면 상당한 리팩토링 비용이 발생할 수 있습니다 [12, 15].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Memoization]], [[Performance Optimization]], [[Clean Code]], [[Rules of React]], [[Vite]]
|
||||
- **Projects/Contexts:** [[Frontend Scalable Architecture]], [[Legacy Codebase Refactoring]]
|
||||
- **Contradictions/Notes:** React Compiler를 적용하면 대부분의 `React.memo`는 중복되어 제거할 수 있지만 [15], 서드파티 라이브러리 호환성 문제나 컴파일러가 자동으로 처리하지 못하는 특정 엣지 케이스에서는 여전히 명시적인 제어를 위해 `useMemo`와 `useCallback`을 병행해야 한다고 소스는 지적합니다 [12, 16].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
@@ -0,0 +1,27 @@
|
||||
# [[React Project Structure]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
React 애플리케이션은 기본적으로 아키텍처나 폴더 구조를 강제하지 않기 때문에, 프로젝트가 확장됨에 따라 구조 관리가 필수적입니다 [1]. 유지보수성, 확장성, 협업의 효율성을 높이기 위해 프론트엔드 생태계는 과거의 파일 유형 기반 구조에서 기능(Feature) 또는 도메인 기반의 구조로 전환되었습니다 [2, 3]. 특히 2025년 기준으로는 모듈화와 관심사 분리를 강조하는 하이브리드 폴더 구조와 Feature-Sliced Design(FSD)과 같이 캡슐화와 단방향 의존성을 강제하는 체계적인 방법론이 권장되고 있습니다 [4-7].
|
||||
|
||||
## 📖 Core Content
|
||||
* **폴더 구조의 중요성**
|
||||
* 구조가 명확하지 않은 대규모 React 앱은 비즈니스 로직이 UI 컴포넌트로 누수되거나 상태 소유권이 불분명해지는 등 아키텍처 붕괴(Architectural Collapse)를 겪기 쉽습니다 [1, 8].
|
||||
* 잘 구성된 폴더 구조는 파일의 목적을 명확히 하여 빠른 파일 탐색을 돕고, 예측 가능성을 높이며, 디버깅을 용이하게 하여 장기적인 기술 부채를 줄여줍니다 [9-11].
|
||||
|
||||
* **구조의 발전 및 주요 접근 방식**
|
||||
* **파일 유형 기반 구조 (File-Type Based Structure):** 컴포넌트, 훅, 스타일 등을 각각의 역할별 폴더(`/components`, `/hooks` 등)에 모아두는 고전적인 방식입니다 [2, 12, 13]. 작은 규모에서는 직관적이지만, 앱이 커지면 특정 기능을 수정하기 위해 전체 디렉토리를 탐색해야 하므로 확장성이 크게 떨어집니다 [2, 12, 13].
|
||||
* **기능 기반 구조 (Feature-Based Structure):** 비즈니스 도메인이나 기능(예: `auth`, `dashboard`)을 중심으로 관련된 컴포넌트, 훅, API, 타입을 하나의 폴더에 캡슐화하여 독립적인 모듈처럼 다루는 방식입니다 [3, 14, 15]. 이는 높은 응집도와 명확한 경계를 제공하여 확장에 유리합니다 [3, 15].
|
||||
* **2025년 권장 하이브리드 구조:** 전역 공유 요소와 기능별 요소를 균형 있게 분리합니다. 주로 `/src` 디렉토리 하위에 재사용 가능한 `/components`, 도메인 로직을 캡슐화한 `/features`, 공통 `/hooks`, `/pages`(라우트), 외부 통신용 `/services`, 전역 상태용 `/store`, 유틸리티 함수용 `/utils` 등으로 구성됩니다 [16-25].
|
||||
|
||||
* **Feature-Sliced Design (FSD)**
|
||||
* 대규모 React 애플리케이션을 위해 설계된 현대적인 아키텍처 방법론으로, 컴포넌트 기반 개발, 도메인 주도 설계(DDD), 모듈식 시스템의 장점을 결합했습니다 [4, 26].
|
||||
* **단방향 의존성 계층:** `shared`(공통 유틸/UI) $\rightarrow$ `entities`(비즈니스 모델) $\rightarrow$ `features`(사용자 상호작용) $\rightarrow$ `widgets`(조합된 UI 블록) $\rightarrow$ `pages`(화면) $\rightarrow$ `app`(전역 설정) 순으로 계층을 나누며, 하위 계층은 상위 계층을 import 할 수 없도록 엄격히 통제합니다 [5, 14, 27].
|
||||
* **Public API 규칙:** 각 슬라이스는 단일 진입점(`index.ts`)만을 노출하며 내부 구현은 숨깁니다. 이를 통해 의도치 않은 결합(Coupling)을 방지하고 안전한 리팩토링을 보장합니다 [28, 29].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Feature-Sliced Design (FSD)]], [[Domain-Driven Design]], [[Clean Code]]
|
||||
- **Projects/Contexts:** [[Scalable Frontend Systems]], [[React Development]]
|
||||
- **Contradictions/Notes:** 기능 기반 구조나 FSD 방법론은 대규모 애플리케이션의 유지보수와 확장을 위해서는 필수적이고 훌륭한 해결책이지만 [4, 30], 매우 단순한 소규모 프로젝트나 초보자에게는 디렉토리 구조 설정이 불필요하게 복잡한 오버킬(overkill)이 될 수 있으며 초기 학습 곡선이 요구됩니다 [30-32].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
@@ -0,0 +1,30 @@
|
||||
# [[SOLID Principles]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
SOLID 원칙은 소프트웨어를 더 명확하고 체계적이며 유지보수하기 쉽게 작성하도록 돕는 5가지 핵심 설계 원칙의 약자입니다[1]. 본래 객체 지향 프로그래밍(OOP)을 위해 고안되었으나, 현대의 함수형 React 코드베이스에서도 유연하게 해석되어 컴포넌트 아키텍처에 적용됩니다[2]. 프론트엔드 개발에서 컴포넌트 간의 결합도를 낮추고 로직의 예측 가능성을 높여 대규모 애플리케이션의 구조적 확장성을 확보하는 데 필수적인 역할을 합니다[3, 4].
|
||||
|
||||
## 📖 Core Content
|
||||
* **단일 책임 원칙 (SRP - Single Responsibility Principle):**
|
||||
* 컴포넌트, 훅, 모듈은 오직 하나의 역할과 변경 이유만을 가져야 합니다[2, 5, 6].
|
||||
* 코드 품질을 향상시키는 가장 효과적인 원칙으로 평가됩니다[5]. 만약 컴포넌트가 300줄을 넘는다면 상태 관리, 데이터 페칭, 렌더링 등 너무 많은 역할을 수행하고 있을 가능성이 큽니다[5].
|
||||
* 거대한 컴포넌트를 더 작고 명확한 컴포넌트(예: `UserDashboard`를 `UserProfile`, `UserPosts` 등으로 분할)로 나누거나, 비즈니스 로직을 커스텀 훅으로 분리하여 이 원칙을 준수할 수 있습니다[2, 5].
|
||||
* **개방-폐쇄 원칙 (OCP - Open/Closed Principle):**
|
||||
* 소프트웨어는 확장을 위해서는 열려 있어야 하고, 수정을 위해서는 닫혀 있어야 합니다[2, 7].
|
||||
* React에서는 기존 컴포넌트의 내부 코드를 수정하는 대신, 컴포넌트 합성(Composition)을 활용하거나 `children` 및 render props 패턴을 사용하여 새로운 기능을 유연하게 추가하는 방식으로 구현됩니다[2, 6, 8].
|
||||
* **리스코프 치환 원칙 (LSP - Liskov Substitution Principle):**
|
||||
* 자식 클래스는 기존 코드를 손상시키지 않고 부모 클래스를 대체할 수 있어야 한다는 원칙입니다[7].
|
||||
* React 관점에서는 하위 컴포넌트가 기본 컴포넌트를 매끄럽게 대체할 수 있어야 함을 의미합니다[6]. 다만, 상속보다는 함수형 컴포넌트 합성을 주로 사용하는 현대 React에서는 상대적으로 사용 빈도가 낮습니다[2].
|
||||
* **인터페이스 분리 원칙 (ISP - Interface Segregation Principle):**
|
||||
* 컴포넌트는 자신이 사용하지 않는 props에 의존해서는 안 됩니다[2, 8].
|
||||
* 예를 들어, 단지 'username' 속성만 필요한 작은 컴포넌트에 거대한 'user' 객체 전체를 전달하면 불필요한 결합이 발생합니다[8]. 책임을 명확히 분리하여 필요한 데이터만 전달해야 하며, 이는 TypeScript 환경에서 특히 중요합니다[2, 6].
|
||||
* **의존성 역전 원칙 (DIP - Dependency Inversion Principle):**
|
||||
* 구체적인 구현체가 아닌 추상화에 의존해야 합니다[2, 9].
|
||||
* React에서는 한 컴포넌트가 다른 컴포넌트에 직접적으로 의존하기보다, props나 Context API를 통해 외부에서 의존성을 주입받는 방식으로 이 원칙을 적용하여 유연성을 높입니다[2, 6].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Clean Code]], [[DRY]], [[KISS]], [[YAGNI]], [[React Architecture]], [[Component Composition]]
|
||||
- **Projects/Contexts:** [[Large-scale React Applications]], [[Functional Programming in React]], [[Refactoring]]
|
||||
- **Contradictions/Notes:** 소스 [6]에서는 하위 컴포넌트가 기본 컴포넌트를 대체하는 방식으로 LSP를 설명하며 React에서의 적용법을 제시하지만, 소스 [2]에서는 현대의 함수형 React 코드에서는 클래스 상속이 거의 쓰이지 않아 LSP의 실질적인 적용 가능성은 낮다고 지적합니다.
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
@@ -0,0 +1,25 @@
|
||||
# [[State Management Migration]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
상태 관리 마이그레이션(State Management Migration)은 애플리케이션의 규모와 복잡성이 증가함에 따라 기존의 상태 관리 도구(예: Context API 또는 Redux)를 현재 프로젝트 요구사항에 더 적합한 도구(예: Zustand, TanStack Query)로 전환하는 과정을 의미합니다 [1-4]. 성공적인 마이그레이션을 위해서는 애플리케이션 전체를 한 번에 재작성하는 것을 피하고, 기술 부채를 관리하면서 기능 개발을 중단하지 않도록 점진적인 접근 방식을 취하는 것이 중요합니다 [3].
|
||||
|
||||
## 📖 Core Content
|
||||
* **주요 마이그레이션 경로 및 난이도**
|
||||
* **Context API에서 Zustand로의 전환 (쉬움)**: Context API는 잦은 상태 업데이트 시 구독 중인 모든 컴포넌트의 불필요한 재렌더링을 유발할 수 있으므로, 앱의 규모가 커질 때 Zustand로 전환하여 렌더링 성능을 최적화하는 것이 유리합니다 [2, 5].
|
||||
* **Zustand에서 Redux로의 전환 (어려움)**: 초기 프로젝트에서는 Zustand의 유연성과 빠른 속도가 이점을 주지만, 팀 규모가 커지고(예: 50~500명) 일관된 구조가 필요해지는 한계점에 도달하면 엄격한 패턴을 강제하는 Redux로의 마이그레이션을 계획해야 합니다 [1, 2].
|
||||
* **Redux에서 Zustand로의 전환 (위험함)**: 가능은 하지만 위험성이 따르는(Possible but risky) 작업입니다 [2].
|
||||
* **Redux 제거 및 TanStack Query 도입**: 서버 상태를 관리하기 위해 TanStack Query(React Query)를 추가하면서 기존의 Redux 구현을 제거하고, 남은 글로벌 클라이언트 상태만 Context나 Zustand로 가볍게 관리하는 리팩토링 방향도 권장됩니다 [4].
|
||||
|
||||
* **점진적 마이그레이션(Incremental Migration) 전략**
|
||||
* 기존의 기술에서 새로운 기술로 마이그레이션할 때, 전체 코드를 한 번에 재작성(complete rewrite)하는 것은 리스크가 너무 큽니다 [3].
|
||||
* 대신 한 번에 하나의 스토어씩 단계적으로 이동하는 방식이 권장됩니다 [3].
|
||||
* 예를 들어, 알림(notifications) 기능과 같은 간단한 유틸리티 영역부터 마이그레이션을 시작하여, 점진적으로 결제 흐름(checkout flow)과 같은 더 복잡한 도메인으로 확장해 나갑니다 [3].
|
||||
* "재작성하지 말고 리팩토링하라(refactor, do not rewrite)"는 철학을 지킴으로써, 프론트엔드 아키텍처를 현대화하는 과정 중에도 새로운 기능 개발을 중단 없이 지속할 수 있습니다 [3].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Context API]], [[Zustand]], [[Redux]], [[Refactoring Techniques]], [[TanStack Query]]
|
||||
- **Projects/Contexts:** [[Scalable Frontend Systems]], [[Legacy React Codebase Refactoring]]
|
||||
- **Contradictions/Notes:** 소스 전반에서 거대한 팀 규모나 복잡한 비동기 로직 통제를 위해서는 Redux가 최적이라고 주장하지만 [6, 7], 실제 레거시 리팩토링 조언에서는 오히려 비동기 서버 상태 관리를 위해 Redux 구현을 제거하고 TanStack Query를 도입하는 것이 추천되기도 하여 상황별로 상태 관리 라이브러리에 대한 선호도가 다름을 알 수 있습니다 [4].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
@@ -0,0 +1,24 @@
|
||||
# [[State Management]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
상태 관리(State Management)는 프론트엔드 애플리케이션에서 데이터의 흐름과 컴포넌트 간의 데이터 공유를 다루는 핵심 개념입니다 [1, 2]. 과거의 단일 스토어(monolithic) 방식에서 벗어나, 현대의 애플리케이션은 로컬 상태, 전역 애플리케이션 상태, 서버 상태 등을 분리하여 각각에 특화된 도구를 사용하는 방향으로 발전했습니다 [1]. 상태를 명확하게 분류하고 아키텍처 규칙을 준수하여 관리하는 것은 불필요한 리렌더링을 방지하고 앱의 성능과 확장성을 보장하는 데 필수적입니다 [3, 4].
|
||||
|
||||
## 📖 Core Content
|
||||
* **상태의 분류와 소유권 (State Categories & Ownership)**
|
||||
애플리케이션이 커질수록 상태를 세 가지 주요 카테고리로 명확히 나누어 관리해야 합니다: 시각적 토글이나 입력값을 다루는 **로컬 UI 상태**, 특정 사용자 상호작용과 연결된 **기능(Feature) 상태**, 사용자나 상품과 같은 핵심 비즈니스 데이터를 다루는 **엔티티(Entity) 상태**입니다 [3]. FSD(Feature-Sliced Design) 아키텍처는 엔티티 상태는 `entities` 계층에, 기능 상태는 `features` 계층에, 전역 인프라 상태는 `app` 계층에 두는 등 명확한 소유권 규칙을 강제합니다 [5].
|
||||
* **서버 상태와 애플리케이션 상태의 분리**
|
||||
API에서 가져온 데이터(서버 상태)는 클라이언트 측의 애플리케이션 상태와 근본적으로 다르며 캐싱, 동기화, 로딩 및 에러 사이클 처리가 필요합니다 [4, 6]. 이 때문에 2025년 프론트엔드 표준에서는 **TanStack Query (React Query)** 와 같은 라이브러리를 활용해 서버 상태를 전역 상태 관리도구와 분리하여 처리합니다 [4, 6-8].
|
||||
* **Context API의 특성과 한계**
|
||||
React에 내장된 Context API는 Props Drilling을 해결하기 위한 데이터 전송 메커니즘으로, 그 자체만으로는 상태 관리 솔루션이 아니며 `useState`나 `useReducer`와 함께 사용해야 합니다 [2, 9]. 테마, 로케일, 기능 플래그와 같이 **드물게 변경되는 정적인 전역 상태**를 구성하는 데 적합합니다 [10, 11]. 하지만, 상태 변경 시 이를 구독 중인 모든 컴포넌트가 불필요하게 리렌더링되는 "브로드캐스트 시스템"이므로 자주 변경되는 동적 데이터에는 적합하지 않습니다 [4, 12, 13].
|
||||
* **Zustand를 활용한 최적화**
|
||||
Zustand는 중소규모 앱(50-500개 컴포넌트)에 적합한 가볍고 유연한 전역 상태 라이브러리입니다 [14-16]. **"선택자(Selector) 패턴"**을 지원하여, 컴포넌트가 구독한 특정 상태 조각(slice)이 변경될 때만 리렌더링되도록 함으로써 Context API의 성능 한계를 극복합니다 [4, 17, 18]. 단, 규칙이 매우 자유롭기 때문에 비동기 패턴 처리에 대해 팀 내 엄격한 규칙이 없다면 코드베이스가 혼란스러워질 수 있는 단점이 있습니다 [15, 19, 20].
|
||||
* **대규모 시스템을 위한 Redux**
|
||||
Redux는 500개 이상의 컴포넌트를 가진 대규모 앱, 복잡한 파생/계산 상태, 10명 이상의 팀원이 협업하는 환경에서 산업 표준으로 사용됩니다 [21, 22]. 보일러플레이트가 많아 보일 수 있으나, 오히려 이러한 구조적 제약이 일관성을 부여하여 버그를 사전에 차단하고 RTK Query를 통해 복잡한 비동기 작업을 수월하게 처리할 수 있도록 돕습니다 [21, 23, 24]. 또한 Time-Travel 디버깅 같은 훌륭한 DevTools 통합 환경을 제공합니다 [22, 23, 25].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Context API]], [[Zustand]], [[Redux]], [[TanStack Query]], [[Feature-Sliced Design]]
|
||||
- **Projects/Contexts:** [[Scalable React Architecture]], [[React Performance Optimization]]
|
||||
- **Contradictions/Notes:** 상태 관리 라이브러리의 선택에 있어, 번들 크기(Bundle Size)만을 기준으로 결정하는 것은 잘못된 최적화 방식이며, 앱의 사용 사례, 팀의 규모 및 상태의 복잡성을 기반으로 평가해야 합니다 [26, 27]. 또한, 한 프로젝트에서 두 가지 도구를 병행하여 사용하는 것도 훌륭한 접근법입니다(예: 정적 설정에는 Context API, 동적 앱 상태에는 Zustand) [28].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
@@ -0,0 +1,19 @@
|
||||
# [[Unit Testing]]
|
||||
|
||||
## 📌 Brief Summary
|
||||
Unit testing(단위 테스트)은 프론트엔드 시스템에서 컴포넌트나 커스텀 훅과 같은 개별 로직을 독립적으로 검증하는 과정입니다 [1]. 특히 기존 코드베이스를 리팩토링할 때 기능이 손상되지 않았는지 보장하는 필수적인 방어 수단으로 활용됩니다 [2, 3]. 확장 가능(Scalable)한 폴더 구조에서는 유지보수성을 높이기 위해 단위 테스트 파일을 대상 컴포넌트와 동일한 위치에 두는 것이 권장됩니다 [4, 5].
|
||||
|
||||
## 📖 Core Content
|
||||
- **리팩토링의 필수 선행 조건**: 낯선 React 코드베이스나 레거시 코드를 리팩토링할 때(예: TypeScript 변환, 함수형 컴포넌트 및 훅(Hooks) 도입 등) **가장 먼저 단위 테스트를 작성하는 것이 강력히 권장**됩니다 [2, 3, 6]. 테스트를 작성하는 과정 자체가 앱의 동작 방식을 이해하는 데 도움을 주며, 코드를 개선하는 과정에서 기능이 깨지는 것을 즉각적으로 알려주는 역할을 합니다 [2, 7].
|
||||
- **폴더 구조 및 파일 배치 (Colocation)**: 단위 테스트 파일은 관련된 컴포넌트 파일명과 동일하게 작성(예: `Button.test.tsx` [8])하여 개발자가 쉽게 식별할 수 있도록 해야 합니다 [9]. 통합 테스트의 경우 별도의 폴더에 관리할 수 있지만, **단위 테스트는 유지보수성을 극대화하기 위해 테스트 대상 컴포넌트나 기능(feature)과 최대한 가까운 동일한 폴더 내에 배치(colocate)**하는 것이 모범 사례입니다 [4, 5].
|
||||
- **관심사 분리와 테스트 용이성**: 크고 복잡한 컴포넌트 내부의 데이터 패칭이나 폼 핸들링 등의 비즈니스 로직을 **커스텀 훅(Custom Hooks)으로 분리하면, UI 로직과 비즈니스 로직이 격리되어 느린 통합 테스트 대신 빠르고 독립적인 단위 테스트를 수행**하기가 훨씬 수월해집니다 [1].
|
||||
- **팀 워크플로우 및 통합 (CI/CD)**: 소규모 팀이든 대규모 팀이든 안정적인 Git 워크플로우를 위해, 코드를 메인(Main) 브랜치에 병합(merge)하기 전에는 **반드시 모든 단위 테스트와 CI 체크가 통과**되도록 보장해야 합니다 [10, 11].
|
||||
- **사용되는 주요 도구**: React와 Vite를 사용하는 최신 프론트엔드 환경에서는 견고한 단위 테스트를 위해 **Vitest 또는 Jest**가 활용되며 [4], UI 컴포넌트 테스트에는 **testing-library**를 사용하는 방식이 언급됩니다 [7].
|
||||
|
||||
## 🔗 Knowledge Connections
|
||||
- **Related Topics:** [[Refactoring Techniques]], [[Folder Structure]], [[Custom Hooks]], [[Clean Code Principles]]
|
||||
- **Projects/Contexts:** [[Scalable React Architecture]], [[Git Workflow for Frontend Teams]]
|
||||
- **Contradictions/Notes:** 전반적으로 모든 코드에 테스트를 작성하는 것이 권장되지만, 작은 규모의 앱이거나 일회성 프로젝트의 경우에는 굳이 테스트 작성에 큰 노력을 들일 필요가 없을 수도 있다는 일부 의견이 존재합니다 [12].
|
||||
|
||||
---
|
||||
*Last updated: 2026-04-26*
|
||||
Reference in New Issue
Block a user