あるツール的なWEB APIを作っていたのですが、
テーブルを定義していて、いつものようにCreatedAt、UpdatedAt、などを作っていました。
わたしはこのやり方はあまり好きではなく、テーブルにいつ誰が作ったか、更新したかを見るのであれば、ログに残せばいいと考えています。
しかしながら、ある現場でCreatedAt、UpdatedAt、CreatedUser、UpdatedUserのようなカラムを全テーブルに持っているプロジェクトがあったので、今回はそれに倣ってやってみようと気軽に考えて、コードの生成をAIにお願いしてみました。
わたしはVSC+Geminiの組み合わせでやってますが、いつものようにGemini君はReadme.mdに書かれた通りの仕様で大体一発でコードを生成してくれました。
で、気になったのがこれ
-- updated_atを自動更新するためのトリガー
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';
CREATE TRIGGER update_products_updated_at
BEFORE UPDATE ON products
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
ようするにトリガーでupdated_atにNOWを設定するトリガーを作り
productsのUpdateがあった際に動くようにしているという点です。
これを見たときに、INSERTではトリガーが動かないなと思ったのですが、INSERT時には、テーブル定義でDEFAULT CURRENT_TIMESTAMPが設定されているため、Created_AtもUpdated_Atも同じ時刻が入ります
で、実際更新するときは、管理画面的なところから更新するのでしょうが、
その際は、トリガーが動いて更新日付が更新されるという挙動になります。
更新する際にプログラム側から日付を入れればいいじゃんと思うのですが、トリガーとして動く仕組みのいいところ悪いところをAIに聞いてテーブルを作ってもらいました
観点 | データベースのトリガー | アプリケーション側のロジック |
---|
データ整合性 | ◎ 非常に高い (更新漏れがない) | △ 低い (更新漏れのリスクがある) |
保守性 | ○ (ロジックが一元化) | △ (コードが分散・重複する可能性) |
DB独立性 | △ (DB製品に依存) | ◎ 高い (DBに依存しない) |
可視性 | △ (コードからは見えない) | ○ (コードで明示的に記述) |
パフォーマンス | ○ (ほぼ影響なし) | ◎ (トリガーのオーバーヘッドがない) |
結論として、created_at
やupdated_at
のようなメタデータの管理には、データベースのトリガー(またはDEFAULT
やON UPDATE
句)を使用するアプローチが強く推奨されます。
データの整合性を担保できるというメリットは、他のデメリットを大きく上回ります。現在のプロジェクトの実装は、このベストプラクティスに従っており、非常に堅牢な設計と言えます。
ぶっちゃけですね、アプリケーション側でやった方が◎が多いんです
しかも△の数も同じです
これでなぜAIがトリガーを強く推しなのかというと、データの整合性の◎はちょっとレベルが違うくらいな◎だということらしいです。
なお、このようにPros/Consをまとめて、同じレベルのものはPros/Consから削除するという手法は、フランクリンがやっていた手法です
まぁ納得いかない人もいるし、別の考えの人もいることでしょう
わたしはモヤッてます