もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

現場で役立つシステム設計の原則を読書中 5〜7章

はじめに

こんばんは。

現在 現場で役立つシステム設計の原則 という本を読んでおります。

前回

kojirooooocks.hatenablog.com

読んだ感想を備忘録で残しておきます。

今回は5〜7章までです。

本題

5 章 アプリケーション機能を組み立てる

ドメインオブジェクトを使って機能を実現する

アプリケーション層(サービスクラス)の見通しが悪く習いなための重要なtipsは以下

  • 業務ロジックは、サービスクラスに書かずにドメインオブジェクトに任せる(サービスクラスで判断/加工/計算しない)
  • 画面の複雑さをそのままサービスクラスに持ち込まない
  • データベースの入出力の都合からサービスクラスを独立させる

一番気をつけないといけないことは、足りない業務ロジックを安易にサービスクラスに書かないこと。

ドメインオブジェクトを追加・修正して足りない業務ロジックをドメインモデルに集約させること。

1つのドメインオブジェクトが複数のサービスクラス(複数の業務機能)から利用されているのは、コードの重複を防いでいる良い傾向です。 逆にドメインオブジェクトの変更が、業務的なつながりと異なるサービスクラスに影響が出た場合は、ドメインオブジェクトの設計に問題がありそうです。

1サービスクラス1ドメインオブジェクトみたいな実装を考えていると失敗するという感じ。

画面の多様な要求を小さく分けて整理する

これよくやっちゃう。

画面からの様々な要求に対して、小さな単位に分けてそれを組み合わせていくことが重要。

分ける基本として、登録系と参照系のサービスを分ける。

分けたサービスをドメインモデルの外で組み立ててしまうと 業務の手順 という業務知識がドメインモデルの外に 染み出してしまう

そのために、分けたサービスをつなぎ合わせて機能を組み立ててつかう、サービスクラスをドメインモデル内に作成する(本の例では Senario)

サービスを利用する側と、サービスを提供する側とで、サービス提供の約束ごとを決め、設計をシンプルに保つ技法を契約による設計と呼びます。

本の例では、口座の残高を更新する withdraw が実行されたさい、 残高更新が行えるかどうかを確認する canWithDraw を実行して falseの場合は Exceptionが投げられている。

サービスを提供する側の残高更新Senarioは、呼び出されるときは 残高更新が行えること が約束毎になっている。

データベースの都合から分離する

「記録」という業務の関心事を、INSERTというデータベース操作に、開発者が頭の中で変換してしまう結果、プログラムの記述から業務の意図が消えてしまいます。

この文刺さった。

たしかにINSERTやUPDATEをするときは、その操作に頭がいっていて、そのコードを業務の関心事として捉えていないかもしれない。

またリポジトリの説明でも良い文があった。

リポジトリは、INSERT文やSELECT文の実行に業務的な名前をつけただけの存在ではありません。 データベース操作の詳細を、サービスクラスに意識させない工夫です。

自分が以前、ドメインを意識して書いたコードを見てみると、データベース保存の都合に、振り回されているようなコードがあった。

サービスクラスにはそれは知らなくていいことだ。

勉強になった。

6 章 データベースの設計とドメインオブジェクト

テーブル設計が悪いとプログラムの変更が大変になる

データベース設計をすっきりさせる

テーブル設計や制約の話。

僕も以前20〜30カラムあるテーブルで、何の制約もなくすべてtext型というテーブルに対面したことがあり、絶望した経験ある。

データベースも最初の設計が大事。

コトに注目するデータベース操作

記録の変更を禁止する という考え方が面白かった。

  • 元データ
  • 取り消しデータ
  • 新データ

という感じで3つの記録を残すようにすれば、変更は起きずすべてINSERTになる。

参照をわかりやすくする工夫

状態を更新するテーブルはコトの記録からいつでも再構築可能な二次的な導入データ

logテーブルとか作るけど、どちらかというと更新テーブルのほうが重要で捉えてたところがあるので、ちょっと考えを改めようと思った。

また 残高更新は同時でなくてよい というのも面白かった。

更新するテーブルは再構築可能な二次的なテーブルという捉え方をしていたら、たしかに、更新テーブルの更新に失敗したらコトの記録も巻き戻すというのはおかしいとわかった。

オブジェクトの設計とテーブルの設計

オブジェクトはオブジェクトらしく、テーブルはテーブルらしく

業務ロジックはオブジェクトで、事実の記録はテーブルで

自分も書いているときに、ドメインオブジェクトとテーブルが1:1でつながっているような設計になっちゃうときがある。

ただ、やはりそこは似ているだけであって同じものではないというところをわかってないとダメだし、違うものだというのを説明できないとだめだと思った。

7 章 画面とドメインオブジェクトの設計を連動させる

画面アプリケーションの開発の難しさ

利用者の関心事に焦点を当てると、画面デザインとドメインオブジェクトの設計は連動します。

この部分、意識できるようになって来ているなと自分では思っている。

もっと設計の実践を積んで行きたい。

画面の関心事を小さく分けて独立させる

注文時の 注文者情報 注文商品決済方法配送方法` などを Order::register() みたいに一つのクラスで処理していると、メソッドが膨らんでしまい、追加削除が大変になる。

注文者情報 ならそれだけの保存注文商品 ならそれだけの保存という感じで、それぞれで保存できるようなロジックにし、それを Order::register() で呼び出すようにすれば、変更がかかっても対象の保存クラスのみに抑えられる。

画面とオブジェクトを連動させる

ドメインオブジェクトをそのまま使って画面の表示するというということらしいが、ここまで出来ているプロジェクトってあるのだろうか...? ちょっと実際に見てみないと、イメージつかない...

画面(資格表現)とソフトウェア(論理構造)を関連付ける

ここで例として紹介されている書籍クラスと画面の関心事と一致させたクラスは、説明としてすごくわかりやすかった。

また、以下の文も自分的に響いた文だった。

画面デザインがごちゃごちゃしている場合は、ドメインオブジェクトの設計の方から、画面をより論理的にデザインする改善点を提供すべきです。 画面のデザインとドメインオブジェクトの設計の一致は、利用者/画面のデザイナ/ソフトウェア開発者が一緒になって検討すべきです。

デザインの部分は苦手で、正直任せていたところがあるので、逃げずにきちんと向かい合わないとと思った。

終わりに

次は8〜10章を読みます。

10章までなので次回で終わりです。

現場からは以上です。