レガシーの複雑さに立ち向かう
ドメイン駆動設計のアプローチ
2019-6-1
ギルドワークス 増田 亨
Legacy Code Meetup Kagoshima 2019
ドメイン駆動設計でなぜつくるのか?
22019/6/1
進化を続けるソフトウェアを手に入れる
ソフトウェアの変更を楽で安全にする
2019/6/1 3
この価値観に振り切っている
リリース後、あまりコードを変えない/変えられない、という世界とは別のアプローチ
ドメイン駆動設計の考え方
2019/6/1 4
ソフトウェアの核心にある
複雑さに立ち向かう
2019/6/1 5
核心にある複雑さ
2019/6/1 6
ここに焦点を合わせて集中する
その効果が、全体の構造の改善に波及する
ソフトウェアの複雑さは
ビジネス活動の複雑さに由来する
ビジネスルール:ビジネスの活動を駆動し、制約する約束事
ドメインロジック:ビジネスルールをコードで表現したもの
ドメイン駆動設計の考え方
2019/6/1 7
中でもビジネスルールの複雑さが
ソフトウェアの複雑さの根本原因
核心にある複雑さを
適切に扱う
核心と周辺との
依存関係が明確になる
全体の構造の
改善に波及する
周辺の
複雑さが軽減される
2019/6/1 8
ビジネスルールの複雑さ
核心にある複雑さをどう扱うか?
2019/6/1 9
ビジネスルールの複雑さ
核心にある複雑さ
に立ち向かう
ビジネスの活動を
継続的に学ぶ
モデルと実装を
密に結合する
ドメイン層を
独立させる
コアドメインに
集中する
システム間の秩序の
改善を続ける
ビジネスを
深く洞察する
ビジネスルールの複雑さ
2019/6/1 10
レガシーコードの改善に
ドメイン駆動設計は役に立つか?
2019/6/1 11
即効性はない
2019/6/1 12
じわじわ効いてくる
2019/6/1 13
レガシーコード
2019/6/1 14
どこに何が書いてあるか、わかりにくい
ひとつの修正が、あちこちに影響する
変更が障害を引き起こす
2019/6/1 15
変更がやっかいで危険
2019/6/1 16
ドメイン駆動設計のアプローチで
レガシーに立ち向かってみた
2019/6/1 17
心の準備
手がかりを
見つける
区分値の
調査と分析
導出項目の
調査と分析
中核を見極める
中核だけを
実装してみる
複雑さの核心に
メスを入れる
アプリケーションを
組み立てなおす
2019/6/1 18
こころの準備
2019/6/1 19
✓ありがちな設計
➢トランザクションスクリプト(入出力機能単位のモジュール)
➢バッチ処理によるつじつまあわせ
➢テーブルは更新可能なデータファイル(重複と不整合)
✓ありがちな状況
➢設計や分析の資料はない/あっても古くてコードと一致していない
➢命名規約は、番号重視 and/or 省略重視 ( KBN01 )
➢使われていないロジック、データ、区分が混在
✓最初から、こういうもんだと思って取り組む
➢期待しない
➢恨まない
2019/6/1 20
手がかりを見つける
2019/6/1 21
✓実データ、実画面、実帳票、実ファイル
➢実際に使われているデータ(事実の記録)が最大の手がかり
➢プログラムの意図は、コードからは読み取りにくい
そういう設計のスタイルだから
コードは意図の表現ではなく、データ処理手続きの表明
✓目のつけどころ
➢区分値 ビジネスルールの複雑さの源泉(if文, switch文)
➢導出項目 ビジネスルールに基づいた計算や判定の結果
2019/6/1 22
区分値の調査と分析
2019/6/1 23
✓コードに書かれたif文やswitch文と格闘する前に、
区分体系を徹底的に調査する
✓データベースの区分カラム
➢GROUP BY 句で、実際のデータ内容の確認
➢区分によって、使うカラム/使わないカラム、意味の異なるカラムの特定
✓画面の区分表示、区分選択ボックス
➢データベースの区分カラムとの対応
➢業務的な使い方の確認
2019/6/1 24
導出項目の調査と分析
2019/6/1 25
✓導出項目の特定
➢ビジネスルールにもとづいた計算や判定の結果
金額、数量、期日、場所、区分、…
➢画面に表示された導出項目
➢データベースに記録された導出項目、導出レコード
✓導出ルール(計算ルールや判定ルール)を調べる
➢業務マニュアル/利用ガイド/料金表 …
➢ソースコード
➢ヒアリング(ありえないデータ、ありえない結果を判断できる人)
2019/6/1 26
中核を見極める
2019/6/1 27
✓導出のロジック(計算式とif文/switch文)に焦点を合わせる
✓単なるデータの記録と参照は、ばっさりスコープからはずす
➢データベースは、計算と判定に使う項目の記録のみを対象にする
➢画面も、計算と判定に使うための入力と、導出結果のみを対象にする
✓ソースコード中の、導出ロジックの記述場所を特定する
➢区分値を使った if文/swtich文
➢if文/switch文の評価式の値を算出している個所
2019/6/1 28
中核だけを実装してみる
2019/6/1 29
✓データベース
➢導出に使うデータと、導出結果の記録に絞り込んだデータベースを用意する
➢FACTを正しく記録するためのテーブル群を新規に設計
イミュータブルデータモデル
データベース制約を徹底する
特に NOT NULL 制約
➢現行のデータベースから必要なFACTデータを複製する仕組みづくり
✓導出ロジックのプログラミングと検証
➢FACT駆動で作成した新データベースを使って、必要な計算と判定ができるプ
ログラムを開発する(UIは作らない)
➢計算結果・判定結果を、既存データベースの該当カラムと突き合わせる
2019/6/1 30
複雑さの核心に切り込む
2019/6/1 31
✓既存の区分体系
➢未使用の区分
➢今となっては意図が不明な区分
➢複数の区分軸の混在
✓区分体系の整理
➢未使用を使わない
➢意図不明もいったん使わない
➢明らかな例外を、事前処理で除外する
➢残った区分を論理的に分解してみる
2軸か3軸の組み合わせになっていることが多い
すべての組み合わせが網羅されていないことが多い(その理由を分析する)
2019/6/1 32
アプリケーションを組み立てなおす
2019/6/1 33
✓中核は手に入った
➢FACTを記録したテーブル群(と実データ)
➢FACTを使った導出プログラム(計算モデル)
➢論理的に整理しなおした区分
➢それらを使った計算サービスや判定サービス
✓中核と画面や外部インタフェースをつなげる
➢選択肢1:中核に合わせて、画面や外部インタフェースを作り直す
➢選択肢2:既存の画面モジュール/外部接続モジュールから中核を呼び出す
✓記録して参照するだけのデータ群の扱い
➢選択肢1:中核の周辺に追加する
➢選択肢2:既存の処理にまかせる
2019/6/1 34
心の準備
手がかりを
見つける
区分値の
調査と分析
導出項目の
調査と分析
中核を見極める
中核だけを
実装してみる
複雑さの核心に
メスを入れる
アプリケーションを
組み立てなおす
2019/6/1 35
手ごたえは十分だった
このやり方を積み重ねれば突破できそうな自信はあった
まわりの理解を得ることに失敗した
チーム内での試行錯誤に集中しすぎた
2019/6/1 36
もう一回やれば、段取りや作業の見通しを事前に説明し、
進捗状況を適宜、報告することはできそう
一方で、短期的で劇的な効果は望めない
そこの同意を取り付けるのは難しいかもしれない
2019/6/1 37
いちばんの成果は、開発者のビジネス理解が進み
コードやデータの全体の見通しが改善したこと
数量化・可視化は難しいが
もう一度やるなら
やはり、このアプローチでやりたい
2019/6/1 38

レガシーコードの複雑さに立ち向かう~ドメイン駆動設計のアプローチ