ステータスを巻き戻す機能に気をつけろ!
これはなに

こんにちは、レバテック開発部のもりたです。
今回はもりたのやらかしたイマイチな機能開発について説明しようと思います。わりとやっちゃいそうで普遍的な要素を含む失敗だったので、ぜひみなさんが実際に触っているシステムと比較しながら読んでいただけると幸いです。
今回の構成
構成

こんな構成でいきます。シンプルにね〜。
ステータスを巻き戻す機能には気をつけろ!
どんな機能追加をしたか?
はじめに、問題となった機能開発がどのようなものだったのかについて説明しようと思います。
本機能開発は、既存機能に対する機能修正でした。
既存機能 - LINE公式アカウントの登録
レバテックではフリーランスや転職者、就活生に向けたエージェントサービスを展開しています。このサービスでは、求人・案件探しの際にエージェントさんと気軽にやり取りができるよう、LINEをコミュニケーションチャネルとして採用しています。
飲食店や美容院で「LINEで友だち登録してね」みたいなQRコードを見たことはありませんか? ああいった感じに利用者に友だち登録を促し、エージェントさんと利用者が直接会話できるようにする、というのがわたしの所属するチームが提供するシステムの責務になります。
今回取り上げるのが、友だち登録に関する機能です。
この機能では、LINEでのやり取り開始に至るまでのフローを管理しており、ざっくり以下のような流れをとります。

最初に利用者がレバテックでの「サービス登録」を行います。それを受け、社内システム上でLINEでのやり取りをするための準備を進めます(「登録用QRコードの発行」)。準備ができたら「メール送信」し、利用者がメールに添付された登録QRコードから「登録」したら、やっとLINEアプリ上で「メッセージのやりとり」ができるようになります。
機能修正 - 登録QRコードの再発行
新たなニーズとデータリペア対応
上記のようなLINE登録フローを運用するうちに、新たなニーズが分かりました。人材がスマホを買い替え、連絡先のLINEアカウントを再登録したくなったようです。
LINEを利用したシステムにおいて、利用者が端末を変更するというのは重要な出来事です。LINEプラットフォームでは利用者の端末情報をもとに利用者を特定し、メッセージの送受信を行っているため、端末が変更になると全ての機能が使えなくなります。
そのため性急に端末変更には対応したいのですが、いかんせん登録に関わる機能は複雑であったため、当初はこれを運用対応しました。具体的には、登録ずみの端末情報をデータリペアで削除し、初期登録用のQRコードを作り直してメール送信していました。
若干ズレる例にはなりますが、パスワードの再登録機能を思い浮かべてもらえるとわかりやすいかと思います。この当時の状況としては、パスワードの再登録機能を持たない状態で利用者からパスワードの再登録をしたいと言われ、どうしても再登録機能を作成できなかったので、一時的にハッシュ済みパスワードを削除して登録用のURLを再度送る運用を採用した、というわけです。
そして対応の余裕ができたタイミングで機能化と相成りました。
再発行機能の概要
再登録機能はデータリペアのフローを踏襲して設計されました。修正概要は以下のとおりです。
- 新しい端末を登録できるよう、DB上の端末情報を削除する
- あたらしく登録用のQRコードを発行する
- あたらしい登録用のQRコードを人材が読み込むと、端末情報がデータベースに登録され、あらためてLINEでのやりとりができる
端末情報を消して、QRコードを再発行しています。ステータスを巻き戻すようなイメージの機能であり、再発行機能と呼ばれました。
もともとの機能を活かして巻き戻すような実装であり、不具合は少ないだろうと踏みました。しかし、これが禍根を残します。

なにが起きたか?
再登録のための運用対応はなくなり、運用コストを圧縮できるようになりました。これはかなり嬉しかったんですが、少し時間が経つと、それまで見たことのないエラーログのアラートが頻発するようになりました。
どうやら、端末変更した人材が、再登録用QRコードで登録する前に、古い端末からメッセージを送信したようです。しかし、古い端末データは削除済みのため、エラーが起きてしまいました。

再発行機能を実装した時は、QRコード発行済みのステータスに戻したつもりでしたが、実際はQRコード発行済みの時点では想定していない振る舞いが許された状態になっています。単に巻き戻しただけと考えていましたが、実は別のデータ状態を作っており、また許可された振る舞いもチグハグでした。
なにがイマイチだったのか?
この機能修正はなにが悪かったのでしょうか? いろんな観点から良くなかったところは挙げられるのですが、今回はステータスに着目しましょう。今回まずかったのは「データ状態と振る舞いの一致を考慮しなかった」ということです。
このまずさが、修正概要を説明した際の表現にも詰まっています。
ステータスを巻き戻すようなイメージの機能であり、再発行機能と呼ばれました。
もともとの機能を活かして巻き戻すような実装であり、不具合は少ないだろうと踏みました。
ここの「ステータスを巻き戻すようなイメージ」「もともとの機能を活かして」に着目してみましょう。
「ステータスを巻き戻すようなイメージ」
まず本来、ステータスというのはデータ状態を代表させたようなものになります。作業者によってデータが入力され、データ状態が変更されることでステータスが遷移するなんてことは多いと思います。
今回は以下の「イメージ」でふんわりとステータスを巻き戻したつもりになっていました。

しかし、実際は様々なデータが巻き戻せていません。
- 巻き戻せなかったデータ
- 永続化データ
- それまでのやりとりの履歴
- 担当エージェントは誰なのか
- スマホ端末側のデータ
- 永続化データ
これでは「QRコード発行済み」のステータスに巻き戻せたとは言えません。
「もともとの機能を活かして」
同時に、振る舞いに関しても考慮が足りていませんでした。
元の機能を活かすこと自体は問題ないですが、このデータ状態でどの機能が流用されうるのか精査していませんでした。
具体的にはスマホ端末側の振る舞いを完全に考慮しておらず、「人材のLINE登録済み」よりも前のステータスで「人材のLINE登録済み」であるかのような挙動を許容することになりました。
どう直すのがいいか?
ではどうすべきだったのか考えてみましょう。直すべきポイントは簡潔で、データ状態と振る舞いの一致です。
OOPの基本中の基本であるカプセル化にも通ずるところがあると思います。新しいデータ状態を追加する際は、そのデータ状態が許容されるべきである振る舞いについても同時に検討するべきです。
今回について言えば、LINEアプリ側の振る舞いに制限をかけることは難しかったため、逆にデータ状態を増やすことなく処理させるのが良かったのだろうと思います。
例えば一般的なパスワード変更フローのように、再登録用のQRコードを添付したメールを送信し、再登録した時点で初めてデータを更新するようにすればよかったはずです。

そのほか、今回でいえば古い端末(データ状態)はどうしても生まれてしまうため、古い端末で許容されるべき振る舞いがなんなのかを考えることで、どのようにエラーにするだとか、追加の振る舞いを考えることができたはずです。
余談:なぜこんな機能にしたのか
ここまで長々とイマイチな設計について語ってきましたが、そもそもなぜこんな機能にしたのでしょうか。パスワード再登録のフローと思い浮かべた時、わざわざパスワード失効中というステータスを挟んでしまう方が不可解ですよね。
なぜわざわざそんな複雑な設計になったのか。考えるに、これは当初のデータリペア運用の延長線上で設計を行なったせいです。
そう考えると次に思い浮かぶ疑問は、データリペア運用の時点で同じようなエラーが発生していなかったのか? という点です。おそらくそういったエラーは発生していたのですが、検知されていませんでした。エラーログの監視が十分に行われていなかった過去の体制にも問題がありそうです。
イマイチな設計の背後には多層的な問題が隠れている...そんなことを考えさせられる機能開発でした。
おわりに

しょっぱい体験になりましたが、カプセル化の意義やシステム開発運用の奥深さを身をもって体験できたのは良かったなあと捉えています。なにかと活かせる概念だと思うので、今後もよく気をつけたいものです。
参考文献
-
画面遷移に順序があるUIの保守性を向上させる「順序ありオブジェクト指向UI」の提案
- 弊テックブログのkimaさん記事
- その他にもステータスに着目した記事をいくつか書いており、面白いです
Discussion