続・体育館予約を自動化しようとした話
この記事はFablic Advent Calendar18日目の記事です。
体育館予約を自動化したい
こんにちは。Fablicのサーバーサイドエンジニア、Jamesです。
突然ですが、去年のアドベントカレンダーでこんな記事を書きました。
要約すると
Selenium Web Driverで体育館予約システムに自動ログインできたけど体育館全然空いてないから予約できないやんけ!
と言う記事です。
去年は自動でログインした後に心が折れてやめてしまいました。
立場の変化
上記の記事を当時所属していたチームはそこまでしっかりとした活動もせず、たまに大会に出て試合をするスタイルでやっていました。 それなりに楽しくやっていたのですがこの一年で自分を取り巻くバスケ環境が紆余曲折あり、なぜか新チームを立ち上げることになりました。
更に気がつけばそのチームの代表になっていました。なんて恐ろしいことでしょう。
代表になったからには同じチームでやっている仲間達と楽しいバスケットボールライフを送りたいものです。幸いなことに「楽しい == 笑いながらやる」ではなく、「楽しい == 真剣にやる」メンバーが集まりました。我々は学生のように毎日練習することはできませんが、週1ぐらいの練習でできる限りのことをして都民大会で上位を狙うことを目標に活動することになりました。
となるとやはり立ちはだかる壁は、そうですね。
体育館予約を自動化したい
はい、我々は2017年になっても体育館の予約で消耗しています。
↑Kobe Bryantファン必読の本でした(エルニドで撮影。エルニドは楽園でした。)
仕様書を確認する
前回心が折れたポイントは、
体育館の予約の仕方が直感的に理解しづらい
この一点に尽きます。
しかし、今回は前回とは違い責任が増えたので根気よく取り組むことにしました。 このようなシステムにありがちな 「ブラウザの戻るが使えない」 仕様のために何度もやり直しをするなどしながら調査を続けていると、普段世の中に出ているWebサービスがどれだけユーザーに寄り添っているのかと感激して涙が溢れてきました。
こうして調査を続けていると以下の仕様がわかってきました。
- 予約は9-22時の間に行うことができる。
- 予約は基本的に抽選である
- 翌月の体育館予約の抽選は前月の1-5日に行われる
- 結果が6日に出る
- 結果を反映した後の9日から当該月のキャンセル分の予約が可能
- キャンセルされた予約は早い者勝ち
- 1つの予約をすると最初の画面からやり直さなければならないので、複数の予約を同時に行うことは不可能
なんという仕様でしょうか。 毎月9日の朝9時に翌月の予約の勝敗が全て決まってしまうではありませんか。
逆を言えば、 その時間にものすごいスピードで予約をしてしまえばだいたいよさそうです。
そして、キャンセル後は早い者勝ちなのでそれを漏れなく予約すればよさそうです。
抽選の内容に関してはこちらとしてはタッチできない部分なので諦めます。(根気よく抽選も申し込んではおりますが、これまで1日しか当選したことがありません、、、)
つまり、我々に必要なものは
体育館のキャンセル状況を確認して、空きが出ていたら自動で予約できる何か
ということがわかりました。
作りたいものが少し具体的になりました。
類似するシチュエーションを利用して仮で予約してみる
さて、作りたいものが具体的にはなりましたがやはり空いている体育館がありません。 どのような状態になれば予約完了に出来るかがわからないので開発が進めません。 去年の自分だったらここでまた心が折れて、この企画はまた来年に持ち越されていたでしょう。
しかし、2017年の僕は一味違いました。人は守りたいものができた時に強くなれるものです。
すぐに作りたいものを作ろうとするのではなく、可能な限り類似するシチュエーションを利用して他の施設を予約してみることにしました。 どういう意味かと申しますと、 まずは、「体育館」を予約することを諦めて、同じシステム上で施設の空きが多い「会議室」を予約出来るシステムを作りました 「体育館予約システム」のためにまずは「会議室予約システム」を作ることになるとは思いませんでした。 しかし、この作戦が功を奏しました。 「会議室予約システム」の完成後、体育館キャンセルをチラチラ見ていたら平日ですが体育館空きがある日も奇跡的に発見することができ、「体育館予約システム」に生まれ変わらせることができました。
コードは公開したくないので(ライバルを増やしたくないw)具体的な内容は伏せますが、フレームワークも使っていないRubyのスクリプトです。
bundle exec ruby app.rb
この1行をターミナルで実行するだけでキャンセル状況を見て予約出来るプログラムがかけました。
マンバメンタリティー!
サーバー上で動かせるようにする
最後は書いたプログラムを定期的に実行させるだけです。 そのためにはサーバーが必要になります。
最初は「どこかのサーバーにcron登録するのかー、会社の開発機にでも置くかw」とか考えていたのですが、ものすごく便利なサービスがありました。
みなさんご存知Herokuです。
Heroku上でSelenium webdriver を利用するためにはChrome headlessモードを利用する必要があるので、Buildpackをインストールする必要があります。(Herokuの管理画面から簡単にできます。) そして、何より驚いたのはHerokuにはHeroku Schedulerというプラグインがあり、これを使うとポチポチ設定するだけで簡単に定期実行してくれます。 cron登録を代行してくれるだけかもしれないですが、とても楽でした。
予約完了後の通知機能をつける
こうして一定の時間で予約をすることが可能になりました。 しかし、予約が成立しているか常に確認しに行くのは不便です。 そこでLINE Notifyを利用して予約が完了したらチームのLINEグループに通知が行われるようにしました。
LINE Notifyはトークンを渡してHTTPポストするだけなので簡単でした。
参考
身近な仲間を幸せにできること
結果
見事我々のチームは安定したバスケットボールライフを送っております。 これまでよりチームプレイも増えてきて、とある市民大会では優勝することもできました。
こんなに首から頭下げてると思いませんでした。
これまで仕事でたくさんのコードを書いてきましたが、1番価値のあるものになったと思いますw 合計で300行も満たないコードで幸せな気持ちにさせてくれるRubyにも改めて感激しました。
このように業務で得た知識が私生活をも充実させてくれるのはこの仕事のいいところであると思います。
しかし何より、仲間たちとバスケをする時間が増えたことがとても嬉しいです。
体育館予約には開発のエッセンスが詰まっていた
実は今回の一連で学んだことに 開発のエッセンスが詰まっているのではなのではないか と考えました。
- 作りたいものの概要を理解する(顧客が本当に必要だったのは「自動予約システム」ではなく、「自動キャンセルされた体育館の予約システム」)
- 制約を理解する(予約できる時間の把握等)
- 機能を細分化し、似た事例を探す(Selenium Web Driverの使用事例を探す、Heroku Schedulerのようなやり方を探す)
- すぐに作りたいものができない場合はそれに類似するシステムを作る(会議室予約システム)
- 本番のシステムに適応させる
- 更に便利になるような仕組みを考える(LINE Notify機能の追加)
特に 機能を細分化し、似た事例を探す というのは大切だと思います。
でも、結局のところ根性な気がします。
最後に
練習試合相手を絶賛募集中です! FacebookやTwitterからお気軽に連絡ください!
クリスマスも近いのでウィッシュリスト載せておきます、、、
最後に何かの有名なセリフを載せておきます
The best teacher, failure is