OurCar 구축: UX, 상태 관리, 그리고 거절의 기술

가족과 차량을 공유하는 것은 연료통이 비워질 때까지는 간단해 보입니다. Mendel Greenberg에게 연료 비용을 나누고 일정 조율의 마찰은 기술 프로젝트의 촉매제가 되었습니다: OurCar. 가스 요금에 대한 '천 가지 작은 상처'를 피하려는 시도로 시작된 것이 결국 크로스 플랫폼 개발, 사용자 경험(UX) 디자인, 그리고 틈새 애플리케이션 유지 관리의 현실에 대한 깊은 탐구로 발전했습니다.

문제: 조정 마찰

핵심 문제는 전형적인 조정 실패였습니다. 가족 구성원들이 장거리 여행 후에 연료통을 채우려 했지만, 작은 심부름 때문에 연료가 서서히 감소했습니다. 결국 연료가 완전히 비었을 때 차를 운전한 사람에게 불공평한 부담이 지워졌습니다.

Greenberg의 목표는 "WhatsApp 그룹보다 차를 공유하기에 더 나은" 무언가를 만드는 것이었습니다. 이를 위해 세 가지 주요 기능이 필요했습니다:

  1. 위치 추적: 차가 사용 가능할 때 어디에 주차되어 있는지 파악합니다.
  2. 상태 모니터링: 누가 언제 차를 사용했는지 추적합니다.
  3. 연료 회계: 연료 사용량을 모니터링하여 누가 충전해야 하는지 판단합니다.

기술 스택

프로토타입에서 프로덕션으로 빠르게 이동하기 위해 Greenberg는 간결한 스택을 선택했습니다:

  • 프론트엔드: Flutter - 크로스 플랫폼 도달을 위해.
  • 백엔드: Pocketbase - 간소화된 백엔드-as-a-service 경험을 위해.
  • 상태 관리: Riverpod - 여러 페이지 간 데이터 동기화를 위해.
  • 네비게이션: Auto Route - 딥링크와 복잡한 라우팅을 처리하기 위해.

Claude Code와 같은 에이전트 기반 개발 도구는 문제 해결 및 부가 기능(예: 계정 삭제 포털) 구축에 사용되었지만, 핵심 아키텍처는 시스템에 대한 깊은 이해를 보장하기 위해 수동으로 처리되었습니다.

"네이티브" 디자인의 도전

가장 큰 장애물 중 하나는 iOS와 Android 모두에서 "네이티브한 느낌"을 구현하는 것이었습니다. Flutter는 Material(Android)과 Cupertino(iOS) 디자인 시스템을 위한 위젯을 제공하지만, 자동으로 전환되지는 않습니다.

이를 해결하기 위해 Greenberg는 flutter_platform_widgets 패키지를 사용했지만, 레이아웃 관용구가 플랫폼마다 크게 다르며, 이를 처리하기 위해 종종 "스파게티 코드"가 발생한다고 언급했습니다. 그는 UI를 설계하는 가장 효과적인 방법은 이미 크로스 플랫폼 균형을 마스터한 앱, 특히 WhatsApp을 참고하는 것이라고 발견했습니다.

"표준 관용구를 따르면 사람들은 갑자기 모든 것이 어떻게 작동하는지 이해하게 됩니다. 왜냐하면 그들은 이전에 그와 같은 상호작용을 여러 번 경험했기 때문입니다."

범위 확장과 거절의 기술

앱이 가족 구성원에게 도달하면서 요청이 쏟아졌습니다: 정비 일정, 주행 거리계 스캔을 위한 컴퓨터 비전, 실시간 GPS 추적 등. 이는 "반-기능"에 대한 중요한 의사결정 과정을 강요했습니다.

예를 들어 GPS 추적은 배터리 소모와 프라이버시 두 가지 이유로 거부되었습니다. 앱은 차가 어디에 주차되어 있는지는 알아야 하지만, 모든 움직임을 추적하면 사용자의 생활에 대한 사적인 세부 정보가 드러날 수 있습니다. 이러한 기능을 반-기능으로 식별함으로써 개발자는 사용자 신뢰와 기기 성능을 손상시키지 않으면서 앱의 핵심 유용성을 유지했습니다.

엔지니어링 함정과 반복

상태와 성능

초기 버전은 "jank"와 동기화 문제를 겪었습니다. 개발자는 "mega-widgets"를 만들면 과도한 재그리기가 발생한다는 것을 발견했는데, 부모 위젯의 작은 상태 변화가 모든 하위 위젯의 재그리기를 유발했습니다. 해결책은 더 작고 관리하기 쉬운 위젯으로, 독립된 상태를 가진 위젯으로 철저히 리팩터링하는 것이었습니다.

상태 머신 접근법

초기에 연료 로그와 여행 로그가 별개였으며, 이는 사용자에게 혼란을 주었습니다. Greenberg는 상태 머신으로 작동하는 단일 통합 타임라인으로 전환했습니다. 논리는 이진화되었습니다: 차는 반환될 경우에만 빌릴 수 있고, 빌린 경우에만 반환될 수 있습니다.

이를 되돌아보며 그는 논리가 데이터 저장 방식과 독립적인 보다 "추상적인" 상태 머신이 있었다면 더 나은 단위 테스트와 버그 감소를 가능하게 했을 것이라고 언급했습니다.

커뮤니티 관점: 과도한 엔지니어링 vs. 유용성

이 프로젝트는 Hacker News에서 이러한 앱의 필요성에 대한 논쟁을 촉발했습니다. 일부 비평가들은 연필과 메모장 혹은 간단한 PWA(Progressive Web App)만으로도 충분했으며, 이 프로젝트를 "과도한 엔지니어링"의 사례라고 주장했습니다.

하지만 다른 사람들은 전용 앱의 가치는 단순히 데이터 기록이 아니라 그것이 강제하는 워크플로우에 있다고 반박했습니다. 한 댓글자는 다음과 같이 언급했습니다:

"모두가 실제로 열어보는 거친 UI가 한 사람이 관리하는 깔끔한 종이 로그보다 더 뛰어날 수 있습니다... 목적에 맞게 만든 도우미는 기록뿐만 아니라 워크플로우 자체가 될 수 있습니다."

다른 기술적 제안으로는 연료 및 주행 거리계 읽기를 자동화하기 위해 OBD-II 블루투스 동글을 통합하는 것이 있었으며, 이는 수동 데이터 입력의 마찰을 완전히 제거합니다.

결론: 틈새 앱의 수명 주기

궁극적으로 OurCar는 "영원한 알파" 상태를 유지했습니다. 가족 구성원들이 떠나면서 앱에 대한 즉각적인 필요가 사라졌고, 추가 개발에 대한 열정도 식었습니다. 그럼에도 불구하고 이 프로젝트는 전체 소프트웨어 개발 라이프사이클을 포괄하는 연습이었습니다: 문제점을 식별하고 프로토타입을 만들며, 앱 스토어 인증의 복잡성을 탐색하고 반복적인 UX 디자인을 수행하는 과정까지.

Sources