Java
リファクタリング
DDD
OriginalTech FunDay 13

レガシーコードを段階的に改善する

この文章は「Tech Fun Advent Calendar 2017」13日目の記事です。

秩序がないプロジェクトをリファクタリングしていく中で、DDDを段階的に導入していったアプローチや感想についてです。

あるプロジェクトに参画した当初の状態

Java8でSpring Bootなプロジェクトですが、下記のようなコードでした。

  • コピペコードが多い。
  • 単体テストがない。
  • ControllerからServiceへ"Model"を渡しており、どのViewを表示するかはServiceが知っている。
  • ServiceにMyBatisの自動生成されたmapperを使ってDBアクセスがべた書きされている。
  • Serviceが、画面・機能に対応した、いわゆるトランザクションスクリプトになっている。

Controllerが機能していないというのはさておき、Serviceがトランザクションスクリプトになってしまっているというのは、わりとあるんじゃないかと思います。

なにが問題なのか?

変更に弱い。これに尽きます。ビジネスルールが変更されると横断的に変更が発生し、変更漏れがあれば当然バグとなります。テストも大変ですね。

最初のアプローチ

DDD以前の話ですが、チームメンバーと話し合い、問題認識を持つことが大事だと思っています。レイヤーを適切に分割し、テストを書いていきます。

レイヤーを分ける

コンポーネント 責務
Controller リクエスト、レスポンスのハンドリングを行う。
Service ビジネスロジックを記述する。ウェブの関心事をここに持ってくるのはだめ。永続化もここでやってはだめ。
Repository 永続化を行う。クエリ投げるのもここで抽象化して、ドメイン層ではコレクションとして扱う。インタフェースと実装は分ける。

ここから三層+ドメインモデルに持って行きます。

テストを書く

スケジュールとの兼ね合いもあり、実際は妥協してクリティカルなものを優先し、必要最低限の機能に絞って単体テストを書きました。

段階的にDDDを導入していく

変更に弱いコードとはどんなコードでしょうか?

データクラス、機能クラスを分ける手続き型の設計では、重複したビジネスロジックが至るところに書かれます。その結果、どこを変更すればいいのかわからなくなります。

逆に、変更に強いコードとはどんなコードでしょうか?

データとビジネスロジックがまとまったオブジェクト群(ドメインモデル)で構成されます。関心事単位に分離することで、どこを変更すればいいのかすぐわかります。

domain3layer.png
引用:現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法 三層+ドメインモデルで関心事をわかりやすく分離する

View、Serviceからドメインモデルを抽出していく

基本的には「業務に使っている用語をクラス名にする」のが良いと考えます。良いクラス名やメソッド名がないか常に考えることが肝要であって、思考停止するとレガシーコード化が進行します。
ドメインモデル駆動設計では、部分に着目し、個々の部品を組み合わせることで段階的に全体を作るアプローチができるため、DDDはすぐにでも導入可能であると実感しています。

参考書籍

DDD

最近は 現場で役立つシステム設計の原則 ~変更を楽で安全にするオブジェクト指向の実践技法 あたりから入門するのがおすすめです。

腰を据えて読む必要はありますが、下記も必読です。
エリック・エヴァンスのドメイン駆動設計
実践ドメイン駆動設計