「SQLアンチパターン」を読んで【第Ⅳ部】

書籍

SQLアンチパターン

SQLアンチパターン

はじめに

読んだ書籍は1記事にまとめると文量が多くなるため、導入+各部ごとの記事としてまとめる。

本記事は「第Ⅳ部:アプリケーション開発のアンチパターン」になる。その他の部についての記事は下記参照。

印象に残った点

※ 下記のカッコ書きは該当する章番号。

リーダブルパスワード(読み取り可能パスワード)[19]

- 目的:パスワードのリカバリーとリセットを行う
- アンチパターン:パスワードを平文で格納する
- アンチパターンを用いてもよい場合
  - 少人数が使うイントラネットのアプリケーション
- 解決策:ソルトを付けてパスワードハッシュを格納する
  • 前に読んだ本も認証のためにソルト使ってた。ソルトを使うことが最低ラインなのかもしれない。
  • パスワードのハッシュ化はなるべくユーザに近い箇所でやるべきなのか。その通りだと思った。

SQLインジェクション[20]

- 目的:動的SQLを記述する
- アンチパターン:未検証の入力をコードとして実行する
- アンチパターンを用いてもよい場合
  - 正当化する理由はない
- 解決策:誰も信用してはならない
  - 状況に応じて以下技法を適切に使い分ける
    - 入力のフィルタリング(無効な値を事前除去)
    - プリペアドステートメントを用いる
    - 動的値を引用符で囲む
    - ユーザの入力をコードから隔離する(マッピングする)
    - レビューしてもらう
  • プリペアドステートメントだけで良いと思っていたがそれだけでは駄目なのか。
    • 状況に応じ、入力値のフィルタリングやマッピングなど様々な引き出しを使えるようにならないといけないなぁ。
  • レビューも効果的に使う必要があるのか。それなりのスキルがないと効果的なレビューにならないなぁ。

シュードキー・ニートフリーク(疑似キー潔癖症)[21]

- 目的:欠番を詰める
- アンチパターン:隙間を埋める
  - 欠番を埋める(欠番を探すクエリは不要な自己結合が必要)
  - 既存行に番号を振り直す(Updateするため競合状態を引き起こしやすい)
- アンチパターンを用いてもよい場合
  - 正当化する理由はない
- 解決策:疑似キーの欠番を埋めない
  - 疑似キーは行番号ではないため連続している必要はない
  - GUIDを使用する
  - 上司を管理する(技術やコストについて説明)
  • 疑似キーはあくまで擬似的なキーなのに欠番を埋める意味ある?と思っていたが、解決策は自分の考えと同じだった。
    • 行番号と同じだと思う人もいることを認識しておかないといけないなぁ。
  • GUID使えるベンダー製品あるのか!!GUIDであれば欠番を意識することないのでメリットもあるなぁ。

シー・ノー・エビル(臭いものに蓋)[22]

- 目的:簡潔なコードを書く
- アンチパターン:肝心な部分を見逃す
  - 戻り値を無視する
  - 実行するクエリをログ等に残さない
- アンチパターンを用いてもよい場合
  - close関数でエラーを返してもその後アプリが終了する
  - 処理の責任がないので例外を無視する
- 解決策:エラーから優雅に回復する
  - 戻り値と例外をチェックする
  - 実際に構築されたSQLクエリを出力する
  • これは当たり前にやってるのでは?と思った。戻り値や例外を握り潰すのはアカンでしょ。
  • 昔保守していた製品はSQLクエリをログに出していなかったので調査が辛かったことを思い出した。痛みを知ってるから当たり前と思っているのかもしれない。

プログラマティック・イミュニティ(外交特権)[23]

- 目的:ベストプラクティスを採用する
- アンチパターン:SQLを特別扱いする
  - アプリケーション開発のルールをデータベース開発に当てはめない
- アンチパターンを用いてもよい場合
  - 1度きりの利用だと割り切れる(利用したら躊躇わず消せる)
- 解決策:包括的に品質問題に取り組む
  - 文書化/バージョン管理/テスティングを行う
  • アプリケーションコードの文書化の価値は低いが、データベースの文書化には価値があると述べる人達もいるのか。
    • 今保守している製品はこの考えに近い。アプリ観点であればアンチパターンになるケースは少ない気がする。
  • StackOverflowのPodcastあるのか!知らなかった。
  • テーブル定義はバージョン管理しているけど、ER図や関連の説明が弱いんだよなぁ。やっぱ欲しいよなぁ。
  • DBに関するテストもやるのか。確かにやったほうが良い。

マジックビーンズ(魔法の豆)[24]

- 目的:MVCのMを単純化する
- アンチパターン:モデルがアクティブレコード(魔法の豆)そのもの
  - アクティブレコードはモデルをデータベーススキーマに強く依存させてしまう
  - アクティブレコードはCRUD機能を公開してしまう
- アンチパターンを用いてもよい場合
  - テーブルの各行を操作するだけのシンプルなアプリ
  - 素早くコードを書くプロトタイプ作成(技術的負債を生むリスクはある)
- 解決策:モデルがアクティブレコードを「持つ」ようにする
  - ドメインモデルの使用(DB操作をモデルクラスに完全に隠蔽する)
  • アクティブレコードはシンプルなアプリであれば良いが、複数のテーブルを使うとなるとスパゲティ化してしまうリスクは確かにありそう。
  • ドメインモデリングの能力も高めたくなった。

砂の城[25]

- 目的:サービスの安定稼働
- アンチパターン:想定不足
- アンチパターンを用いてもよい場合
  - コストとのトレードオフで許容する
- 解決策:トラブルを「当然起きる日常的なもの」として捉える
  - ベンチマークを取る
  - テスト環境を用意しておく
  - 適切な例外処理を実装する
  - バックアップを取る
  - ディザスタリカバリを考慮する
  - 運用ポリシーの作成
  • 問題かサービスへ及ぼす影響が軽微であれば、自動的にトランザクションをリトライして問題を無視することも視野に入れることは大事なのかもしれない。
    • 保守していて思うのは、全てを完璧にする(=何も問題がない)ことは不可能だと感じるので、重要度に応じた対応を意識したい。
  • リスクマネジメントをちゃんとやりましょう!ということだろう。リスクの想定が甘いと問題になりますよね…