こんにちは、篠原です。
今回はごく基本的な内容になりますが、ご紹介します。
Webアプリケーションでは、画面上からリクエストされた入力内容は常にチェックし、
アプリケーションを正しく動作させるとともに、不正データの混入を防止することが求められます。
このチェック処理のことをバリデーションと呼んでいますが、単純に
①アプリケーション上、不正な文字種を入力させない
という内容だけではなく、
②ある状態になっていたら入力内容を許容しない
など、何らかの”状態”によってバリデーションのOK/NGが異なるケースもあります。
(特定の組み合わせを選択させない、既に実行済みの処理は再実行させない、など)
実際に報告が挙がったのは、
とある画面入力の1回目と2回目で、内容変更をしても結果が変わらなくなり、何度操作しても正しく実行されなくなった
というものでした。
その原因は、クラス内でユーザーごとのバリデーション結果をキャッシュする作りになっていたためでした…!
コーディングにおけるSingletonパターンとは、アプリケーション上でインスタンスが1つしか存在しないようにクラス設計を行うデザインパターンのことです。
詳しい説明は割愛しますが、WebアプリケーションでのController(Action)クラスやServiceクラスなど、
フレームワークでDIするクラスもこのパターンに当てはまります。
こうしたクラスに、ユーザーごとの計算結果など、常に変化する”状態”を保持させてはいけません。
先ほどのバリデーションの話に戻すと、
②のように、入力内容の正当性が他のデータ状態に依存する場合、最新のデータ状態で判定する必要があります。
Webアプリケーション内部の状態管理は、DBやサーバーセッションなど、しかるべきストレージに保持し、そちらに適宜アクセスして行います。
また、その情報はSingletonなクラスのフィールドとせず、適宜呼び出すメソッドの引数に追加して情報を持ち回り、異なるリクエスト間で使い回すような設計にしてはなりません。
おそらく、まずい設計になった動機は、
データ取得のためのDBアクセスが頻繁に発生して、パフォーマンスのボトルネックになることを懸念した
ということだと推測しています。
重い処理をキャッシュして速くしようとする考え方自体はオーソドックスなものですが、
入力内容のバリデーションは常に一定した基準で判定を行うべきで、このケースではDBアクセスを安易に削減するアプローチをとるべきではありませんでした。
Singletonなクラスには、状態に関する情報を保持させないような設計にしましょう!
もし、WebアプリケーションのDB面で高速化が必要なのだとすれば、
・1リクエストあたりのDBアクセス回数を減らす
・リクエストの回数を少なくなるようにする
・クエリやDB自体をチューニングする
・もともとのデータ設計を見直す
などが正しいアプローチになるでしょう。
もちろん、データ設計を後から大きく変更することは、はばかられるケースがほとんどですが…。
次回はDBのパフォーマンスにまつわる事例について、書いていきたいと思います。