この記事は CAMPHOR- Advent Calendar 2018 3日目の記事です.
高校の文化祭の食販の注文フローを電子するべくWebアプリケーションを作り,当時*1はWeb素人だったためクソ実装になったが,役には立ったという話をします.
背景
僕の母校の高校には,三年生が文化祭で食販をやるという慣習があり,僕のクラスはケバブを販売することになりました. 母校の家庭科の教員は衛生管理に大変厳しい人で,食販を行う場合は以下の条件を満たさないと許可が降りませんでした*2.
- 調理は調理室のみで行う(教室で調理してはいけない)
- 作り置きは禁止*3
これらの制約を満たすため,多くのクラスは以下のような流れで食販を行っていました.
- 教室で注文を受け,注文を何件か溜める
- 注文を持って調理室に向かう
- 注文を伝え,調理が完了するのを待つ
- 料理を運ぶ
このフローには問題があります. まず,2に「調理室に向かう」とありますが,調理室までの廊下は大変混んでおり,たどり着くまでに時間がかかります*4. 次に,3で「調理が完了するのを待つ」とありますが,作り置きが禁止されているため待ち時間が発生します.
これらが原因で,お客さんは注文してから料理が届くまで長い間待たされていました. この待ち時間を短縮するべく,注文フローを電子化することにしました.
仕様
以下が電子化された注文フローです.
注文フローには大きく分けて3種類の人間が登場します.
これらの人間がWebアプリを介して図のように協調するわけです.
実装
動くものはこちら:
実装の全ては gist に置きました.読みたい人は読んでください.
以下ではこのコードを抜粋してクソ実装ポイントを解説します.
実装に興味がない人は 文化祭当日の話 までジャンプしてください.
クソ実装ポイント1: HTMLをPythonの文字列に直書きしている
当時は若く,テンプレートエンジンという概念を知りませんでした. そのためHTMLをPythonのコードの中に直書きしています.
迫力がありますね.
https://gist.github.com/genya0407/d8af63f8fd0730bedf1408f8a9b29a8b#file-main-py-L187
少しでも共通化しようとする涙ぐましい努力が感じられます.
https://gist.github.com/genya0407/d8af63f8fd0730bedf1408f8a9b29a8b#file-main-py-L69
Pythonの文字列の中にHTMLを書いてるので,HTMLのシンタックスハイライトは一切効きません.当然JavaScriptのシンタックスハイライトも効きません. これは実際開発中に問題を起こしており,コードに色がついていなかったためJavaScript中のクォーテーションマーク(')が全角になっているのに気づかず,丸一日デバッグで溶かしたという記憶があります.
これが原因で当時悪夢を見た.
絶対自分では書いてないコードをソースの中に見つけて、その処理の内容も全くわからず、ずっと悩み続けるという悪夢を見ました。
— 𝑨𝒓𝒓𝒂𝒚-𝒔𝒂𝒏 (@genya0407) September 7, 2013
クソ実装ポイント2: 全てのPOSTリクエストを単一のエンドポイントに投げている
なんでそうしたのか本当に覚えていません.フォームに type
という属性を付与して,その値で分岐しています
https://gist.github.com/genya0407/d8af63f8fd0730bedf1408f8a9b29a8b#file-main-py-L110
なんでこんなことをしたんですかね...
多分エンドポイントを増やすのが面倒みたいな理由だと思うんですが覚えてない.
クソ実装ポイント3: 全てのリダイレクトをJavaScriptで実現している
POSTリクエストを受けた後などのリダイレクトしたくなる全ての場面で location.href="/path"
が使われています.
https://gist.github.com/genya0407/d8af63f8fd0730bedf1408f8a9b29a8b#file-main-py-L131
当時はHTTPのレスポンスでリダイレクトを表現できることを知らなかったのでこういう実装になりました.
文化祭当日の話
発生した致命的な問題
実際に運用したところ,1日目の午後から,「作ったはずの注文に完了フラグが立たず,古い注文が永遠に表示され続ける」という現象が発生しました. こうなると新しい注文が表示されないので,調理者は完全にストップします. そして教室には注文を待つお客さんが溢れ,いつまで経ってもケバブが届かない...という地獄が発生します.
結局その日は途中で手作業にフォールバックし,どうにか残りの注文を捌きました.
その日の夜,クラス委員で集まって2日目をどうするかということを議論しました(文化祭は二日間ある). また同じ現象が起こるかもしれないという不安があるため,僕は手作業の方が安全だという主張をしました. しかし,調理者側の責任者が「手作業よりもWebアプリの方が全然楽だ」と強く主張したため,翌日もWebアプリで行くことになりました*5.
原因
とはいえ,問題を解決しなければ翌日も地獄が発生する可能性があります. しかしコードを見てもバグっぽいところは見つからないし,そもそも午前中は正しく動いていたのです.
午前中に動いていたシステムが,午後になって突然動かなくなるなんてことがあるか?午前と午後で変わるものって何だ? というところまで考えて,この現象は「運搬者が記録ボタンを押し忘れている」ことに起因するのではないかということに思い当たりました.
運搬者はシフト交代がありました*6. 午前中はみんなちゃんと記録ボタンを押していたのだが,午後のシフトの誰かが記録ボタンをよく押し忘れる人だったという仮説を立てるとこの現象を説明できます*7.
他の人間と違って運搬者は,運搬/記録 という2つの独立した作業をする必要があります. 記録はしなくても運搬はできてしまうので,記録するのを忘れやすい構造になっています.
解決策
原因がわかったところで,どうやって解決するのかという話になります.
問題は結局,人間に間違いやすい行動をさせるのが悪いというところに帰着されます. では,間違いやすい行動を人間にさせないためにはどうすればよいでしょうか?
これは,間違いやすい行動を複数の簡単な行動に分割することで実現できます.
このことを踏まえ,注文フローを以下のように修正しました.
- 受付
- 教室で客の注文を聞き,Webアプリに入力する(注文)
- 調理者
- Webアプリの注文を見て調理室でケバブを作る(確認)
- 運搬者
- 調理室から教室までケバブを運ぶ(記録はしない)
- 管理者
- ケバブが運び出されたのを確認して注文完了フラグを立てる(記録)
つまり,運搬者に記録をさせるのをやめて,記録するだけの人間(=管理者)を新たに作ったということです. 管理者は記録という業務に集中できるので,記録忘れをすることは基本的にありません.
これの何が嬉しいのかというと,新しく機能を作らなくて済むという点です. アプリケーションを修正するのではなく,運用方法を修正することで対応したわけです.
これに加えて,ケバブの注文状況と出荷状況が把握できる管理者用画面を作りました.
これを見れば,問題なく注文が捌けているのか一目瞭然です.
このように注文フローを修正することで,2日目は特に障害もなくWebアプリが動作しました.
めでたしめでたし.
考察/学び
- 知識は大事である.テンプレートエンジンやHTTPの知識などを含めたWebシステムにおけるベストプラクティスを知らなかったのでこういうクソコードを書くことになった.
- 人は間違いをするということを前提にシステムを作る必要がある.
- 人に作業をさせるときは,それをチェックする仕組みとミスしたときに修正する仕組みを用意しなければならない.
- ミスの原因は,人にあると考えるのではなく,業務にあると考える.
- クソコードでも役には立つ.
現在の文化祭はもっとハイテクになっていた
...というようなことをTwitterで連投していたところ,母校の後輩から以下のようなツイートが飛んできました.
2016年
高校の文化祭といえば、まだ日本語ドキュメントもないFirebaseのHostingとRealtime DBで注文システム作ったの大変懐かしい pic.twitter.com/2yrVy7hNW7
— ど(∩❛ڡ❛∩)ら (@_dorayaki_) November 28, 2018
2018年
でも今年のとか見たらもっとハイテクでびっくりしますよ… pic.twitter.com/pbHLi4ldcv
— ど(∩❛ڡ❛∩)ら (@_dorayaki_) November 28, 2018
食販ハイテクムーブメントの始祖になれたということで一つ...
来年5年ぶりに母校の文化祭行ってみようかな
— 𝑨𝒓𝒓𝒂𝒚-𝒔𝒂𝒏 (@genya0407) November 28, 2018
追記
このブログをFacebookに投稿したところ,他にも様々な面で電子化が進んでいるとの情報を高校の先生からいただきました.
例えば,アトラクションを出し物にしているクラスが得点ランキングの表示を電子化したり,各団体の待ち時間が廊下のディスプレイに表示されたりしているそうです. デジタルネイティブの波を感じますね.
関連記事
4年間の修行の末,もっといい感じのWebアプリを作れるようになった.