【895日目】サロン予約管理システムの開発を行いました

こんにちは。あとむです。

ここ3ヶ月ほどはサロン予約管理システムのプロジェクトに参画していたのですが、ようやく全ての実装とテストを終えてリリースまで完了することができたので、そのふり返りをしていきたいと思います!

プロジェクト概要

  • Laravelで実装
  • プロジェクト内のエンジニアは2名で、インフラ全般・リモート解錠・クーポン周りを担当。その他全てはもう一人のエンジニアが担当
  • リモート解錠はAkerunを使用して実装
  • インフラはもともとLightsailだったが最後にEC2に移行した
  • 口座振替機能も実装したが途中で仕様変更が入りリリースまではされなかった
  • Google Cloud Vision APIで免許証から文字抽出

今回はプロジェクトの途中からヘルプで参加したのですが、主にサロンのリモート解錠の部分を実装しました。

これまではあくまでプログラム上でデータを管理したり決済したりする開発しかしたことがなかったのですが、今回はサロンを予約した人が予約時間になると対象のドアをウェブアプリを通してリモートで解錠できるようにするという、ユーザーさんに物理的な影響を与えるシステムでした。

なので処理に不具合があったりするとかなり大きな迷惑をかけることになるので、プレッシャーが大きくリリース時はとても緊張しました。

またテストが大変で、解錠のテストをすると実際にドアが開いてしまうので、お客様と事前にテスト日程を打ち合わせしたりする必要があり、その分の工数を見積時に入れることができていなかったので後半はかなりバタバタしました。

最終的にはシステムを利用する店舗が一駅となりにあったので自分でPCとスマホを持ちながら店の前でテストをしたのですが、何も知らない人からすると完全に不審者でした。訴えられなくてよかった。

Akerun API

今回開発のメインとなるリモートでのドアの解錠にはAkerunというサービスを使用しました。

Akerun APIはOAuth2.0の仕組みを採用しており、APIの使用時はアクセストークンを使ってリクエストを投げることができます。

またアクセストークンは90日で使用不可能になるので、アクセストークン発行時に同時に発行されるリフレッシュトークンを使ってアクセストークンを再発行する仕組みが必要でした。

なので初回のアクセストークンは手動で発行してそれをDBに保存、その後はcronでアクセストークン再発行のバッチを毎月実行することで永続的にAPIを投げることができるようにしたのですが、これを全環境で実施すると肝心の本番環境のDBに最新のアクセストークンがなくて動きませんでしたみたいなことにもなるかなと思い、このあたりのデータのハンドリングが少し面倒だったなと思います。

ただ今記事を書いているうちに気づいたんですけど、別に再発行しても再発行以前のアクセストークンが使えなくなるわけではないんですかね?あれ?これかなり無駄なこと私やってたかもしれないです。。。

まあそんな感じでリモート解錠という言葉に最初は恐れていましたが、実際に実装してみると普通にAPI投げるだけなので、以前の開発で実装したBOX APIの方が何倍も面倒だったなと思います。

APIすごい。

APIの開発自体は簡単だったのですが、お客様からの要望で「Akerun APIの利用履歴からある程度の混雑情報を予測してほしい」との要望がでてきて、そこの仕様の部分で話をつけるのにとても苦労しました。

最近はコードを書くことよりも「やりたいことを実現するためにどのような仕様にするか」というところで悩みます。

もう少し正確に言うと「具体的な要望が出てきた時に、その修正を実施することでお客様が本当にやりたいことを実現できるのか」というところで悩むことが多いです。

会社員時代はSEだったので、当時はもしこのまま会社員だったら死ぬまで仕様を考え続けるんだろうなと思って絶望していたのですが、結局フリーランスになっても仕様の話が1番頭を悩ませるところで、なんだかなという感じです。

LightSailからEC2への移行

今回のシステムはなぜそうなったのかは全く知らないのですが、もともとLightsailで立てていたサーバーを、一旦ユーザーに公開した後にEC2に移行するという、良くわからないオペレーションが必要でした。

移行する時は普通にユーザーさんが使用している時で、かつ悲しいことに本システムが24時間使用できるを売りにしているサービスだったので、移行時にはきちんと事前に日時を決めて告知をして手順書を書き深夜にそれを実施するという感じでした。

もともと会社員やっていた時に参画していたプロジェクトが夜間のバッチがあるシステムで、良く手順書の確認やメンテナンスの実施をしたのを思い出します。あの時は辛かった。。。

ただその時の経験が今回の移行にはかなり生きました。真面目に社会人しておいて本当に良かったと思います。

移行の手順としては簡単に言うと

1.EC2・RDS等で移行先の本番環境を作る(事前準備)
2.移行前と移行先の環境をメンテナンスモードにする
3.DBとストレージの移行
4.Route53の対象ドメインのAレコードを変更
5.DNSの浸透を待つ
6.移行先環境で一通りテスト実施
7.移行先環境のメンテナンスモードを解除

みたいな感じでした。

AWSだとこういう時も全てAWSのコンソール内で完結できて素晴らしいですね。昔変なレンサバからXserverにドメインを移管した時はごちゃごちゃしてすごく大変だったので、今回も僕はかなり身構えていたのですが、お客さんはわりとフラットな感じで移行作業をしていた理由がわかりました。
(そもそもドメイン移管とシステムのインフラの移行は話が大分変わるのでアレですが)

またLaravelさんにも感謝です。メンテナンスモードなるものが実装されているおかげでとてもスムーズに移行を進められました。

コマンド一発でメンテナンスモードにできることだけじゃなく、特定のURLからアクセスしたユーザーのみメンテナンスモード画面ではなく通常の画面に遷移できる部分には感動しました。

実は今回の移行は移行する1週間前に伝えられたのでかなりキレそうになったのですが、このメンテナンスモードがあることを知ったことで怒りが一気に引きました。マジでありがとうLaravel。

Google Cloud Vision APIで免許証から文字抽出

免許証の画像から文字を抽出するためにGoogle Cloud Vision APIなるものを使ったのですが、そのコードの簡単さとその精度の高さに驚きました。

「画像データから文字を抽出する」という難しそうなことでも、APIに画像をぶん投げるだけでできてしまう時代なのですね。

実際に書いたコードはこれだけ

// 画像を取得
$file = file_get_contents($img_path);
$client = new ImageAnnotatorClient([
    'credentials' => storage_path(config('gcp.cloud_vision.json_path'))
]);

// API連携
$image_file = $client->createImageObject($file);
$response = $client->textDetection($image_file);

if (!is_null($response->getError())) {
    response()->json($response->getError());
}

$annotations = $response->getTextAnnotations();
description = isset($annotations[0]) ? str_replace('"""', '', $annotations[0]->getDescription()) : "";

return $description;

めっっっっちゃ簡単。調べるところから始めてギリギリ1時間かかりませんでした。

エンジニアからすると「は?API投げただけでイキんな」ですが、非エンジニアからすると「AIを使って画像から文字データ抽出とかいうすごいことをこんな短時間に??すごい!!」ってなるんでしょうね。恐ろしい。。

最後に

こんな感じでリモート解錠を実装したという話でした。

振り返ると3ヶ月たっていましたが実際にメインの開発は1ヶ月で残りの2ヶ月は永遠とでてくる新仕様の対応に明け暮れていたように思います。

途中から諦めて脳を停止させて言われたものを作ってしまったのですが、もう少し頭を使って仕様(というかやりたいこと)をきちんと聞いて実装すればもう少しスムーズに行けた気がしているので、その部分は反省です。

そんな感じの開発でした。ありがとうございました!