
1. 과제를 진행하면서 고려한 것
1) React에서 추상화 벽이 만들어진 코드의 계층과 경계를 이해하기.
코드를 어떻게 잘 분리를 해두는게 좋을까? 이번 과제에서는 이를 크게 4단계로 나누어서 생각했다.
- 데이터 / 모델 (비즈니스 로직) / 로컬 상태(데이터를 비즈니스 로직 태운 다음 local에서 사용하기 위한 상태) / 컴포넌트
코드를 잘 분리한다는 것은 결합도가 낮고, 응집도가 높은 코드를 만들었다는 것이다. 이런 코드는 기능을 통째로 날려도 잘 돌아가야 한다. 고로 cart가 어떻게 돌아가는지, product가 어떻게 돌아가는지 서로 알 필요가 없다.
이 지점에서 FSD가 최근 각광받는 이유도, 기능별 / 레이어별로 분할이 잘 되어 있어 서로 서로 어떻게 돌아가는지 모르고, 낮은 결합도와 높은 응집도를 제공할 수 있기 때문이라고 생각한다.
- 물론 이번 과제에서 쓰기에는 오버엔지니어링이라고 생각하기도 했고, 단순한 구조에서 과제를 진행하며 아키텍처 개선이 이래서 필요하구나를 느껴보고 싶어서 hint의 구조를 참조해서 진행했다.
- 코드가 충분히 분리되어 많은 파일이 생긴 basic 과제 막바지 쯤, 같은 도메인의 코드끼리 묶여져 있지 않은 것의 불편함을 느꼈다. 그러면서 UIToast를 FSD처럼 폴더 내에서 세그먼트를 분리하고, 캡슐화를 해서 UI만 export해보았다. 해당 커밋
2) 계층 분리의 과정에서 순수함수의 개념과 디자인 패턴이 어떤 도움을 주는가?
기본적으로는 재사용성을 높이고, 테스트를 쉽게 하고, 이름만으로 내부를 추측하게 해 가독성에 도움을 준다.
- 하지만 모두 적절한 추상화가 있어야 가능하다.
const filteredProducts = debouncedSearchTerm
? products.filter(
(product) =>
product.name.toLowerCase().includes(debouncedSearchTerm.toLowerCase()) ||
(product.description && product.description.toLowerCase().includes(debouncedSearchTerm.toLowerCase()))
)
: products;
- 과제를 진행하면서 위의 filteredProducts함수를 어떻게 분리해야할지 몰라 일단 모두 나눠보았었다.
normalizeSearchTerm() // 1. 검색어 정규화
isValidSearchTerm() // 2. 검색어 유효성 체크
matchesProductName() // 3. 상품명 include 여부 확인
matchesProductDescription() // 4. 상품설명 include 여부 확인
matchesProduct() // 5. 상품 필터링 로직
filterProductsBySearchTerm() // 6. 메인 로직
- 하지만 지나친 분리로 오히려 읽기 힘들어지는 과도한 추상화라는 생각이 들어 다시 이를 아래와 같이 수정했다.
normalizeSearchTerm() // 1. 검색어 정규화
matchesProduct() // 2. 검색어 유효성 체크 ~ 4. 상품설명 include 여부 확인
filterProductsBySearchTerm() // 5. 상품 필터링 로직 ~ 6. 메인 로직
- 검색어 정규화 처리는 재사용의 여지를 고려하여 단독으로 분리했다.
- 유효성 체크 ~ 상품설명 include 여부 확인에서는 메인 비즈니스 로직을 과하지 않은 선에서 묶어주고자 했다.
3) 컴포넌트에 대한 계층구조와 상태관리.
컴포넌트 계층 분리는 어떻게 해야 할까? UI 컴포넌트와 Entity 컴포넌트로 나눠서 생각해봤다.
- 원래는 이렇게 생각했다(as-is)
- Entity 컴포넌트: 상태를 import해서 사용하는 컴포넌트
- UI 컴포넌트: 데이터를 사용하지 않는 컴포넌트
지훈님의 피드백: "장바구니 담기 버튼도 sold out 여부에 따라 바뀌는데?"
-> UI 컴포넌트는 데이터를 몰라도 props로 받아서 처리할 수 있어야 한다!
- 바뀐 생각(to-be)
- Entity 컴포넌트: 데이터를 직접 가져와서 사용하는 컴포넌트
- UI 컴포넌트: data를 주입받아서 사용하는 멍청한 컴포넌트
예를 들자면 다음과 같다.
ItemCard (데이터 컴포넌트)
├── 상품 데이터를 직접 가져옴
├── sold out 여부 판단
└── AddToCartButton (UI 컴포넌트)
├── 데이터를 주입받아 처리
└── 멍청해서 시키는 대로만 동작
- 분리해야 하는 이유
- 재사용성: UI 컴포넌트는 멍청해서 재사용이 쉽다
- 가독성 & 유지보수성: 데이터와 엮인 컴포넌트를 데이터 가까이 둘 수 있다
만약 재사용하지 않는 UI 컴포넌트도 분리해야할까? 내 대답은 YES다.
- 가독성 문제: 데이터 컴포넌트를 데이터 옆에 두고 싶다
- 유지보수: 구조 파악이 어려워지고 불필요한 컨텍스트를 읽어야 함
4) 컴포넌트 계층 분리 과정에서 props drilling을 이해하고 개선 방안 찾기
원래 나는 state를 최상단의 각 페이지들에서 내려주는 방식으로 구현하는 걸 선호했다. 그리고 그 방법이 props를 통해서 의존성을 보여주는 방식이라고 생각하고 있었다.
- 이번 과제를 통해서 적절한 props drilling의 기준에 대해서 생각해볼 수 있는 기회가 되었다.
notification과 productForm, couponForm만 Jotai를 사용해 수정하였다.
- notification: 비즈니스 로직과 무관하게 모든 컴포넌트에서 사용할 수 있는 횡단 관심사 컴포넌트이기 때문
- 고로 의존성을 보여줄 수도 없고, 어디서든 재사용이 가능해야 함 -> 전역으로 사용하는게 확실히 이득
- productForm&couponForm: 의존성을 보여줄 수 있기에 굳이 전역으로 관리할 필요는 없음
- 하지만 지나치게 많은 인터페이스가 노출되고 있어 단순화의 필요성을 느낌
- 사실 프로젝트였다면 현 시점에서는 추가적인 depth가 없으니 수정을 하지 않았을 수도 있겠지만, props drilling을 체험하는 과제인 만큼, 조금 적극적으로 jotai를 사용했다.
- 하지만 지나치게 많은 인터페이스가 노출되고 있어 단순화의 필요성을 느낌
내게 기준을 정하라고 한다면, 횡단 관심사이거나 앱의 크기에 비해서 depth가 깊고 인터페이스가 많을 때 전역 상태관리를 고려해볼 것 같다.
코치님의 경우에는 도메인과 관련된 코드가 여러 컴포넌트들에서 사용되는 경우가 많기에 이를 전역으로 관리한다고 하셨다.
2. 과제를 하면서 새로 알게된 점과 좋았던 점
알게된 점
- as-is: 1년 반 전에 함수형 액션/계산 분리 찍먹해봄, 아키텍처 모름(MVC 패턴도 이해못함)
- to-be: 액션/계산/데이터 분리가 왜 중요한지 이해함, 레이어 분리, 기능 분리의 중요성과 아키텍처가 어떻게 구현되는 것인지 깨달음
좋았던 점
1) 다른 사람들과 적극적으로 이야기를 나누면서 진행한 것
- 특히 병준이과 지훈님, 휘린님과 많은 이야기를 나눴다.
- 병준님: 레이어드 아키텍처와 Store/Service 계층 분리 방식 공유
- 지훈님: 산파법을 통한 컴포넌트 계층 학습, 기준 세우기의 중요성
- 휘린님: Hook과 UI 분리, FSD 아키텍처에 대한 친절한 설명
2) AI 적당히 쓰기
- 최근 함께 자라기라는 책을 읽고 있는데, 난이도가 실력보다 너무 높으면 불안함을 느끼고, 반대로 난이도가 지나치게 낮으면 지루함을 느낀다고 하더라.
- 그리고 불안함을 느끼고 있다면 해결방안으로 제시된 것이 AI등을 사용해서 난이도를 낮추는 것이였다.
- 이에 지난 주차 과제에서는 적극적으로 AI를 사용했고, 불안함에서 벗어날 수 있었다. 하지만 반대로 AI를 지나치게 사용하다보니 남는게 없다는 생각이 들었다.
- 이번 주차에서는 AI는 검색을 대신하는 용도와 자동 완성, 그리고 단순 작업을 위주로 사용했다.
- 이렇게 사용하는 동안 느낀 점은, 일단 지난주에 적극적으로 사용했던 agent가 생각보다 굉장히 멍청하다는 것
- 그리고 직접 hook과 model 부분을 작성하면서 프론트엔드의 추상화 벽이 나눠지는 것을 이해할 수 있었다.
- 앞으로도 처음해보는 것을 곧바로 AI로 작업하기 보다는, 일단 직접 해보면서 이해를 하고 난 후 AI로 작업하려고 한다.
'항해 플러스' 카테고리의 다른 글
| 항해 플러스 프론트엔드 7~8주차 회고(테스트 코드와 TDD) (0) | 2025.08.30 |
|---|---|
| 항해 플러스 프론트엔드 6주차 회고(FSD: Feature-Sliced Design) (2) | 2025.08.18 |
| 항해 플러스 프론트엔드 4주차 회고(클린코드와 리팩토링 with 바이브 코딩) (0) | 2025.08.04 |
| 항해 플러스 프론트엔드 2주차 회고(VirtualDOM 만들기) (0) | 2025.07.25 |
| 항해 플러스 프론트엔드 1주차 회고 (0) | 2025.07.25 |