
Claude Code로 Skills를 정비하고, Flutter 앱을 BLoC화하여 머지하기까지
요약
Claude Code의 Skills와 AGENTS.md 규약을 활용하여 Flutter 앱의 상태 관리 패턴을 setState에서 BLoC으로 전환하고, GitHub Flow에 따라 PR 생성 및 Squash merge까지 완료하는 과정을 다룹니다.
핵심 포인트
- AGENTS.md와 Skills를 통한 AI 에이전트용 개발 규약 동기화
- Flutter 앱의 상태 관리를 BLoC 패턴으로 리팩토링
- 단방향 데이터 흐름(UI → Event → State) 구현
- 규약에 따른 브랜치 전략 및 Squash merge 워크플로우 적용
실제로 진행한 일련의 작업을 기사로 정리합니다.
「AI 에이전트용 규칙(AGENTS.md / Skills)을 별도 리포지토리에서 이식하고, 그 규약에 따라 앱을 BLoC으로 구현하여, PR을 생성하고 머지하는」 것까지의 흐름입니다.
TL;DR
- 별도 리포지토리
flutter-test-app의 AGENTS.md와 Skills를 동일한 구성으로 이 리포지토리에 동기화했다. - 동기화한 bloc / bloc-state 스킬의 규약에 따라, 기본
setState카운터를 **BLoC 패턴 (BLoC Pattern)**으로 이행했다. - 하나의 브랜치로 모아서 커밋 → 푸시 → PR #1 생성 → squash merge로
main에 반영했다.
1. 개발 플로우 전체 (이번에 수행한 작업)
포인트는, AGENTS.md에 작성된 브랜치 전략 (GitHub Flow) 및 **「Squash merge로 main에」**라는 규약을 실제 작업에서도 그대로 답습하고 있다는 점입니다.
구현 → 커밋 → 머지가 일관되게 연결되어 있습니다.
2. 이행 전후의 아키텍처
setState 버전
Before: 상태(_counter)와 그 업데이트 로직이 Widget 내에 닫혀 있어, UI와 상태 관리(State Management)가 밀결합되어 있었습니다.
After: BLoC 버전
- 상태의 유지·업데이트는 Bloc이 담당 (Widget은 상태를 가지지 않음).
- UI는
add를 직접 호출하지 않고, Bloc이 공개하는 **공개 메서드 (Public Method)**를 호출한다.increment()(add를 래핑한 입구). CounterState는Equatable에 의한 불변 클래스 (Immutable Class).BlocBuilder가 상태 변화를 구독하여 재그리기를 수행한다.
3. 클래스 다이어그램
BLoC을 구성하는 클래스 관계입니다. Event / State는 모두 Equatable을 상속하며, CounterBloc은 Bloc<CounterEvent, CounterState>를 상속합니다.
CounterEvent는sealed기저 클래스이며,CounterIncremented가 그 구체 이벤트(Concrete Event)이다.CounterState는count를 가진 불변 클래스 (props로 값 비교).CounterBloc은 Event를 받아 State를emit한다. 공개 메서드 (add를 래핑한 입구)는increment(), 핸들러는_onIncremented이다.
4. 블록 구성도 (위젯 트리)
앱 기동 시의 위젯 조립과 CounterBloc의 공급 범위입니다.
BlocProvider가CounterPage의 서브트리로CounterBloc을 공급한다.BlocBuilder는context를 통해 Bloc을 구독하고,state.count를 그린다.FloatingActionButton은context.read<CounterBloc>().increment()로 공개 메서드 (add를 래핑한 입구)를 호출한다.
5. 런타임 데이터 플로우 (버튼을 눌렀을 때)
UI → 공개 메서드 → Event → 핸들러 → emit(State) → BlocBuilder 재그리기라는 단방향 흐름으로 되어 있습니다.
6. 동기화한 Skills와 AGENTS.md
| 파일 | 역할 |
|---|---|
AGENTS.md | 에이전트가 항상 따라야 하는 기본 규칙 (개요 / 아키텍처 / 규약 / 브랜치 전략) |
.claude/skills/bloc/SKILL.md | Event + State + Bloc를 1개 파일에 만드는 규약 |
.claude/skills/bloc-state/SKILL.md | Equatable한 불변 (Immutable) State 규약 |
.claude/skills/bloc-test/SKILL.md | bloc_test를 이용한 테스트 작성법 |
.claude/skills/test-workflow/SKILL.md | 설계서 → 구현 → 검증 → 리뷰 → CI → 머지(Merge) 품질 워크플로우 |
이 파일들은 Claude Code가 인식할 수 있는 .claude/skills/<name>/SKILL.md 구성으로 배치되어 있습니다.
"요청에 대해 어떤 스킬을 사용할 것인가"를 에이전트가 자동으로 선택하고, 그 규약에 따라 구현하도록 하는 흐름을 지원합니다.
7. 구현의 요점 (규약 준수)
lib/counter/counter_bloc.dart에 Event / State / Bloc를 1개 파일로 집약했습니다.
// ===== Event =====
sealed class CounterEvent extends Equatable {
const CounterEvent();
...
규약에 따라 의식한 점:
- 1개 파일 집약: Event를 별도 파일로 분할하지 않음 / 파사드 (Facade)를 만들지 않음.
- 메서드 참조로 등록:
on<...>(_onIncremented)(인라인 람다를 사용하지 않음). - 공개 메서드 (Public Method): UI는
add를 래핑한 입구인add를 직접 쓰지 않고increment()를 호출함. - 사용하지 않는 것을 가져오지 않음: UI가 가산(Increment)만 수행하므로
decrement()는 구현하지 않음.
8. 배운 점
- AGENTS.md / Skills는 "구현의 지도": 규칙을 미리 정비해 두면, 후속 구현이 일관된 형태로 수렴한다.
- 문서와 구현이 동일한 규약으로 일치: "Squash merge로 main에 머지"와 같은 운영 규칙까지 실제 작업에 반영할 수 있었다.
- 작게 나누어 진행하기: 동기화 → 구현 → 머지를 단계적으로 진행. 각 단계에서 의도를 확인하며 나아갈 수 있었다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기