#전체 글
글 53개
Type Object와 SKU로 자주 바뀌는 상품 조합 다루기
donghyk2-eric: 들어가며개발 도중 기획 쪽에서 상품 구성 정책을 크게 바꾼 적이 있었습니다. 하지만 이때 프론트엔드 코드는 단 한 줄도 건드리지 않았습니다.제가 맡았던 시스템은 조합형 상품 카탈로그였습니다. 고객사마다 팔 수 있는 상품 조합이 다 달랐고, 기획팀의 요청으로 그 조합은 수시로 바뀌었습니다. 하지만 주문 퍼널(상품 선택부터 주문 완료까지 이어지는 화면 흐름)은 모든 고객사가 동일한 코드를 써야만 했죠. 이 경험을 통해 저는 변경 요청이 들어왔을 때 '무엇을 코드에 고정하고, 무엇을 데이터로 관리할지' 다시 나누게 되었습니다. 이 글에서는 자주 바뀌는 정책을 코드의 어느 부분이 알아야 하는지, 그 수정 범위를 줄이기 위해 설계 단계에서 어떤 판단을 내려야 하는지 제 사례를 통해 살펴보려 합니다. 실제 제가 다..
closure of operations(닫힌 연산) FE 인가정책에 적용하기
donghyk2-eric: 들어가며기획팀에서 복잡한 권한 조합 요구사항을 수시로 가져왔지만, 몇 달 동안 판정용 컴포넌트를 새로 만들지 않고 기존 화면 코드의 수정도 최소화할 수 있었습니다. B2B SaaS 서비스를 개발하다 보면 역할(Role), 결제 권한, 요금제 플랜, 기능 플래그(Feature Flag) 등이 얽히면서 인가(Authorization) 조건이 기하급수적으로 복잡해집니다. 처음에는 조건마다 가드 컴포넌트를 만들어 해결하려 하지만, AND와 OR 조건이 뒤섞이기 시작하면 컴포넌트 구조만으로는 감당하기 어려워집니다. 이 글에서는 에릭 에반스의 『도메인 주도 설계(DDD)』에 등장하는 '닫힌 연산(Closure of Operations)' 개념을 활용해, 복잡하게 변하는 조건을 컴포넌트가 아닌 어느 계층에서 조합해야..
데이터 오염을 경계에 격리하기
donghyk2-eric: 들어가며 기능 개발을 하다 보면 이런 공지를 받습니다. "API 응답에 필드 하나 추가했어요. 옵셔널이라 기존 동작엔 영향 없습니다."저희는 파이프라인이 복잡하고 오래 운영된 서비스라 레거시 데이터가 많았고, backfill(나중에 생긴 규칙을 과거 데이터에 채워넣는 DB 작업)보다 API 응답 옵셔널 추가가 합리적인 상황이 자주 나왔어요. 그래서 이런 공지도 자주 받았고, 매번 별생각 없이 넘겼습니다.근데 몇 주 지나서 컴포넌트 코드를 열어보면, 그 영향 없는 필드가 여기저기 분기를 뿌려놓고 있더라고요.옵셔널인데 왜 문제가 생겨요?실제로 동료가 물었던 질문입니다. 옵셔널 추가는 API 스펙 관점에선 하위호환이 맞아요. 문제는 스펙이 아니라 타입이 앱 안에서 하는 일입니다. 서버가 필드를 옵셔널로 추가하..
서버 상태가 바뀌는 스텝은 라우트를 쪼갠다
donghyk2-eric: 들어가며MFA(2차 인증) 설정 화면을 만들던 중, 유저가 새로고침 한 번에 필수 단계인 '복구 코드'를 보지 못하고 홈 화면으로 빠져나가는 버그를 마주했습니다. 스텝을 관리하던 프론트엔드 상태와 서버 상태의 수명이 어긋났기 때문이었습니다. 처음에는 화면이 렌더링될 때 서버 상태를 조회해 특정 스텝으로 강제 이동시키는 '가드(Guard) 로직'으로 때우려 했습니다. 하지만 조건 분기는 금세 복잡해졌고, 예외 케이스는 계속 늘어났습니다. 결국 이 문제를 해결한 방법은 복잡한 상태 계산 코드가 아니라, '서버 상태가 변하는 지점'을 기준으로 라우트(URL)를 분리하는 것이었습니다. 스텝 중간에 서버 상태가 바뀐다면, 프론트엔드 내부 상태로 화면을 넘길 것이 아니라 라우트 경계 자체를 다시 나눠야 합니다. 이..
구현 말고 질문에 이름 붙히기
donghyk2-eric: 들어가며화면을 개발하다 보면 아이템이 특정 그룹에 속하는지 가려내기 위해 item.key.startsWith(...) 같은 접두어 검사를 인라인으로 작성하곤 합니다. 문법적으로는 아무 이상 없는 평범한 한 줄입니다. 하지만 이 한 줄을 쓰기 위해 호출처(사용처)가 "왜 접두어를 비교하면 소속을 알 수 있는가"라는 비즈니스 규칙까지 알고 있어야 한다면, 이미 화면 코드마다 도메인 로직이 새어나가고 있는 상태입니다. 호출처가 도메인 지식을 직접 조립하기 시작하면, 식별자 포맷이나 소속 규칙이 조금만 바뀌어도 그 한 줄을 쓰던 모든 화면 코드를 일일이 찾아 고쳐야 합니다. 이 글에서는 단순해 보이는 문자열 비교 뒤에 어떤 도메인 지식이 숨어 있는지 살펴보고, 이를 감추려 할 때 범용 유틸이나 제네릭이 왜 오히..
토스 Frontend Fundamentals 모의고사 후기 (2회차)
donghyk2-eric: 1회차 후기에 이어서 2회차 모의고사 후기를 쓴다.1회차에서도 강조됐던 내용인데, 예측 가능한 코드를 짜야한다는주제가 이번에도 반복적으로 나왔다사람 뇌는 코드를 "이해"하지 않는다사람 뇌가 코드를 읽는 방식은 생각보다 단순하다. 한 줄 한 줄 의미를 분석하는 게 아니라, 함수명이나 구조를 보고 "이렇게 동작하겠지?"를 먼저 예측한다. 그 예측이 맞으면 넘어가고, 틀리면 그때서야 내부를 파고든다.문제는 예측이 틀렸을 때다. 인지 강도가 급격하게 올라간다. 결국 가독성이라는 건 코드가 얼마나 "뻔하게" 읽히느냐의 문제다.호출처의 관심사를 모르게 추상화한다이번에 가장 신선했던 관점이다.DatePicker 컴포넌트를 하나 만든다고 생각해보자. 이 컴포넌트에 date와 setDate를 prop으로 내려보내면 어떻..
원자적 action으로 훅의 확장성 확보하기
donghyk2-eric: 들어가며vscode의 탭 바처럼 동작하는 대시보드를 만들고 있었습니다. 파일을 열면 탭이 생기고, 클릭하면 전환되고, X로 닫는 그 구조요.대시보드에는 화면 종류가 몇 가지 있습니다. 항상 존재하는 기본 탭인 home이 있고, 새 인사이트를 작성하는 new는 사이드바에서 "새 페이지 만들기"를 누르면 열립니다. 작성이 끝난 개별 인사이트 페이지는 insight-{id}인데, new에서 저장하면 insight-42 같은 탭으로 교체됩니다. 그 밖에 특정 태그에 속한 인사이트 목록 tag-{id}, 그리고 휴지통 trash가 있습니다.이 탭 상태를 어디에 저장할까요? React state에 넣으면 간단하지만 새로고침하면 날아갑니다. 그래서 공유 기능도 넣을 겸 URL query string을 single s..
Branded Type String Key Factory 만들기
donghyk2-eric: 들어가며지난 글에서는 Branded Type을 도입해 개발자가 공통 유틸 함수 사용을 강제하도록 만드는 방법을 다뤘습니다. 지난번과 마찬가지로 도메인이 낯설 수 있으니, 커머스 대시보드 예시를 그대로 가져와서 이야기를 이어가 보겠습니다. 앞선 작업으로 getOrderAnchorId, getRefundAnchorId 같은 개별 함수들을 만들어서 액티비티 타입마다 올바른 ID 포맷을 보장할 수 있게 되었습니다. 그런데 액티비티 타입이 6개가 넘어가면서 함수 개수도 덩달아 늘어나니, 이번엔 '어떤 함수가 있는지 찾기 힘들어지는' 새로운 문제가 생겼습니다. IDE에서 자동완성으로 get만 쳐도 프로젝트 내의 수십 개 함수가 쏟아지는데, 그중에서 앵커 ID(Anchor ID) 관련 함수만 쏙쏙 골라내는 것도 꽤 ..
Branded Type으로 유틸함수 강제하기
donghyk2-eric: 들어가며실무에서 여러 종류의 아이템을 다루다가 겪은 일입니다. 원래 도메인은 유전진단 SaaS 쪽이었지만 너무 낯설 수 있으니, 우리가 흔히 아는 '커머스 대시보드' 예시로 바꿔서 이야기해 보겠습니다. 대시보드에서 특정 활동 내역(activity)을 클릭하면 해당 테이블 로우(row)로 스크롤되는 기능이 있었습니다. URL 해시 기반의 네비게이션인데, 사용자 흐름을 뜯어보면 대략 이렇습니다.테이블 로우에는 id="ORDER----" 같은 속성이 붙어 있습니다. (strategy 영역)액티비티 카드에서 코멘트 버튼을 누르면 "ORDER----"가 포함된 텍스트가 채팅 메시지로 추가됩니다. (message 영역)나중에 채팅창에서 그 메시지의 링크를 누르면 #ORDER---- 해시로 이동하면서 해당 로우로 스..
컴포넌트 분기를 상위로 밀어내기
donghyk2-eric: 들어가며이전 글에서 로직 계층을 내려서 단일 관심사를 챙기는 이야기를 했었습니다. 여러 주제가 섞인 컴포넌트를 분리하고, 각 컴포넌트가 자기 로직만 가지도록 만드는 거였죠.이번엔 반대 방향입니다. 분기를 상위로 올려서 단일 관심사를 챙기는 이야기를 해보겠습니다. 여기서 단일 관심사란 곧 높은 응집도, 그러니까 하나의 컴포넌트가 하나의 맥락에 필요한 것만 모아 둔 상태를 말합니다. 근데 컴포넌트 안에서 강하게 결합된 로직들을 어떻게 분리할 수 있을까요?위에서 풀수록 아래가 단순해집니다React 컴포넌트는 단방향 트리 구조입니다. 데이터와 제어 흐름이 위에서 아래로만 흐르죠. // 여기서 결정하면 // 여기는 단순해진다즉 상위에서 복잡도를 해소할수록 하위가 단순해집니다. Typ..