state-management

7 개의 포스트

AI 에이전트가 실제 Stripe (새 탭에서 열림)

최근 LLM은 코드 스니펫 작성을 넘어 파일 단위의 리팩토링까지 수행할 정도로 발전했으나, 실제 소프트웨어 프로젝트를 자율적으로 관리하는 능력은 여전히 검증이 필요한 영역입니다. Stripe는 에이전트가 100%의 정확도를 요구하는 결제 통합 작업을 완수할 수 있는지 확인하기 위해, 실제 운영 환경과 유사한 11개의 벤치마크 환경을 구축하여 성능을 측정했습니다. 연구 결과, 최신 모델들은 UI 탐색 및 복잡한 API 구성에서 기대 이상의 성과를 보였으나, 모호한 상황에서의 의사결정이나 완벽한 엔드 투 엔드 검증에서는 여전히 한계를 드러냈습니다. **Stripe 통합 벤치마크의 설계와 구조** * **다층적 환경 구축**: 실제 비즈니스 시나리오를 반영하여 백엔드 전용 작업, 풀스택 작업, 그리고 특정 기능(Checkout, Billing 등)을 깊게 파고드는 'Gym' 문제 세트로 구성된 11개의 환경을 설계했습니다. * **에이전트 실행 도구**: 모든 모델에 일관된 환경을 제공하기 위해 'goose' 기반의 하네스를 사용했으며, MCP(Model Context Protocol) 서버를 통해 터미널, 브라우저, Stripe 전용 검색 도구에 대한 접근 권한을 부여했습니다. * **결과 검증 시스템(Graders)**: 단순히 코드의 형태를 보는 것이 아니라, API 호출 및 자동화된 UI 테스트를 통해 소프트웨어의 동작을 결정론적으로 검증하며, 생성된 Stripe API 객체의 상태까지 직접 확인하여 정확도를 측정합니다. **에이전트의 뛰어난 실전 적응력과 성과** * **기대 이상의 풀스택 수행 능력**: 모델들은 단순히 코드를 작성하는 데 그치지 않고 브라우저를 직접 조작하며 실시간 이슈를 디버깅하는 능력을 보여주었으며, Claude 4.5와 GPT-5.2 같은 모델들은 특정 영역에서 70~90% 이상의 높은 평균 점수를 기록했습니다. * **복잡한 UI 역공학**: 'Checkout Gym' 과제에서 에이전트들은 기존 UI를 분석하여 제품 ID, 수량, 세금 설정 등 20개 이상의 매개변수를 역으로 추출해 API 호출로 변환하는 복잡한 추론 과정을 성공적으로 수행했습니다. * **자율적인 자기 검증**: 레거시 UI를 새로운 시스템으로 교체하는 작업에서, 에이전트는 명시적인 지시 없이도 브라우저에서 테스트 결제를 진행하고 Link(Stripe의 디지털 지갑)와 같은 실제 결제 수단을 활용해 동작 여부를 스스로 확인했습니다. **한계점과 향후 과제** * **모호성 처리의 부재**: SDK 업그레이드와 같이 모호한 상황이 주어졌을 때, 에이전트들은 존재하지 않는 데이터를 입력하거나 API 오류(400 Error)가 발생해도 이를 논리적으로 해결하지 못하고 정체되는 현상을 보였습니다. * **엔드 투 엔드 검증의 어려움**: 코드를 생성하는 능력과 사람이 수행하는 수준의 엄격한 검증 및 테스트 사이에는 여전히 간극이 존재하며, 특히 장기적인 프로젝트 관리 능력에서는 추가적인 개선이 필요합니다. **실용적인 제언** 에이전트를 실제 개발 워크플로우에 도입하려는 조직은 단순히 코드 생성 엔진으로서의 성능뿐만 아니라, 에이전트가 터미널과 브라우저를 사용하여 자신의 작업을 스스로 검증할 수 있는 환경을 제공하는 데 집중해야 합니다. 또한, API 문서의 명확성과 모호하지 않은 에러 메시지 제공은 에이전트의 자율적 문제 해결 능력을 극대화하는 핵심 요소가 될 것입니다.

서버를 위한 Redux: Node.js 이벤트 소싱 라이브러리 개발기 (새 탭에서 열림)

당근 프론트엔드코어 팀은 복잡해지는 내부 도구의 요구사항을 해결하기 위해 기존 CRUD 방식의 한계를 넘어 '이벤트 소싱' 패턴을 도입했습니다. 이를 위해 프론트엔드 개발자들에게 친숙한 Redux의 구조를 서버 환경으로 옮겨온 TypeScript 기반 라이브러리 'Ventyd'를 직접 개발하여 오픈소스로 공개했습니다. 이 방식은 데이터의 현재 상태뿐만 아니라 모든 변경 이력을 보존함으로써 감사 로그, 롤백, 비즈니스 인사이트 추출을 획기적으로 용이하게 만듭니다. **전통적 CRUD 방식의 한계와 이벤트 소싱의 필요성** * 기존 CRUD(Create, Read, Update, Delete) 방식은 데이터의 '최종 상태'만 저장하기 때문에, 어떤 과정을 거쳐 현재 상태에 이르렀는지에 대한 맥락을 파악하기 어렵습니다. * 승인 절차, 수정 기록 관리, 복잡한 롤백 로직 등을 구현하려면 별도의 히스토리 테이블이나 복잡한 상태 컬럼을 추가해야 하며, 이는 코드의 복잡도를 높이고 유지보수를 어렵게 만듭니다. * 이벤트 소싱은 상태를 직접 수정하는 대신 "상태를 변경시킨 모든 이벤트"를 순차적으로 기록하여, 필요할 때마다 이벤트를 재생(Replay)해 어느 시점의 상태든 완벽하게 재구성할 수 있게 합니다. **Redux 패턴을 통한 이벤트 소싱의 이해** * 이벤트 소싱 아키텍처는 프론트엔드 상태 관리 라이브러리인 Redux와 매우 유사한 구조를 가집니다. * Redux의 'Action'은 이벤트 소싱의 'Event'와 대응되며, 'Reducer'는 이전 상태와 이벤트를 결합하여 새로운 상태를 계산하는 핵심 로직 역할을 수행합니다. * 가장 큰 차이점은 Redux가 브라우저 메모리에서 상태를 관리하는 반면, 서버의 이벤트 소싱은 이 모든 이벤트를 데이터베이스에 영구적으로 저장하여 데이터의 영속성과 신뢰성을 보장한다는 점입니다. **TypeScript 퍼스트 라이브러리: Ventyd** * Ventyd는 TypeScript 환경에서 이벤트 소싱을 더 쉽고 안전하게 구현하기 위해 개발되었으며, 강력한 타입 추론을 제공합니다. * **스키마 정의**: `defineSchema`를 통해 발생 가능한 이벤트의 종류와 최종 상태(State)의 형태를 정의합니다. 이때 Valibot, Zod, TypeBox 등 다양한 검증 라이브러리를 선택하여 사용할 수 있습니다. * **리듀서 구현**: `defineReducer`를 사용해 각 이벤트가 발생했을 때 상태가 어떻게 변화하는지 선언적으로 기술합니다. * **유연한 확장성**: 특정 데이터베이스에 종속되지 않도록 설계되어 있으며, 프론트엔드와 백엔드 엔지니어가 공통의 비즈니스 로직 언어(이벤트)로 소통할 수 있는 환경을 제공합니다. 단순히 현재의 데이터 값만 저장하는 것을 넘어, 서비스의 성장 과정과 모든 변경 맥락을 자산으로 남기고 싶은 팀에게 Ventyd 도입을 추천합니다. 특히 Redux에 익숙한 엔지니어라면 낮은 학습 곡선으로도 서버 사이드에 견고한 이벤트 중심 아키텍처를 구축하고, 복잡한 비즈니스 요구사항을 깔끔하게 정리할 수 있을 것입니다.

AWS Lambda Durable Functions를 사용하여 다단계 (새 탭에서 열림)

AWS Lambda Durable Functions의 출시로 개발자들은 별도의 상태 관리 인프라를 구축하지 않고도 복잡한 다단계 애플리케이션과 AI 워크플로우를 익숙한 Lambda 환경에서 구현할 수 있게 되었습니다. 이 기능은 '체크포인트 및 재실행(Checkpoint and Replay)' 메커니즘을 통해 실행 상태를 자동으로 추적하며, 실행 도중 실패가 발생하더라도 마지막 완료 지점부터 작업을 재개합니다. 특히 대기 상태에서는 컴퓨팅 비용이 발생하지 않으면서도 최대 1년까지 실행을 일시 중단할 수 있어, 결제 처리나 사용자 승인이 필요한 장기 프로세스에 최적화된 솔루션을 제공합니다. ### 지속성 실행(Durable Execution)의 핵심 메커니즘 * **체크포인트 및 재실행:** Durable execution SDK를 사용하면 함수가 실행될 때마다 진행 상황이 자동으로 기록됩니다. 예기치 않은 오류로 실행이 중단되더라도 Lambda는 처음부터 핸들러를 다시 실행하되, 이미 완료된 단계는 스킵하고 마지막 체크포인트부터 비즈니스 로직을 이어갑니다. * **비용 효율적인 대기:** 실행 중 특정 지점에서 실행을 일시 중단하면 컴퓨팅 자원 할당이 해제되어 유휴 비용이 발생하지 않습니다. 이후 정의된 조건이 충족되면 자동으로 실행이 재개됩니다. ### 워크플로우 제어를 위한 주요 프리미티브(Primitives) * **context.step():** 비즈니스 로직에 자동 재시도 및 체크포인트 기능을 추가합니다. 해당 단계가 성공적으로 완료되면 이후 재실행 시 다시 수행되지 않도록 보장합니다. * **context.wait():** 지정된 기간 동안 함수의 실행을 중단합니다. 최대 1년까지 대기가 가능하며, 대기 기간 동안에는 비용이 청구되지 않습니다. * **create_callback():** 외부 API 응답이나 사람의 직접적인 승인과 같은 외부 이벤트를 기다릴 수 있는 콜백을 생성합니다. * **wait_for_condition():** REST API 폴링 등을 통해 특정 조건이 충족될 때까지 실행을 일시 정지합니다. * **parallel() 및 map():** 복잡한 병렬 처리 및 동시성 유스케이스를 지원하여 효율적인 리소스 활용을 돕습니다. ### 서비스 도입 시 고려사항 * **설정 방식:** Durable Functions 기능은 Lambda 함수를 처음 생성하는 단계에서만 활성화할 수 있으며, 기존에 이미 생성된 함수에는 소급 적용이 불가능합니다. * **개발 환경:** 함수 생성 시 'Durable execution' 옵션을 활성화한 후, 코드 내에 오픈 소스로 제공되는 Durable Execution SDK를 포함하여 비즈니스 로직을 작성해야 합니다. * **활용 사례:** 주문 처리 프로세스, AI 에이전트의 다단계 추론 오케스트레이션, 인적 승인이 필요한 결재 시스템 등 상태 유지가 필수적인 워크로드에 강력한 이점을 제공합니다. AWS Lambda Durable Functions는 Step Functions와 같은 외부 오케스트레이션 도구 없이도 코드 수준에서 상태ful한 워크플로우를 관리할 수 있게 해줍니다. 단순한 이벤트 처리를 넘어 긴 호흡의 비즈니스 로직을 관리해야 하는 백엔드 개발자나 AI 엔지니어에게 매우 실용적인 도구가 될 것입니다.

Flutter Riverpod 200% 활용하기 (새 탭에서 열림)

Riverpod은 기존 Provider 라이브러리의 한계를 극복하고 개발자가 더욱 직관적이고 유연하게 상태를 관리할 수 있도록 설계된 Flutter 상태 관리 라이브러리입니다. 서버 데이터 처리 최적화, 자동 생명 주기 관리, 의존성 주입 등 강력한 기능을 기본으로 제공하여 코드의 복잡성을 대폭 낮춰줍니다. 결과적으로 개발 생산성을 높이고, 성능 저하나 디버깅 오류와 같은 상태 관리의 고질적인 문제들을 효과적으로 해결해 줍니다. **서버 데이터 처리 및 상태 관리 최적화** * 서버에서 데이터를 가져올 때 필수적인 로딩, 에러, 데이터 유무 상태를 별도 로직 없이 기본적으로 제공합니다. * API 호출 도중 해당 데이터가 더 이상 필요하지 않게 되면 요청을 자동으로 취소하거나, 데이터의 유효 기간 및 재사용 설정을 손쉽게 관리할 수 있습니다. * '당겨서 새로 고침(pull to refresh)'과 같은 빈번한 UI 패턴을 `ref.refresh` 기능을 통해 간결하게 구현할 수 있어 반복적인 코드 작성을 줄여줍니다. **자유로운 의존성 주입과 자동 생명 주기 관리** * 위젯 계층 구조에 묶이지 않고 어디서든 Provider에 접근할 수 있어, 복잡한 순서나 구조를 신경 쓰지 않고 데이터를 참조할 수 있습니다. * Riverpod이 Provider의 생성과 소멸 시점을 자동으로 관리하므로 메모리 누수 방지와 같은 자원 관리가 용이합니다. * 개발자는 상태를 정의하는 Model과 이를 관리하는 Provider, 데이터를 소비하는 View를 명확히 분리하여 깔끔한 아키텍처를 유지할 수 있습니다. **효율적인 데이터 연동 및 캐시 활용 기법** * **Provider 간 상태 구독:** 필터 조건이 변경되면 이를 구독 중인 목록 Provider가 자동으로 데이터를 새로 불러오도록 설정할 수 있어 수동 리빌드 로직이 필요 없습니다. * **즉각적인 사용자 경험 제공:** 상세 화면 이동 시 목록에서 미리 불러온 데이터를 즉시 노출하고, 동시에 서버에서 추가 정보를 가져오는 방식으로 로딩 지연을 최소화합니다. * **오프라인 데이터 결합:** 로컬 DB 데이터와 서버 데이터를 유연하게 결합하여 네트워크가 불안정한 환경에서도 사용자에게 끊김 없는 인터페이스를 제공할 수 있습니다. * **화면 간 동기화:** 상세 화면에서 수정된 즐겨찾기 상태나 업데이트 내역이 목록 화면에도 즉각 반영되도록 구현하여 앱 전반의 데이터 일관성을 보장합니다. Riverpod은 단순히 상태를 저장하는 도구를 넘어, 비동기 프로그래밍과 의존성 관리를 우아하게 해결해 주는 솔루션입니다. 특히 서버 통신이 많고 화면 간 데이터 동기화가 복잡한 앱을 개발할 때, Riverpod의 선언적인 코드 스타일과 리액티브한 특징을 활용하면 유지 보수성이 뛰어난 코드를 작성할 수 있습니다.

코드 품질 개선 기법 12편: 세트 할인 (새 탭에서 열림)

여러 속성을 개별적으로 변경할 수 있게 허용하는 구조는 상태 간의 불일치를 초래하고 예기치 못한 버그를 유발할 수 있습니다. 이를 해결하기 위해 서로 연관된 상태들을 하나의 객체로 묶어 한 번에 업데이트하도록 인터페이스를 제한하면 시스템의 예측 가능성을 높일 수 있습니다. 결과적으로 코드의 의도가 명확해지고 스레드 안전성 확보와 디버깅이 훨씬 용이해집니다. **개별 속성 변경의 위험성** * **실행 순서 의존성:** 활성화 상태(`isActive`)와 세부 설정(`minImportanceToRecord` 등)이 분리되어 있으면, 설정을 변경하기 전에 활성화를 먼저 시도할 경우 의도치 않게 이전 설정값이 적용되는 문제가 발생합니다. * **상태 초기화의 불일치:** 특정 속성이 변경될 때 내부 카운터가 초기화되어야 함에도 불구하고, 어떤 속성은 초기화를 수행하고 어떤 속성은 누락하는 등의 관리 포인트가 파편화되어 로직이 복잡해집니다. * **경쟁 상태(Race Condition):** 비동기 환경에서 여러 속성을 순차적으로 변경하면, 변경 중간에 다른 로직이 개입하여 불완전한 상태의 데이터를 읽게 될 위험이 있습니다. **데이터 묶음과 인터페이스 제한을 통한 개선** * **객체 캡슐화:** 연관된 설정값들을 `SamplingPolicy`와 같은 별도의 불변(Immutable) 클래스로 묶어 관리함으로써 속성들이 항상 한 세트로 업데이트되도록 강제합니다. * **상태 표현의 최적화:** 별도의 불리언 플래그 대신 상태 객체의 `null` 여부로 활성화 상태를 표현하여, 활성 상태일 때는 반드시 유효한 설정값이 존재함을 보장합니다. * **원자적 업데이트:** `startRecording`과 같이 명시적인 메서드를 통해서만 상태를 변경하게 함으로써 내부 카운터 초기화와 설정 변경이 한 번에(Atomic) 이루어지도록 제어합니다. **실용적인 결론** 단순히 모든 필드에 세터(setter)를 열어두는 것보다, 비즈니스 로직상 함께 움직여야 하는 데이터는 하나의 '상태 객체'로 정의하는 것이 좋습니다. 특히 한 속성의 변화가 다른 속성의 의미나 동작에 영향을 주는 경우에는 인터페이스를 엄격하게 제한하여 잘못된 상태 조합이 발생하는 것을 원천적으로 차단해야 합니다.

코드 품질 개선 기법 11편: 반복되는 호출에 함수도 지친다 (새 탭에서 열림)

객체의 상태를 확인하고 그 결과에 따라 상태를 변경하는 로직은 호출자가 아닌 해당 객체 내부로 캡슐화하는 것이 코드 품질을 높이는 핵심입니다. 이를 통해 외부로 드러나는 상태 전이 로직을 단순화하고, 조건 확인 누락으로 인해 발생할 수 있는 잠재적인 버그를 효과적으로 방지할 수 있습니다. 특히 상태 변경 여부에 따른 후속 작업이 필요할 때는 복잡한 콜백보다 명확한 반환값을 활용하는 것이 코드의 가독성과 유지보수 측면에서 유리합니다. **상태 확인 로직의 내재화** * `if (receiver.a()) { receiver.b() }`와 같이 외부에서 객체의 상태를 묻고 동작을 결정하는 구조는 중복 호출의 번거로움과 확인 누락의 위험을 수반합니다. * 상태를 변경하는 함수(예: `markAsFriend`) 내부에서 직접 조건을 검사(예: `isFriend`)하도록 설계하면, 호출자는 객체의 내부 상태를 일일이 신경 쓰지 않고도 안전하게 기능을 수행할 수 있습니다. * 이러한 방식은 객체 내부의 상태 전이를 단순화하며, '이미 해당 상태인 경우 아무것도 하지 않는다'는 동작을 자연스럽게 보장합니다. * 만약 조건부 동작임을 명시적으로 드러내야 한다면 `markAsFriendIfNotYet`과 같이 함수 이름을 명확하게 짓거나 주석으로 보완하는 방법이 권장됩니다. **콜백 대신 반환값으로 결과 전달** * 상태 변경 성공 여부에 따라 팝업 노출과 같은 후속 작업이 필요할 때, 고차 함수를 통한 콜백(onSucceeded) 방식은 피하는 것이 좋습니다. * 콜백 방식은 의존성 순환을 일으킬 수 있고, 해당 로직이 동기적으로 실행되는지 비동기적으로 실행되는지 호출부에서 파악하기 어렵게 만듭니다. * 대신 `Boolean` 등의 반환값을 활용하면 호출자가 결과에 따라 후속 로직을 직접 제어할 수 있어 코드의 실행 흐름이 명확해집니다. * 이때 함수 이름에서 반환값의 의미가 명확히 드러나지 않는다면 문서화를 통해 보완하고, 호출자가 반환값을 반드시 확인하도록 강제하는 기법을 함께 사용할 수 있습니다. 객체 설계 시 "묻지 말고 시키라(Tell, Don't Ask)"는 원칙을 적용해 보시기 바랍니다. 객체 외부에서 상태를 묻고 판단하기보다, 객체가 스스로 자신의 상태를 확인하고 동작하게 함으로써 더 견고하고 읽기 쉬운 코드를 작성할 수 있습니다.

LiveGraph: Figma의 실시간 (새 탭에서 열림)

피그마(Figma)는 사용자가 디자인 작업 중 데이터를 잃지 않도록 수동 저장 방식에서 벗어나 정교한 자동 저장(Autosave) 시스템을 구축했습니다. 이 시스템은 실시간 협업 환경에서 발생하는 방대한 변경 사항을 성능 저하 없이 안정적으로 기록하기 위해 동기화 엔진(Sync Engine)과 타임라인 기반의 데이터 모델을 결합했습니다. 결과적으로 피그마는 사용자에게 '저장'이라는 행위를 인식하지 못하게 하면서도, 모든 수정 이력을 완벽하게 복구할 수 있는 신뢰성을 제공합니다. ### 동기화 엔진과 변경 사항의 추적 * 피그마의 자동 저장은 단순히 주기적으로 파일을 덮어쓰는 방식이 아니라, 모든 수정 사항을 '뮤테이션(Mutation)' 단위로 기록하는 동기화 엔진을 기반으로 합니다. * 사용자가 레이어를 이동하거나 색상을 변경할 때마다 해당 작업은 즉시 큐에 쌓이며, 엔진은 이를 서버로 전송하여 실시간으로 반영합니다. * 문서 전체를 저장하는 대신 변경된 부분(Delta)만 전송함으로써 대용량 파일에서도 네트워크 부하를 최소화하고 응답성을 유지합니다. ### 스냅샷과 타임라인 모델을 통한 이력 관리 * 무한한 변경 이력을 효율적으로 관리하기 위해 특정 시점의 전체 상태를 저장하는 '스냅샷'과 세부 변경 사항인 '오퍼레이션'을 병행하여 사용합니다. * 사용자가 과거 버전으로 되돌아갈 때 모든 변경 사항을 처음부터 다시 실행하는 대신, 가장 가까운 스냅샷을 불러온 뒤 이후의 변경 사항만 적용하는 방식을 취합니다. * 이는 복구 속도를 획기적으로 높이는 동시에 저장 공간의 효율성을 극대화하는 핵심 아키텍처입니다. ### 오프라인 작업 처리와 데이터 무결성 보장 * 네트워크 연결이 끊긴 상태에서 발생한 작업은 브라우저의 IndexedDB와 같은 로컬 스토리지에 임시로 저장됩니다. * 연결이 복구되면 클라이언트는 서버와 통신하여 로컬에 저장된 변경 사항을 순차적으로 전송하며, 이때 발생할 수 있는 충돌은 서버의 타임스탬프를 기준으로 정교하게 해결됩니다. * 서버는 최종적인 '진실의 원천(Source of Truth)' 역할을 수행하며, 모든 클라이언트가 일관된 문서를 볼 수 있도록 보장합니다. ### 성능 최적화와 사용자 경험의 조화 * 자동 저장 프로세스가 메인 렌더링 스레드를 방해하지 않도록 비동기적으로 처리하여 디자이너가 작업 중 끊김(Lag)을 느끼지 않게 설계했습니다. * 저장되지 않은 변경 사항이 있을 때는 UI를 통해 상태를 알리고, 브라우저 종료 시 경고를 띄우는 등 기술적 장치와 UX 요소를 결합하여 데이터 손실 가능성을 차단합니다. 결국 훌륭한 자동 저장 시스템은 사용자에게 그 존재가 드러나지 않을 때 가장 가치 있게 작용합니다. 기술적 복잡성을 엔진 내부로 캡슐화하고 사용자에게는 '언제나 안전하다'는 신뢰를 주는 것이 피그마 엔지니어링의 핵심 목표이며, 이는 대규모 협업 툴이 지향해야 할 실무적인 표준을 제시합니다.