Flutter + Node.js(Typescript)로 포스기 앱 만들기
일일호프에서 사용된 포스기 앱을 만들어갔던 과정과 기술 스택을 가볍게 다룹니다. 기획적인 설계와 성과에 대해 회고합니다.
개요
2023년 말에 간단한 포스기 앱을 만들었고, 그 경험을 에세이처럼 쓰는 글입니다. 기획적인 것들이나 실제 사용됐을 때의 이야기가 주입니다. 기술적인 이야기는 자세히 작성한 각각의 글에서 다루도록 하겠습니다.
포스기란 결제/매출 시스템인 POS(Point Of Sale System)가 설치된 컴퓨터를 의미한다고 합니다. POS 는 완전히 영어인데 여기에 한국어인 "기"가 들어가니까 왠지 모를 친숙함이 느껴집니다. 마치 드라이기처럼요…
서막
2023년 후반에 참여했던 (지금은 거의 참여하지 못하는… ㅠㅠ) 한 봉사 단체가 있었습니다. 거기서는 활동비를 충당하기 위해 일년에 한 번 일일호프를 주최했습니다. (대신 회비를 받지 않습니다). 지인들을 초대하고 생긴 수익을 활동비로 썼죠. 일년에 한 번인 만큼 중요한 프로젝트였습니다. 주점을 통째로 빌리고 메뉴를 정하고 재료를 사고 정산도 하고 모두 직접 운영해야 하는 등 규모도 만만찮은 프로젝트.
공교롭게도 봉사 단체에 개발자가 몇몇 있었습니다. 아이디어가 나왔습니다. 실제 운영할 때도 쓸 만한 포스기 앱을 만들자. 주문도 받고 주방에서도 편하고 정산할 때도 좋은 그런 앱! 이야기는 그렇게 시작되었고, 제가 합류한 시점은 완전 초반이었습니다. 딱히 결정된 게 없었어요. 다들 직장인이다 보니까 모여서 와글와글 프로젝트하는 20대의 파릇파릇한 느낌도 없었죠. 중요한 건 노력을 얼마나 들이지 않느냐 였습니다. 가장 적은 노력을 해서 가장 큰 효과를 봐야 하는 포스기 앱인 것이죠.
기술 스택은 일찌감치 결정되었습니다. 프론트는 Flutter, 백엔드는 Node.js.
정해진 것들이 크게 없다고 했었죠. 불확실한 것들을 안고 가도 어떻게든 되겠지 하는 아저씨스러운 마음이 있었습니다. 다들 개발 일 해왔고, '될 때엔 된다'는 건 모두 체득된 상태였죠... 이런 마음가짐이 재밌긴 합니다.ㅋㅋ 하여튼 당일 사용할 기기도 마땅히 정해질 기미가 보이지 않았습니다. 화면이 큰 태블릿 계열이긴 하겠지만 안드로이드 계열일 수도 있고 아이패드일 수도 있었어요. 빌드가 뜻대로 안되는 상황이 올 수도 있으니 그럴 땐 웹으로 또 급하게 돌려야 할 수도 있었습니다. 그래서 네이티브 개발은 애초부터 선택지에 없었고 남은 건 크로스 플랫폼 빌드를 할 수 있는 것. 2023년 시점에서 핫한 Flutter 와 React Native.
이런 프레임워크가 각광받는 이유 중 하나는 높은 생산성입니다. React Native 는 사실상 웹에서 많이 쓰이는 React 기반이라 개발자들이 이미 친숙하죠. Flutter 또한 빵빵한 구글이 팍팍 지원해주기도 하고 개발자들이 좋아하는 것들을 모아둔 느낌이었습니다. 크로스 플랫폼이라고 해서 거의 아무도 안쓰는 Qt를 사용할 것도 아니니깐… 뭘 사용해도 생산성이 적당히 나오겠다는 기대 + 어차피 React 란 회사에서도 많이 쓰는데, 이왕 새롭게 할 거 조금 공부하면서 쓰면 좋으니까 Flutter 로 가볍게 결정되었습니다.
백엔드도 필요하죠. Flutter 는 프론트니까 백을 뭘로 하지? 여기서는 그냥 익숙한 걸로 선택했습니다. Node.js. 프로젝트에 새로운 거 하나만 있으면 충분하죠.
전체 비율로 따지면… 음, 익숙한 것 7-80% 에 새롭게 배우는 것 2-30% 정도면 좋지 않을까 해요.
배포는 cloudtype 이라는 서비스를 이용하기로 했습니다. 2024년 시점에서는 돈을 착실히 내야 사용할 수 있는 서비스지만 2023년까지만 해도 베타 서비스라서 성능 좋은 DB 조차 공짜로(!) 쓸 수 있었어요. Vercel 처럼 배포 단위를 GitHub 리포지토리 단위로 가져갈 수 있었고 배포 명령어나 환경변수 등을 지정하기도 편했습니다.
우리에게 중요한 건 다음과 같았습니다. ✅
- 요구사항 만족.
- 당일에만 안정적으로 잘 동작해야 한다.
신경을 안써도 될 건 다음과 같았구요. ❌
- 보안
- 지속적 배포 (운영과 개발이 동시에 이루어질 일이 없음)
API 서버와 DB는 cloudtype 에 띄우고 Flutter 는 그냥 로컬 빌드하여 아이패드에 설치해서 보여주는 식으로 하기로 했습니다. 배포하는 게 전혀 복잡하지 않아서 Flutter는 무조건 배포된 API 서버를 바라보도록 했습니다. 아, DB나 그런건 테스트용과 운영용을 나누는 것도 하지 않았습니다. 심지어 DB Endpoint 도 그냥 리포지토리 프라이빗하게 해서 저장소에 다 때려박았습니다.
API 서버
API 서버 구성은 제가 좀 주도했습니다. 다른 사람이 코드 읽었을 때 "이거 왜 이렇게 복잡해" 정도만 아니면 아무렴 괜찮지 않을까요?
웹서버는 최대한 간단하게 구성하려고 노력했습니다.
- tsup: esbuild 기반 번들링해주는 툴입니다. 개발 서버를 띄울 때 tsc 나 ts-node-dev 보다 훨씬 가볍고 쓰기도 편합니다. 또 전반적으로 쉬워서 간단하게 시작하기도 좋구요.
- itty-router: Express 보다 훨씬 가볍고 모던한 라우터입니다.
- logtail + pino 로 로깅
더 자세한 내용은 tsup으로 간단하게 타입스크립트 기반 Node.js 서버 띄우기에서 확인할 수 있습니다. (WIP)
그 외에 신경쓴 부분은 다음과 같습니다.
- prisma: Node.js 에서 유명한 ORM 라이브러리 입니다. 여기에 더해 vitest를 활용하여 실제 DB를 돌리는 테스트도 진행했습니다. 더 자세한 내용은 prisma로 DB를 관리하고 테스트까지 자동화해보기에서 확인할 수 있습니다. (WIP)
- async-mutex: 동시에 상태를 변경하는 요청이 여러 개 들어왔을 때 순차적으로 처리하기 위해 Mutex 를 활용했습니다. 더 자세한 내용은 async-mutex로 요청에 대한 동시성 제어하기에서 확인할 수 있습니다. (WIP)
푸근하다
아저씨스럽다는 느낌이 뭔가 몽글몽글 떠오르지만 대놓고 그런 단어를 쓰자니 뭔가 부정적인 어감인 것 같네요. 그래서 그냥 푸근하다 정도로 표현하겠습니다. 이 푸근한 느낌을 정리하자면 음... 다음과 같을까요?
- 이렇게 해도 저렇게 해도 상관없다. (뭔가 하고 싶은 쪽이 좀 더 주도권을 가진다)
- 그 때 상황에 따라 움직인다. (특정한 기능이 개발이 덜 된다면 그냥 사용하지 않는다)
- 최악의 상황도 별 거 없다. 앱이 너무 불안정하다면 그냥 안써도 된다.
뭔가를 해야 한다!
라는 게 없는 것이죠. 어차피 봉사활동의 일부이기도 하고 이걸로 인해 뭔가 큰 손해를 입거나 큰 이익을 얻는 것도 아니어서 부담이 다들 없었던 거 같아요. 장점은 분위기가 자유롭다는 것. 단점은 일정에 대한 의지를 가진 사람이 아무도 없다는 것... 그냥 하루 밤 새서 만들어도 충분하다는 느낌! ㅎㅎ... 그런데 전 밤 못새는 체질이라 미리미리 좀 했어요.
이렇게 자유로운 분위기일 때의 장점은 상상의 나래를 마음껏 펼칠 수 있다는 것! 그리고 일정에 막 쫓기지 않아도 된다는 것. 그냥 취미로 개발하는 느낌이어서 좋았네요. 새로운 Flutter 라는 것도 써보고.
API 서버를 하면서 느낀 점
왠만하면 그냥 Express 씁시다. 좀 투박한 느낌이긴 하지만 커뮤니티의 도움을 쉽게 받을 수 있다는 것이 무시못할 장점입니다. 문제에 부딪쳤을 때 해법이 아주 많으니까요.
주문이 들어왔을 때 알림을 효율적으로 받기 위해서 server-sent events (sse)라는 기술을 써보고 싶었는데, 일반적인 HTTP 요청-응답과 다른 방식으로 데이터를 다뤄줘야 하다 보니 일반적인 케이스만 다루는 서버/클라이언트 라이브러리로선 한계가 있었습니다. itty-router 에서도 자료가 적었구요. 시간을 들여 연구를 더 할 수 있었지만 그러지 못했네요.
Flutter
2023년은 AI가 대두된 해였습니다. ChatGPT가 엄청나게 큰 화제였죠. 저는 Copilot도 굉장한 도구라고 생각해요. 특히 이번 Flutter 프로젝트를 진행하면서 도움을 크게 받았습니다.
어떤 프레임워크든지 그 철학을 이해하는 건 중요합니다. Flutter의 철학, 구글과 관련된 뒷배경, 어떤 방식으로 컴파일을 거쳐 각 플랫폼에 맞는 바이너리를 생산하는지, 렌더링 모델이 어떻게 되는지, 어떻게 리렌더링을 관리하는지에 대한 이해는 코파일럿이 도와줄 수 없습니다. (ChatGPT엔 물어볼 수 있겠죠)
이런 철학을 가볍게나마 이해한 뒤 코드를 짤 때의 코파일럿의 도움은 엄청난 효율을 가져옵니다. 왜 코파일럿이 그런 식으로 제안하는지 이해할 수 있고, 내가 이해한 바와 다르게 코드를 제안해왔을 때 그 차이가 무엇일지 다시 검색하고 일반론과 나만의 이론을 비교하면서 학습하기가 좋습니다. Flutter와 웹 브라우저의 렌더링 방식을 비교할 수도 있구요.
Flutter의 가벼운 특징을 이야기하자면, 구글이 팍팍 밀어주기 때문에 관련 생태계와 연동하기 쉽다는 것과 별도 컴파일 과정을 통해 성능을 잡았다는 것 정도로 이해했습니다. 다만 제게 좀 낯설었던 것도 있었어요. 테마가 처음부터 안드로이드와 iOS 스타일 두 개로 나뉘어져 있고 컴포넌트도 테마별로 아예 구분되어 있었다는 것. 웹앱의 굉장히 열려있는 스타일에 익숙해져 있다가 플러터의 꽉 짜여진 테마 속에서 놀려고 하니까 살짝 갑갑한 느낌이 들긴 했습니다.
예를 들어 터치했을 때의 효과를 구글식 Ripple 효과가 아니라 나만의 효과를 주고 싶다고 했을 때, 어디서부터 어떻게 건드려야 할지 전혀 감이 안온다는 느낌쓰... 그렇게 정말 하고 싶다면 렌더링과 관련하여 열심히 공부해야겠죠?
기술적인 특징은, 모든 것은 위젯으로 이루어져 있고 Stateless 한 것과 State한 것이 구분되어져 있고, build
함수가 굉장히 중요한 역할을 하고... (마치 class 방식의 React 에서 render
함수가 그러했듯이.)
레이아웃을 잡는 방식도 인상깊었습니다. Column, Row, Container, SizedBox, Expanded, Padding, Flexible 등등의 위젯으로 크기와 영역을 잡고 무제한 width/height 라는 개념도 있고 했어요. 만약 컨테이너에서 "나의 크기는 자식의 크기에 따른다" 인 상태 + 자식에서 "나는 크기가 무한함"이 충돌했을 때 화면에서 이거 문제있고 깨진다! 라는 표시도 명확히 해줘서 따라가기가 편했던 느낌이었어요.
Flutter 개발할 땐 IntelliJ를 사용했는데요, 여기서 제안하는 수정 방식들도 굉장히 많이 도움을 받았습니다. 예를 들어 const
를 적소에 사용하여 렌더링과 관련된 최적화를 한다든지... 특정 위젯을 Sized 등의 위젯으로 감싸려고 할 때 편한 방법을 제공해준다든지... VSCode 와는 뭔가 느낌이 다른 편안함이 있었어요. 커밋 때리거나 터미널 열땐 좀 불편한 부분들이 있지만 그건 제가 IntelliJ 식으로 잘 못쓰는 거라 생각할래요...
성과
단체의 자료라 엄청나게 공개하기는 어렵네요.
- 매출 약 750만원
- 최대 1시간 138건 주문 (음료(주류)와 요리 둘 다 합쳐서) = 1분에 두 건 정도.
- 사용한 기기는 세 대 (주방, 카운터, 생맥주기계), 기기 하나 당 3초에 한번 폴링 방식으로 정보를 가져옴. 대략 1초에 1번의 요청 처리
- 오류 1건 (다른 개발자 분이 DB 들어가서 직접 값 수정)
매출이 저정도로 나왔다고 했을 때 저는 좀 놀랐습니다. 하루인데 750만원이라... 꽤 잘 팔렸잖아... 저는 주방에서 열심히 닭꼬치나 굽고 해서 홀 상황이 어떻게 돌아가는지 잘 몰랐는데, 성황리에 잘 마무리된 것 같습니다. 그거랑 별개로 사람들 개개인의 노력이 정말 많이 들어갔다는 건 비밀.
오류가 한 건 있었습니다. 데이터가 꼬여서 서버 쪽의 validation 때문에 이러지도 저러지도 못하는 상황이었다고 합니다. 저도 제대로 확인을 못해서 좀 아쉽네요. 그것과 관련하여 에러 로그가 3건 정도 찍힌 게 있었는데, logtail 에서 보관하는 로그가 그렇게 빨리 사라질 줄 몰랐습니다. 미리 export 해둘 걸... 결국 그 에러의 원인 파악은 영영 못하는 걸로... 만약 다음 번에 한다면 e2e 테스트를 많이 추가하여 약간의 부하 테스트겸 돌려볼 수도 있을 것 같아요.
앱이 터질 정도로 심각한 문제는 없었습니다. 솔직히 안터진 게 기적이라고 생각합니다.
앱을 안 쓰는 것보다 앱을 써서 더 좋았나? - 즉 프로덕트의 측면으로서 좋았나? 라는 질문에 대해 저는 좋았다고 자평합니다. 제가 생각하는 가장 큰 성과 두 가지를 꼽으면 다음과 같습니다.
- 기존에는 수기로 작성한 빌지에만 의존했기 때문에 데이터 관리가 힘들었음. 그러나 앱으로 운영함으로써 정보를 데이터화하여 시간과 노력을 많이 세이브할 수 있었음. 일일호프 성과 산출도 비교적 쉽게 이루어짐.
- 카운터에서 주문을 받을 때부터 요리가 시작될 때까지 흐름이 스무스했음. 주문이 누락되거나 잘못 들어간 케이스가 없었음.
기획적인 것들은 후술하겠습니다.
기획적인 것들
포스기 앱의 목적은 사람이 손으로 하던 일을 좀 더 손쉽게 하고자 하는 데에 있으니, 앱의 기획도 거기에 맞춰서 가는 건 당연하겠죠. 필수로 처리해야 하는 일들은 무엇인지, 어디서 불편함을 느꼈는지, 엣지 케이스는 어떠하고 그걸 손쉽게 풀어내는 방법은 무엇일지 정도로 생각했습니다.
카드 결제를 넣는 건 생각도 안했어요. 정식 사업자를 내고 하는 것도 아니고 대학생 시절 주점을 여는 것과 비슷한 느낌입니다. 주문할 때 빌지를 작성하고 나중에 카운터에서 계좌이체가 확인되면 결제완료 처리를 하는 식입니다.
이 앱을 이용하는 주체는 크게 두 가지로 나뉩니다. 바로 카운터와 주방입니다.
먼저 카운터에서는 다음과 같은 일을 수월하게 처리할 수 있어야 합니다.
- 테이블 별 주문 추가 (+ 취소)
- 결제 처리 (현금 및 쿠폰)
좌측 테이블 리스트에서 확인할 수 있는 정보는 다음과 같습니다.
- 테이블 상태 (빨강, 주황, 초록)
- 빨강: 대기 중인 주문이 하나라도 있을 시
- 주황: 대기 중인 주문이 하나도 없고, 요리 중인 주문이 하나라도 있을 시
- 초록: 모든 주문이 요리가 완료되었을 시
- 테이블의 최초 주문 시간
- 간단한 주문 목록
- 총액
여기서는 적은 정보로 최대한의 효과를 내야 합니다.
- 특정 테이블의 주문 활성화 정도를 파악: 테이블의 최초 주문 시간과 총액의 비율을 어림잡아 계산할 수 있습니다.
- 전체적으로 주문이 밀리는지 등을 파악: 테이블의 주문 상태를 색으로 요약해뒀기 때문에, 대략 초록색이 많으면 주문이 원활하게 처리되고 있음을 뜻하고 주황 및 빨강이 많으면 주문이 밀리고 있음을 보일 수 있습니다.
그런데 말입니다, 사실 위 목적은 유용하지 않았던 거 같습니다. 현황 파악 목적 보다는 빠르게 주문을 넣고 결제 완료 처리를 안정적으로 하는 것이 더 중요한 포인트였습니다.
테이블 배치와 관련하여 이야기를 하자면, 단순히 6열의 표로 하여 좌측 상단부터 순서대로 테이블을 표시했죠. 일반적인 포스기 앱처럼 테이블을 실제 자리에 맞춰 지도처럼 표현한 게 아니었습니다. 그럼에도 크게 불편함은 없었습니다. 어차피 서빙이 테이블 번호를 가지고 카운터에 주문을 요청하러 올 것이고, 결제할 때도 손님이 빌지를 가지고 오기 때문입니다. 빌지에는 테이블 번호가 적혀있죠.
뒤늦게 이야기하지만, 주문의 상태는 아래 다섯 가지 입니다.
- 대기 중: 주문만 들어가고 요리가 시작되지 않은 단계입니다.
- 요리 중: 요리 중인 단계입니다. (주방이 확인한 단계)
- 요리 완료: 요리가 완료되어 서빙 대기거나 서빙까지 완료한 상태입니다.
- 결제 완료: 최종 결제까지 완료된 주문입니다.
- 취소: 유효하지 않은 주문입니다.
테이블은 탭했을 때 선택 상태와 그렇지 않은 상태 사이에서 토글됩니다. 특정한 동작을 하는 건 아닙니다. 테이블이 선택된다면 우측에 상세 정보가 나옵니다. 상세 정보에서는 시간 순서대로 들어온 주문을 보여주고, 각각의 주문 상태도 표시됩니다.
주문을 추가할 때에는 개수, 메모, 0원으로 추가, 그냥 추가 이렇게 네 가지 요소가 있습니다. 주문을 추가한 이후에도 편집할 수도 있습니다. 아직 요리 중이 아닌 주문에 대해서는 취소도 할 수 있고 결제되기 전까지 금액도 세부적으로 수정할 수 있습니다.
주문으로서의 금액과 메뉴 상 금액이 다르다는 점도 살짝 복잡성을 높인 요인이 됐습니다. 예를 들자면 처음에 메뉴의 금액을 10,000원 정도로 생각했는데, 너무 주문이 몰려서 이거 수요와 공급의 법칙에 의해 가격을 두 배로 올려야겠다 해서 20,000원으로 올린다 쳐요. 그렇게 돼도 이미 들어간 주문의 금액이 바뀌면 안되잖아요. 이렇듯 메뉴상 금액은 언제든지 바뀔 수 있고, 주문이 들어가는 시점에 메뉴의 금액만 참조할 뿐 그 이후엔 주문과 메뉴는 전혀 상관이 없었어요. 하지만 또 완전 상관이 없는 것은 아닌게, 메뉴 이름 등은 연결이 되어야 했습니다. 주문에서 메뉴에 관한 정보를 참조하되 일부 정보만 참조를 해야 하는 신기한 처리해야 하는 경험을 했습니다. 어떻게 하면 테이블 구조를 더 잘 짤 수 있었을까 다시 고민해보게 되네요.
카운터에서는 주문의 마지막 단계인 결제 처리를 잘 해내야 하는 의무가 있습니다. 그러나 결제 또한 만만치 않은 작업이었어요. 케이스들이 많았거든요. 일단 계좌이체(현금결제) 말고도 여러 요소가 있었습니다.
- 쿠폰: 일일호프 개시 전에 판매한 현금성 쿠폰이 있었습니다. 하나 당 3,000원으로 판매됐어요. 그렇다고 이득이 있는 건 아니고 일일호프에서 결제할 때 하나 당 3,000원의 가치로 현금을 대체할 수 있습니다. 사전에 쿠폰을 이리저리 판매하고 (선수금 형태) 당일날 쿠폰이 사용되지 않는다면 그대로 이익인 구조입니다.
- 후원: 고객은 주문 총액보다 더 많은 돈을 후원이라는 형태로 낼 수 있습니다. 즉 결제 금액과 주문 총액이 달라질 수도 있다는 거죠.
- 할인: 일일호프에서는 여러가지 게임과 이벤트가 준비되어 있습니다. 이런 게임의 상품으로는 할인권 같은 게 주어지죠. 그러니 서비스 차원에서 주문 자체에 할인을 먹이는 것이 아니라 결제 시점에 할인을 포함하여 함께 계산해야 하는 케이스가 흔했습니다.
위 이미지에서는 티켓이 곧 쿠폰이라고 보시면 됩니다.
좌측에서는 주문 내용을 확인할 수 있고, 가운데 버튼처럼 생긴 탭(현금/티켓/할인/티켓후원)에 따라 어떤 항목에서 금액을 처리할 건지 정할 수 있습니다. 우측에는 직접 숫자를 입력할 수도 있고 간편 버튼으로 금액을 추가할 수 있습니다. 하단에 남은 금액
을 0원으로 맞추는 게 목표입니다. 주문 금액은 현금, 티켓, 할인을 이용하여 0원을 만들어야 하며, 마이너스가 된다면 (주문 금액보다 내는 게 초과한다면) 후원으로 처리할지 등을 선택해야 합니다.
후원 금액과 관련해서는 사용례에 따라 두 가지로 나누었다고 볼 수 있습니다.
- 계좌이체가 아닌 지폐 등으로 현금 결제할 때 잔돈을 후원하는 경우 (결제에 영향을 미침)
- 돈은 돈대로 계산하고 쿠폰은 후원 차원으로 반납하는 경우 (결제에 영향을 미치지 않음)
저런 화면 구성이 좋았는가를 평가하기는 쉽지 않은 거 같아요. 실제로 써본 사람의 (무조건적인 칭찬이 곁들여진) 사용기를 들어보면 나쁘지만은 않은 것 같았습니다. 실제 포스기와 비교해도 그렇게 뒤떨어지지 않는다는 극찬을 받았습니다. 그러나 기기 혹은 숫자에 익숙하지 않다면 사용 난이도가 꽤 있다는 것... 부정할 수 없습니다. 저 화면을 보고 딱 한번에 뭐가 뭔지 이해하는 사람은 없을 겁니다.
마지막으로 주방의 화면만 살펴보고 기획적인 부분은 마치겠습니다.
주방의 최대 목표는 들어온 주문을 빠르게 처리하는 것입니다. 식당에서 모든 병목의 시작은 주방이죠. 요리하는 데 오래 걸리면 주문이 밀리고 기다리는 사람은 늘어나고 끝없는 악순환이 시작됩니다. 포스앱이 어떻든, 주문이 어떻든 간에 일단 요리가 빨리빨리 돼야 고객을 만족시킬 수 있습니다.
실제 요리하는 시간을 빼고 모든 시간적 비용을 줄이는 게 주방 화면의 목표라고 볼 수 있습니다.
- Notifying: 카운터에서 주문이 들어오면 빠르게 주방 화면도 갱신되며 알람이 울립니다 (띵똥띵똥)
- 요리 완료된 주문을 탭으로 구분: 현재 들어온 주문 현황을 한눈에 파악할 수 있도록 합니다.
- 주문 우선순위 부여: 주문이 들어온지 오래 된 것 순으로 정렬하여 더더욱 빨리빨리의 마음을 다잡을 수 있도록 합니다. (심리적 압박을 부여합니다) 주문이 들어온지 10분이 경과하면 빨간 글꼴로 표시하도록 했습니다. 좀 강력하긴 하죠?
실제로 운영할 때에는 주방에 사람이 많았습니다. 대략 한 5명 이상은 계속 있었어요. 주문 현황이 티비 급으로 커야 모든 사람이 화면을 제자리에서 확인하며 각자 할 일을 할 수 있었을텐데, 태블릿이란 작디 작았습니다. 사람마다 요리하는 구역이 정해져 있고 크게 왔다갔다 할 수 있는 동선 또한 비효율적이었습니다. 그래서 아예 태블릿 화면 앞에 한 사람이 배치되어 (이하 태블릿맨) 새로운 주문이 들어오면 바로 육성으로 주문이 들어왔다고 외쳤습니다. 각 요리마다 주문이 몇 개 남았는지 계속 확인할 때도 육성으로 소통했습니다.
태블릿맨이 서빙과 주방의 연결다리 역할을 하며 임무를 다했습니다. 요리가 나가는 통로가 너무 좁기도 했구요. 요리가 완료되면 태블릿맨은 완료 처리를 함과 동시에 주방 입구에 놓여진 벨을 띵띵띵 울렸습니다. 그러면 대기하고 있던 서빙맨이 등장합니다. 태블릿맨은 서빙맨에게 어느 테이블로 이 요리를 가져가야 하는지 전달합니다.
처음에는 주방 통로가 좁아서 좀 걱정했는데요, 요리가 완료되는 속도보다 서빙 나가는 속도가 월등히 빨랐기에 아무런 문제가 되지 않았어요.
그리고 띵똥띵똥띵똥 소리가 생각보다 잘 들려서 모두에게 새로운 주문이 들어왔다는 노티파잉이 확실히 잘 됐다는 생각이 들었습니다. 소리 넣길 잘 한거 같아요.
화면에 표시되는 아이템은 주류와 완전히 분리되어 있습니다. 생맥주 등 주류는 주방에서 처리하지 않기 때문이죠. 주류 쪽이 어떻게 실제로 운영되었는지는 모르겠지만, 뭐 알아서 잘 됐겠죠... ^^;;
글을 마치며
전체적인 평가를 해보자면, 대만족입니다.
저는 일일호프를 운영해본 적이 없어서 실제 어떤 상황이 닥칠지 예상할 수 없었는데요. 무려 20년도 넘게 봉사활동에 몸담은 분과 대화를 많이 해서 설계과 실제 사이의 간극을 좁히는 데 성공한 것 같습니다. 공교롭게도 그 분도 개발자입니다...
앞으로 이런 소규모의 확실한 프로젝트가 있으면 더 재밌게 진행할 수 있을 것 같네요 호호.
앞서 이야기했다시피 이런 앱은 사용성(편리성) 보다는 데이터의 신뢰성이 조금 더 중요한 것 같습니다. 다음 번에도 한다면, 요청이 몰릴 때 테스트를 좀 더 해봐야 할 것 같고, 비상상황(데이터가 꼬이는 상황)을 좀 원복할 수 있는 수단도 마련해야 할 것 같네요. 서버 쪽 validation 을 어느정도 수준으로 해야 할지도 고민 더 하구요.
2023년에 일일호프는 끝났지만 몇 개월이 지나서야 회고를 하게 됐습니다. 하나하나 정리 중입니다. 저는 올해 목표를 회고로 잡았습니다. 열심히 회고를 해보겠습니다.