開発の終わりごろになって、重要な機能が漏れていたことに気づくというケースは意外に多いです。
小さな案件であれば起きにくいですが、プロジェクトが大きくなればなるほど、仕様が複雑になればなるほど、後から問題が発覚しがちです。
- システムテストの段階になって、データの不整合が発生していることに気が付く
- 同じ画面の操作でも、特定の条件のときだけエラーになる
このような問題が生じると、修正や原因調査にコストが大きくかかります。できる限り仕様の抜け漏れをなくし、問題を起こさないようにするにはどうすればよいでしょうか。
そのための1つの手段が、データのライフサイクルを考えるということです。
データのライフサイクルとは
データのライフサイクルとは、データが作成されてから削除されるまでの一連の流れのことです。
各処理の頭文字をとって、CRUDとも呼びます。
データのライフサイクルに沿って仕様を検討するとは、データの状態に注目して順に追いかけながら、都度どのような状態になっているのが正しいのかを仕様に反映させることです。
仕様を考える順番や検討項目に漏れを作らないために使われる考え方で、データベースがあるシステム開発の現場ではどこでも使うことができる、とても汎用性の高い思考のフレームワークの一つです。
それでは、どうやってデータのライフサイクルを仕様に反映させるのでしょうか。
1.データの作成(Create)
どんなデータであっても、初めに「作成」というステップがあります。
- ユーザーを登録する
- 売上情報を入力する
- デバイスから受信したデータを登録する
データの作成時に考える必要のあることは、どのようなことでしょうか。
データを作っても良い状態になっているのか
たとえば、売上情報を登録するには、事前にお客様に見積もりを提示したというデータが必要かもしれません。夜間はデータの参照のみで登録や更新、削除はできないシステムかもしれません。
このように、データを作ってはならない状態であれば、操作を止める必要があります。
必要なチェック処理を実装し、エラーメッセージを表示したり、そもそもデータ作成画面への遷移を止めたりして、データを作れないようにします。
作っても良いデータになっているのか
たとえば、ほとんどのシステムでは、ユーザー情報には名前が必須です。業務用のシステムでは、ユーザーに会社の所属や上司の情報を紐づける必要もあります。
ユーザー登録画面で入力されたメールアドレスが、実際には存在しないものかもしれません。
このように、入力された値が不足していたり、他のデータと不整合があったりする場合は、操作を止める必要があります。
必要なチェック処理を実装し、エラーメッセージを表示したり、メールアドレスは実際にメールを送信して存在確認の手順を踏んでもらったりして、入力内容が正しくなるように制御します。
データの作成と同時に、何を登録・更新・削除する必要があるのか
データを作成できる状態であり、作成可能なデータが入力された場合は、実際に登録作業に入ります。
その際、入力された情報以外にも作らなければならないデータ・更新しなければならないデータがある場合は、同時に作成する必要があります。
データを作成したことを残すログであったり、デバイスからの疎通状況であったり、対象のデータ以外にも登録しなければならないデータは発生しえます。
システム全体として不整合が発生しないように、何のデータをそろえる必要があるのかを考える時間を取りましょう。
データの作成を検討し終えたら、次に考えることは以下です。
2.データの参照(Read)
登録されたデータには、システムの画面上に表示されるものもあります。
- 登録されたユーザーの一覧、詳細
- 売上情報の金額、今のステータス
- デバイスの稼働状況グラフ
データの参照時に考える必要のあることは、どのようなことでしょうか。
見えても良いデータはどこまでか
入力されたデータは大部分は見えても良いかもしれません。他のユーザーには見えてはいけないデータであったり、権限によって見えて良いかどうかが変わったりします。いつから見えても良いかを考えなければならないデータもあります。
登録したからといって、すべてのデータをだれでも見えても良い訳ではありません。個人情報や企業の内部情報を扱うシステムであれば、この点は特にシビアに検討する必要があります。
どのように見せるのか
1つの画面ですべての情報を見せることもありますし、複数の画面に分けることもあります。文言で見せることもあれば、アイコンや記号で見せることもあります。
UI/UXを考慮した見せ方をしたり、編集しやすいように工夫をしたりするのも、ここで検討することです。編集できないのであれば、ラベルにするのか入力不可のテキストボックスにするのかといった細かなことも検討する必要があります。
データを見せる方法、データの見せる内容は、次に考えるデータの更新とセットになることも多いです。更新されてステータスが進めば編集できなくなってラベル表示にする必要がでてきたり、表示対象外となったりします。
更新されるたびに、何がどう変わるのかも検討する必要があります。
それでは、更新時に考えることはどのようなことでしょうか。
3.データの更新(Update)
登録されたデータは、削除されるまで更新される可能性があります。
- ユーザーの住所、名前の変更
- 売上情報のステータスの変更
- デバイスの接続状況のライブアップデート
データの更新時に考える必要のあることは、どのようなことでしょうか。
データを変更しても良い状態になっているか
データの作成時と同じく、裏側でバッチ処理が実行されている間は、更新できないようにする必要があります。
また、データの作成と異なるのは、排他制御です。
たとえば、Aさんがブログを編集しているとします。そのブログはBさんと共同で運営していて、Bさんも同じ時に同じ記事を編集しているとします。
このとき、Bさんが更新した記事の内容を、Aさんが確認する前に上書き更新するわけにはいきません。Bさんの編集がなかったことになり、Bさんの努力が水の泡です。
このような想定外の更新を防ぐには、更新処理に以下の手順を追加します。
- 画面の表示時に更新シーケンスを取得する
- 更新時に、1で取得した更新シーケンスを更新処理に渡す
- 更新処理で、引数として渡ってきた更新シーケンスがDBの対象データの更新シーケンスと一致するかを検証する(排他制御)
- 一致する場合は、DBの対象データを更新してシーケンスも更新する。
一致しない場合は、更新処理を中断する。
これが排他制御の流れです。排他制御をするための項目がDBに必要になりますし、その値の更新仕様も決める必要があります。
変えても良い値は何か
たとえば、メールアドレスを使ってログインするアプリにおいて、ユーザー作成後にメールアドレスを変えても良いのかというのは、検討が必要になります。締め処理が終わった売上データの金額や数量は変更不可とすることが多いですが、コメントやメモは追加可能かもしれません。
このように、変更ができないステータスになっていたり、他のデータと不整合があったりする場合は、操作を止める必要があります。
データの作成時と同じく、必要なチェック処理を実装し、エラーメッセージを表示したり、データの状態によってラベル表記に変えたりして、変更できないことをユーザーに伝えます。
更新対象のデータをどのように特定するか
データを1行だけ更新したいと思っても、誤って2行更新してしまうとシステムの誤作動につながります。
キー項目で更新対象を特定する場合は1行ずつ更新できるため問題ありませんが、複数行を更新対象とする際はどのように更新対象を特定するのかを、確実に特定できるようにしておく必要があります。
データの更新と同時に、何を登録・更新・削除する必要があるのか
データを更新できる状態であり、更新可能なデータが入力された場合は、実際に更新作業に入ります。
その際、入力された情報以外にも作らなければならないデータ・更新しなければならないデータがある場合は、同時に作成する必要があります。
データの作成時よりも、更新時の方が検討の漏れが発生しやすいです。
データの作成時は、まだデータがありません。そのため、システムを使えるようにすべてのデータを丁寧にそろえるという意識が強くなります。
それに対して、データの更新時は、すでにシステムが機嫌よく使えている状態です。その中でとあるデータの更新が影響する範囲を特定することになります。予想外の部分で影響が出て急に動かなくなることもあります。ほとんどのデータは機嫌よく動きますが、たまに動かないということもあります(このケースは、調査に時間がかかります)。
システム全体として不整合が発生しないように、何のデータをそろえる必要があるのかを考える時間をデータの作成時以上に取りましょう。
作ったデータを更新しながら都度参照していきました。
最後に待っているのは、そのデータの削除です。
4.データの削除(Delete)
削除には、大きく2種類あります。
- 物理削除
データをDBから物理的に削除(Delete)し、誰も見れなくなる状態にする方法。
残しておく必要のないデータや、古くなったデータの退役時に使われる削除です。 - 論理削除
物理的には削除をせず、削除したように見せる方法。削除フラグを立てて取得できないデータとしてマークをし、すべてのデータの取得クエリで対象外とすることで実現します。
マスタデータや、誤って削除してしまうことを防ぐときに使われる削除です。
まずは、データの削除をどちらで実装するのかを検討する必要があります。
たとえば、ユーザー情報を削除したいと考えている場合。売上情報に誰がその売上を上げたのか、担当者前を出していることは多いです。このような場合に、ユーザー情報を物理削除してしまうと、売上情報に担当者名が表示されなくなることがあります。データの取得方法によっては、売上情報そのものを取得できなくなることもあります。
このように、どちらの削除にするかはデータの性質によって変わります。誤って物理削除をしてしまって、データが見えなくなるし元に戻せなくなったということがないようにしましょう。
それでは、この点以外にデータの削除時に考えることは、どのようなことでしょうか。
いつ、データを削除するか
作成されたデータは、いつ削除されるのか、もしくはいつまでも削除されないのかを決める必要があります。
- ユーザーの操作によって削除されるデータ
- 作成から一定期間が過ぎると、削除されるデータ
- 法的に一定期間残しておく必要のあるデータ
ユーザーの操作による削除の場合は、リクエストでの削除となりますが、一定期間が過ぎたデータの削除は定期実行されるバッチ処理での削除となります。
いつ削除されるのかによって、実装する処理が大きく変わるため、注意が必要です。
データを削除しても良い状態になっているか
更新よりも削除の方が、複雑な判断ロジックになることが多いです。
- ステータスが少しでも進んでいたら削除できない
- 対象データに紐づく子どもデータやトランデータが1つでもある場合は削除できない
削除のリクエストがあるたびに、これらの状態を確認する必要があります。
更新と同タイミングで処理がなされることもあるため、排他ロックをどのテーブルでかけるのかを考える必要も出てきます。
削除対象のデータを、どのように特定するか
更新時と同じく、削除の場合も対象データをどのように特定するかは非常に重要です。
誤って別のデータを削除してしまうと、取り返しがつかなくなります。
また、一定期間経過後にデータを削除するという場合、削除対象の件数が大量になる場合もあります。その際に、データベースからレスポンスが返ってこなくなることを避けるために、対象データを小分けにして削除していく必要も生じます。
データの件数は、アプリの利用者が増えるにしたがって増えていくため、いずれレスポンスが無理になると言った作りにすることは極力避けましょう。
データの削除と同時に、何を登録・更新・削除する必要があるのか
関連するデータを一緒に削除することは当然として、削除と同時に操作ログを登録することもあります。
また、データを削除する順番も重要になります。
リレーショナルデータベースでデータを保持している場合は、テーブル間に参照制約が付与されている場合があるため、子テーブルのデータから削除していくことになります。
データの削除時は、他のデータの削除、更新、作成が複雑になることが多いです。1処理ずつ丁寧に見直しが必要になります。
まとめ
CRUDは、見積時に仕様を整理するための重要なフレームワークのひとつです。
何かのデータを作るという話になった時点で、必ず一度は検討する癖をつけましょう。
また、データを扱えるエンジニアはチーム内で重宝されます。システムの仕様のコアな部分を抑えられるようにもなります。
つまり、フリーランスとしては契約の延長にもつながりやすい業務範囲であり、抑えていきたい範囲だということです。
しかし、むやみに手を出してもいけない領域なのは明らかです。データが壊れると、最悪の場合システム全体が動かなくなります。
データを正しく扱えるエンジニアになるためにも、CRUDの視点からシステムを見れるようになりましょう。