ブログトップ 記事一覧 ログイン 無料ブログ開設

Strategic Choice

2016-07-28

[]デリート・フラグ・フォー・ナウ

デリート・フラグ・フォー・ナウ(Deleted Flag for now, とりあえず削除フラグ)

どういうこと?

【したいコト】

データを消さずに、残したまま「無い」ことにします。

【やらかしたコト】

論理削除で設計します。

テーブルに「削除フラグ」列を設けて、フラグが立っている場合を、論理的なレコード削除とみなします。レコードの削除SQLは、DELETE文ではなく、削除フラグをたてるUPDATE文になります。

f:id:asakichy:20160614174859p:image


どうしてヤル?

ユーザにはデータがなくなったように見せたいのですが、実際のデータは消したくない場合があります。

  • 削除したデータを検索したい
  • データを消さずにログとして残したい
  • 誤った操作をなかったことにして、すぐに元に戻したい

また、精神論ですが、本当に消していないと簡単に元に戻せる気がするので、なんとなく安心感があります。

どうしてダメ?

  • 検索条件が常に必要
    • 全件取得でも、WHERE句が必要になり、コードが削除フラグだらけになります。
  • 認識の齟齬を生みやすい
    • テーブルによって削除フラグがあったりなかったりすると、SQLにミスが生まれやすくなります。
  • 隠れたデータが存在
    • 削除フラグの立ったデータが、テーブルに隠れていることになります。
  • 削除要不要の検討機会の剥奪
    • 事実が消えるということはないので、削除そのものを許すことが誤りな場合もあります。
    • 論理削除は「削除してもよい」という暗黙の了解に思考を縛られます。

どうすれば?

以下の設計を検討します。


【削除日列】

論理フラグの列を、削除日にします。

生きている間はNULLで、削除されると、その削除された日付が記録されます。フレームワークの論理削除プラグインは、大体この方法をとっています。

f:id:asakichy:20160614174858p:image

論理フラグより情報は多いですが、NULLを使用しているので、インデックスが使えなくなります。


【ドメイン命名列】

論理フラグの列を、ドメインの言葉に変更します。さらに、初期値にマジックナンバーを利用します。

f:id:asakichy:20160614174856p:image

インデックスは使用できますが、やはり、論理フラグより情報が多いだけで、根本解決にはなっていません。


【状態列】

論理フラグの列を、状態列に変更します。フラグではなく、状態遷移と捉えるようにします。

f:id:asakichy:20160614174857p:image

レコードであらわされるデータの状態は、とても「削除」の一言では表せないからです。

  • 従業員は、削除されるわけではなく、解雇されたり、退職したりします。
  • 注文は、削除されるわけではなく、キャンセルされます。
  • 仕事は、削除されるわけではなく、完了します。

これらに加え、途中の「状態」もあるので、状態遷移と考えるのが正しい設計です。


【履歴テーブル】

元のテーブルからは削除しますが、別に履歴用のテーブルを作成し、そちらに移動します。

f:id:asakichy:20160614174855p:image


テーブル間の整合性は、トリガーを駆使して保ちます。ただし、テーブルの関連が複雑な場合には、処理もかなり複雑になります。


【削除再検討】

削除という行為そのものを、再検討します。なぜなら、事実は、本来、消えてしまうことに矛盾があるからです。

たとえば、データをキャンセルするなら、データを消すのではなく、「データをキャンセルするという新しいデータ」を追加します。こうすると、「事実」をすべて記録することができるようになります。

データが増え続けることになりますが、パフォーマンスは別の問題で、別の観点(物理)から解決できます。

名前の由来

居酒屋の最初の注文(「とりあえずビール!」)のように、あまり考えることなく、まずはこれからという意味で「論理削除」の設計を選んでしまうことから、「とりあえず削除フラグ(デリート・フラグ・フォー・ナウ)」と名付けられました。

教訓

「とりあえず」と思考停止しないで、そのデータの「削除」が意味するところについて、よくよく検討しましょう。

出典

参考

2016-07-27

[]サンドキャッスル

サンドキャッスル(Sandcastle, 砂の城)

どういうこと?

【したいコト】

サービスを安定稼働させます。

【やらかしたコト】

どのようなことが起きるかという想定と、それぞれの事象への対策を、事前に十分に検討していません。

どうしてヤル?

世を見渡すと、データ消失やデータ漏洩によって甚大な被害がもたらされるインシデントが度々発生しています。ただ、それは対岸の火事で、自分の身には決して起こらないと、高を括ります。

どうしてダメ?

今日では、様々なサービスが24時間365日連続稼働を前提としています。

基幹系業務は、元々無停止が基本です。しかし最近では、無料のWebサービスですら無停止が当たり前のように求められます。サービスを提供する側にとって、サービスの停止は収益の減少に直結するからです。

また、たとえ無料のサービスであっても、データが消失すれば信頼が大きく失墜し、サービスが停止すればユーザーが離れてしまうといった懸念があります。

どうすれば?

コンピュータシステムにおいて安全神話はありません。サービスを安定稼働させるには、トラブルは当然起きるものとして想定しておく必要があります。そして、想定しただけでは不十分で、実際に事象が起きたとき、どのような対応をするべきかといった事前検討も必要です。

どのような種類の問題が起きるかという点について網羅的に想定するため、過去起きた事例にあたるようにします。事象に応じて自動的にサービスを継続させる仕組みや対応手順を決めておくことで、被害が最小限に抑えられます。

意外と行われていないのが、性能問題や障害が起きた時の対処をどうするかというポリシーの策定です。そういった問題に対処するには、種々の分析用データが必要となります。ただ、データの採取をおこなうと、運用中のシステムに対してディスクスペースやオーバーヘッドといった負担がかかるというジレンマがあります。そのような場合、「どこまでのデータ採取なら許容できるか」をあらかじめ決めておくと、問題にスムーズに対処できます。万一、トラブルシュートの中で、採取していないデータが必要になってしまったら、潔く原因の究明を諦めて、回避策に注力します。

また、データ採取やリカバリ処理などは、日頃から訓練しておきます。実際にやってみると、手順を間違ったり想定以上の時間がかかったりします。訓練により、このような問題を事前に洗い出すことができます。被害の拡大を防ぐための訓練は、決して無駄なことではありません。


サービスの運用を始めるにあたって実施・想定しておくべき代表的な対策には、以下のようなものがあります。

  • ベンチマーク
    • 事前にどの程度まで処理が可能なのかということをベンチマークしておきます。
    • その際、現実に即したシナリオで、実際と同程度のデータ量で、実際と同じ環境で行うようにします。
  • テスト環境
    • 運用時の問題の切り分けに役に立ちます。
    • その際、本番に極力近い環境が望ましいです。
  • 例外処理
    • アプリケーションで、どのような例外処理が発生しうるかを想定して、対策します。
  • バックアップ
    • データ破壊リスクに備える、最後の生命線です。
  • 高可用性
    • マシンの故障からは逃れられないので、冗長化しておきます。
  • ディザスタリカバリ
    • マシン単体を超え、自然災害時などの、データセンターないしはサイト全体の障害も想定します。
  • 運用ポリシーの策定
    • すべての想定事象を超えた事象が発生したときのポリシーを決めておきます。
    • 「高可用性の限界を超えた障害」「問題発生時の調査」「性能の劣化」などが考えられます。

名前の由来

さまざまなトラブルを想定していないシステムは、砂で作った「崩れやすい」「脆い」お城にすぎないというところから、「サンドキャッスル(砂の城)」と名付けられました。

教訓

どれだけ盤石な基盤を築けるかは、どれだけのインシデントを想定しているかが鍵になります。

2016-07-26

[]マジックビーンズ

マジックビーンズ(Magic Beans, 魔法の豆)

どういうこと?

【したいコト】

モデル・ビュー・コントローラー(Model-View-Controller, MVC)の「M(モデル)」を単純化します。

【やらかしたコト】

モデルをアクティブレコードそのものにします。たとえば、アクティブレコードのクラスを継承してモデルを作成します。

どうしてヤル?

アクティブレコードは、良く知られているデータアクセスパターンの1つです。多くのWebアプリケーションフレームワークで、データアクセスオブジェクト(DAO)設計として採用されています。

アクティブレコードは、1レコード1オブジェクトで管理します。そのオブジェクトはレコードの「追加」「読込」「更新」「削除」(いわゆるCRUD操作)機能を持っています。

アクティブレコードは、単一テーブルの各行に対するシンプルなインタフェースを提供してくれる、優れたパターンです。アクティブレコードそれ自体に問題はありません。

どうしてダメ?

  • モデルがデータベースに強く依存
    • データベースの変更がモデルに波及し、勢い、モデルを使っている部分にも波及します。
  • モデルがデータベースCRUDを公開
    • アクティブレコードを継承してモデルを作ると、勢い、CRUDも外部に公開されてしまいます。
  • モデルがドメインモデル貧血症を発症
    • モデルをシンプルなデータアクセスオブジェクトとすると、勢い、モデルの外部でビジネスロジックが必要になります。
  • 各ユニットテストが困難
    • MVCがうまく分離されていないと、勢い、どの部分のユニットテストも難しくなります。

どうすれば?

モデルがアクティブレコードを「持つ」ようにします。

MVC本来の意味合いにおけるモデルとは、オブジェクト指向によって、対象ドメインをアプリケーションの中に表現することです。すなわち、アプリケーションのビジネスルールと、ビジネスルールのためのデータです。モデルは、アプリケーションのビジネスロジックを実装する場所です。データベースとのやりとりは、モデルの内部的な実装の詳細なのです。

データベースの構造ではなく、アプリケーションの概念に基づいてモデルを設計すると、データベースの操作をモデルクラスに完全に隠蔽して実装できるようになります。そのために、アクティブレコードをモデルとするのではなく、モデルが手段としてアクティブレコードを持つような設計とします。

名前の由来

童話「ジャックと豆の木」において、ジャックは、魔法の豆が一晩で巨木になるのを信じて眠りにつきます。しかしこれはおとぎ話にすぎません。フレームワークを信じて規約に従っていれば、まるで魔法のようによい設計になる、と盲目的に信じてしまうところから「マジックビーンズ(魔法の豆)」と名付けられました。

教訓

モデルはテーブルから分離させましょう。

関連

2016-07-25

[]ディプロマティック・イミュニティ

ディプロマティック・イミュニティ(Diplomatic Immunity, 外交特権)

どういうこと?

【したいコト】

ソフトウェア開発のベストプラクティスを採用します。

プロのソフトウェア開発者は、以下のようなソフトウェアエンジニアリングのベストプラクティスに努めて従おうとします。

  • 構成管理ツールを用いて、ソースコードのバージョン管理を行います。
  • ユニットテストや機能テストを自動化します。
  • 「ドキュメント」「コードコメント」を書き、要件や実装戦略を記録します。

ベストプラクティスの実践に投じた時間は、極めて大きな見返りをもたらします。多くの不要な仕事や繰り返し作業を減らしてくれるからです。経験ある開発者は、このベストプラクティスを怠るとプロジェクトが失敗に向うことを知っています。

【やらかしたコト】

SQLを特別扱いして、ベストプラクティスから外します。

アプリケーションコードの開発ではベストプラクティスを受け入れる開発者であっても、データベースコードではこれらの慣行が免除されると考える傾向があります。

どうしてヤル?

SQLが特別扱いされるのは、通常のアプリケーションコードとは異なる、いくつかの事情があります。

  • ソフトウェアエンジニアの役割とデータベース管理者(DBA)の役割が別です。
  • アプリケーションの言語とデータベースの言語(SQL)が別です。
  • 統合開発環境にSQLが統合されていません。
  • 少数のデータベース管理者が制御権を握っています。

どうしてダメ?

データベースはアプリケーションの屋台骨であり、その品質はアプリケーションと同等に重要です。

高品質のアプリケーションコードを開発する方法を知っていたとしても、SQLを特別視してしまったら、その部分の品質は担保されません。アプリケーションが依存するデータベースが、プロジェクトのニーズを満たさず、誰も理解していない代物になる可能性もあるのです。せっかく良いアプリケーションを開発しても、プロジェクトがデータベースのために失敗するかもしれません。

どうすれば?

ソフトウェア開発者の多くにとって、品質とは単にテストを行うことを意味します。しかし、これは「品質管理(Quality Control:QC)」に過ぎません。大きなストーリーの一部でしかないのです。

ソフトウェアエンジニアリングのライフサイクルは「品質保証(Quality Assurance:QA)」を伴います。品質保証は3つの部分から成り、これらをすべて行う必要があります。

  • プロジェクト要件の明確な定義・文書化
  • 要件に対する解決策の設計・構築
  • 解決策が要件を満たしていることの確認・テスト(ここが「品質管理」)

そして、データベース開発における品質保証は、以下のベストプラクティスに従うことで達成できます。

  • 文書化
  • テスト
  • バージョン管理

名前の由来

「アプリケーション開発のルールは、データベース開発には当てはまらない」というような、データベースには「特権的な何か」があるという考えを、治外法権などの外交特権になぞらえて、「ディプロマティック・イミュニティ(外交特権)」と名付けられました。

教訓

アプリケーションと同じく、データベースに対しても、ソフトウェア開発のベストプラクティスを適用し、文書化、テスト、バージョン管理を行いましょう。

2016-07-22

[]シー・ノー・エビル

シー・ノー・エビル(See No Evil, 臭いものに蓋)

どういうこと?

【したいコト】

簡潔なコードを書きます。

【やらかしたコト】

肝心な部分を見逃します。これには2つのパターンがあります。

  • コードを書くとき、データベースAPIの戻り値を無視します。
  • コードを読むとき(デバッグのとき)、アプリケーション内の断片的なSQL(完成していないSQL)しか読みません。

どうしてヤル?

開発者は「エレガントなコードを書きたい」と考えています。すなわち、「少ない」コードで、「クールな」仕事をしたいのです。少ないコードを志向するのには、合理的な理由があります。

  • より短い時間でアプリケーションのコーディングを行えます。
  • テスト、文書化、ピアレビューの対象となるコードの量が減ります。
  • バグが混入する可能性も少なくなります。

このため、開発者は(ほとんど本能的に)不要(だと自分では思った)コードをできるだけ書かないようにします。特に、それがクールではないと感じられる場合に顕著です。

どうしてダメ?

戻り値を無視する限り、問題に気づくことはできません。

開発者は、戻り値や例外のチェックのために、自分のコードに手を加える必要はないと考える傾向があります。起こるはずがないと考えているためです。また、例外処理のために追加すべきコードはよく似た繰り返し作業が多く、アプリケーションを汚く、読みにくくするとも考えています。クールではないというわけです。しかし、この情報を無視する限り、問題に気づくことはできません。

SQL文字列を組み立てている、アプリケーションコード側からデバッグを開始すると、問題に気づきにくくなります。

SQL文字列はアプリケーションロジックや文字列連結、アプリケーション変数の中身などから構築されるため、最終的な構築結果を思い浮かべるのは難くなります。構築されたSQLそのものではなく、SQLを構築するコードを調べることによって、デバッグに驚くほど多くの時間とエネルギーを浪費してしまうのです。

どうすれば?

データベースAPI呼び出しの戻り値と例外のチェックを行います。これは、処理にミスがないことを保証するための最善策です。データベース接続時やSQL文実行時に都度行うようにします。

デバッグでは、SQLクエリを構築するコードではなく、実際に構築されたSQLクエリを見るようにします。綴り間違いや括弧の不一致など、コードではわかりにくく不可解になりがちな、多くの単純なミスを簡単に発見できます。

名前の由来

開発者である以上、美しいコードを書きたいと思うのは自然なことです。しかし、特に例外処理は煩雑になりがちで、デバッグ作業も泥臭くなりがちです。「クール」ではないので、避けられるのであれば、避けたいところです。

このように、醜い(見難い)部分は見て見ぬふりをして、根元的な解決を後回しにしているところから、「シー・ノー・エビル(臭いものに蓋)」と名付けられました。

教訓

コードのトラブルシューティングは、それだけで十分に大変な作業です。闇雲に進めても、作業を遅らせるだけです。