Todo 앱 사이드 프로젝트를 시작한 지 다섯 달쯤 됐습니다. 그런데 지난달 커밋 로그를 확인해보고 놀랐습니다.

$ git log --oneline --since="2026-07-01" --until="2026-08-01" --author="irus"
a3f291c 필터 UI 초안

7월 한 달 동안 커밋이 하나였습니다. 회사 일이 바빠서였다고 스스로 넘기려 했는데, 8월에 다시 붙잡아보니 문제는 시간이 아니라 다른 데 있었습니다.

문제 상황

"완료된 항목만 보기 필터 추가"라는 이슈를 하나 만들어놓고 몇 주째 손을 못 대고 있었습니다. 주말에 짬이 나서 노트북을 열어도 막상 뭘 해야 할지 감이 안 잡혔습니다. TodoViewModel을 열어봤다가, StateFlow를 어떻게 노출할지 고민하다가, UI 쪽 토글 버튼 디자인이 마음에 안 들어서 다시 닫는 식이었습니다. 30분쯤 이러다 "오늘은 여기까지"하고 덮는 날이 반복됐습니다.

돌이켜보면 매번 "필터 기능 추가"라는 하나의 큰 덩어리를 통째로 끝내려고 했습니다. ViewModel 로직, UI, 상태 저장까지 한 번에 완성해야 커밋할 자격이 있다고 생각한 겁니다.

원인 분석

이슈를 다시 읽어보니 "완료 항목만 보기"라는 한 줄짜리 작업 안에 실제로는 서로 다른 결정 세 개가 섞여 있었습니다.

  1. 필터 상태를 StateFlow<Boolean>으로 둘지, enum(All, ActiveOnly, CompletedOnly)으로 확장 가능하게 둘지
  2. 필터링을 TodoViewModel 안에서 할지, TodoRepository에서 쿼리 단계에 할지
  3. 토글 버튼을 앱바에 둘지, 리스트 상단에 별도 칩으로 둘지

이 세 가지를 동시에 결정하려니 매번 "일단 나중에 생각하자"며 미루게 됐고, 결정을 미루니 코드를 못 쓰고, 코드를 못 쓰니 커밋할 게 없었습니다. 회사 업무에서는 스프린트 단위로 누가 태스크를 쪼개줬는데, 사이드 프로젝트는 저 혼자 기획자이자 개발자다 보니 쪼개는 단계 자체를 건너뛰고 있었던 겁니다.

해결 과정

이슈를 커밋 단위로 다시 쪼갰습니다. 기준은 하나, "이거 하나만 하면 앱이 빌드되고 동작하는가"였습니다.

- [ ] 필터 상태를 enum(FilterType)으로 정의하고 기본값 All로 고정
- [ ] TodoViewModel에 FilterType StateFlow 추가 (UI 연결 없이 로직만)
- [ ] Repository에 필터링 함수 추가, 유닛 테스트 통과 확인
- [ ] UI에 토글 칩 3개 배치 (동작 없이 레이아웃만)
- [ ] 토글 칩 클릭 시 ViewModel 상태 변경 연결

그리고 각 항목을 커밋 하나에 대응시켰습니다.

// commonMain/todo/FilterType.kt
enum class FilterType {
    All, ActiveOnly, CompletedOnly
}
$ git commit -m "FilterType enum 추가, 기본값 All"
[main 7c1d0a2] FilterType enum 추가, 기본값 All
 1 file changed, 3 insertions(+)

이 커밋은 그 자체로는 아무 기능도 안 하지만, 컴파일은 되고 빌드는 통과합니다. 다음 날 이어서 작업할 때 "어디까지 했더라"를 git log만 봐도 바로 알 수 있었습니다.

// commonMain/todo/TodoViewModel.kt
private val _filter = MutableStateFlow(FilterType.All)
val filter: StateFlow<FilterType> = _filter.asStateFlow()

fun setFilter(type: FilterType) {
    _filter.value = type
}
$ git commit -m "ViewModel에 필터 상태 추가 (UI 미연결)"

핵심은 "UI 미연결"이라고 커밋 메시지에 그대로 써도 괜찮다고 스스로 허락한 것이었습니다. 예전에는 어중간한 상태를 커밋하는 게 찜찜해서 미뤘는데, 어차피 로컬 브랜치에서 저 혼자 보는 히스토리이니 완성도보다 "다음에 이어갈 수 있는가"가 더 중요하다고 생각을 바꿨습니다.

한 주 동안 이렇게 다섯 번에 나눠 커밋하고 나니 필터 기능이 끝나 있었습니다.

$ git log --oneline --since="1 week ago"
e4a8f31 토글 칩 클릭 시 필터 적용 연결
b291cc0 토글 칩 UI 배치 (레이아웃만)
9d0f421 Repository 필터링 함수 + 유닛 테스트
7c1d0a2 ViewModel에 필터 상태 추가 (UI 미연결)
3a5e881 FilterType enum 추가, 기본값 All

결론

사이드 프로젝트가 멈췄던 이유는 시간 부족이 아니라 작업 단위가 너무 컸기 때문이었습니다. "빌드되고 동작하는 최소 단위"로 이슈를 쪼개고, 미완성 상태라도 커밋 메시지에 정직하게 남기니 다시 이어가는 부담이 확 줄었습니다. 회사 업무에서는 당연하게 여기던 태스크 쪼개기가 혼자 하는 프로젝트에서는 오히려 생략하기 쉬운 단계라는 걸 이번에 알게 됐습니다. 다음 기능부터도 이슈를 만들 때 체크리스트부터 먼저 쓰기로 했습니다.