開発・技術選定

Django の管理画面を Flask で再現する — 大規模リプレイスで考えたこと

既存サービスのリプレイス案件で、管理画面一式を Django 以外のフレームワークで
再現する必要が出ました。Django admin の便利さを痛感した仕事でした。

Django admin が実際にやってくれていること

移植して初めて分かりますが、admin は次を全部やっています。

  • モデル定義からのフォーム自動生成とバリデーション
  • 一覧の検索・絞り込み・並び替え・ページング
  • 権限(モデル単位・オブジェクト単位)
  • 変更履歴(誰が・いつ・何を)
  • 外部キーの選択UI(オートコンプリート含む)

これを手で書くと、素直に作れば数か月かかります

全部は作らない、と決める

最初にやったのは機能の棚卸しでした。実際の管理画面の利用ログを見ると、
使われている画面は全体の3割程度でした。

  • 毎日使う画面 … 作り込む
  • 月1回の画面 … 最低限のCRUDだけ
  • 1年間アクセスなし … 作らない(必要になったら追加)

「Django admin と同じものを作る」ではなく
実際に使われている操作を作る」に目標を置き換えたのが最大の判断でした。

共通化した3つの部品

1. 一覧のクエリ生成

検索・絞り込み・並び替え・ページングは、どの画面でも同じ構造です。
宣言的に書けるようにしました。

LIST_CONFIG = {
    "users": {
        "search": ["name", "email"],
        "filters": ["status", "plan"],
        "order": ["-created_at"],
    },
}

2. フォームの自動生成

モデルのカラム定義から入力欄を組み立てます。
型ごとのウィジェットと必須チェックだけでも、手書きの量が激減しました。

3. 監査ログ

これは最初から必須にしました。
誰が・いつ・どのレコードを・どう変えたかを全操作で残します。

def log_change(user, obj, action, before, after):
    AuditLog.objects.create(
        user=user, model=obj.__class__.__name__, object_id=obj.pk,
        action=action, diff=json_diff(before, after),
    )

管理画面は権限の強い人が触るので、ここが無いと事故の追跡ができません。

複数DBを跨ぐときの注意

参照系が複数DBに分かれている構成では、トランザクションが跨げません
「片方だけ書き込まれた」状態が普通に起こります。

対処は2つでした。

  1. 書き込みは可能な限り1つのDBに寄せる
  2. どうしても跨ぐ場合は、後から突合できるように相関IDを持たせる

分散トランザクションを自前で作るのは、規模に対して割に合いませんでした。

開発環境をローカルで完結させる

AWS 依存のまま開発すると、全員が同じクラウド環境を共有して事故ります。
ローカルでエミュレートできる仕組みを入れ、
開発者が1コマンドで環境を立ち上げられる状態にしました。

これは移植そのものより、チームの速度に効きました。

まとめ

  • admin 相当を全部は作らない。使われている画面を実測して決める
  • 一覧・フォーム・監査ログの3つを共通部品にすると量が激減する
  • 複数DBを跨ぐトランザクションは諦め、寄せるか突合できるようにする
  • ローカルで完結する開発環境が、移植作業そのものより効く