【技術書記録002】「現場で役立つシステム設計の原則」の要点メモ

今回の技術書

現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法 | 増田 亨 | コンピュータサイエンス | Kindleストア | Amazon

選考の中で話題に上がったので読んでみる。Javaを前提に書かれているので、ある程度Javaの知識ある人向け。



CHAPTER1 小さくまとめてわかりやすく

・業務の関心事とプログラムの単位を一致させる
・値オブジェクトを用意して、intやStringを独自の型にする
・メソッド等に出現するコレクションは、すべてコレクションオブジェクトに集約する


総じて、後に変更が生じた場合や、バグ修正等のときに、変更の影響範囲を特定しやすく、変更を容易にするための設計指針。
業務領域(ドメイン)とプログラムを一致させることで、仕様書がなくてもコードみればアプリケーションの内容を理解できるようにする。
基本データ型をラップして独自の型にしてしまう発想は、静的型付け言語でよくみられるのだろうか。扱うデータの範囲・用法を限定してしまうのは慣れないけど、確かに有効だ。参考になる。



CHAPTER2 場合分けのロジックを整理する

if等の場合分けのコードを極力なくす
→判断や処理のロジックをメソッドに抽出
→else句を使わず、早期リターンでガード節にする(if ~ return if ~ returnな書き方)
・区分ごとのロジックを別クラスに分ける(大人料金クラス、子ども料金クラスといった具合)
・区分ごとのクラスを同じ型として扱う
Javaのinterfaceを活用。多態性で個々の振る舞いは個々のクラスに、呼び出す側は親クラスであるinterfaceの型を扱い、子クラスの型・詳細の振る舞いに関心を持たない
・Map等を活用して、入力データからMapの中身に一致するものを吐き出す、という構成にすれば、ifがなくても場合分けできる
Javaの列挙型(enum)を利用して区分ごとのロジックをわかりやすく整理する(区分オブジェクトにする)


Rubyにはenumがなかったので馴染みがないが、章末の状態遷移の例はわかりやすかった。個々の状態から遷移先を限定することができる。業務フロー・ロジックをコードの実装と一致させることができる。なるほど。



CHAPTER3 業務ロジックをわかりやすく整理する

・従来の手続き型の設計:ロジッククラスとデータクラスが分離している。三層アーキテクチャのどこからもデータクラスを参照できてしまうため、影響範囲が大きく、コードの重複を生む・見通しが悪くなる。Java本来の意図しているクラスの使い方ではない
→ロジックはメソッドに集約、メソッドは短く、インスタンス変数を使う(使わないものは別クラスに移動を検討)
→ロジックを、データを持つクラスに移動する
使う側のクラスにロジックを書き始めたら、設計を見直す
→クラスは薄く小分けに、パッケージでクラスを整理(凝集度を高く、疎結合に)
・業務の対象領域(ドメイン)を小分けのオブジェクト(ドメインオブジェクト)に、ドメインオブジェクトは上の手順で業務データと業務ロジックを区分けして整理したもの
ドメインオブジェクトを俯瞰的な視点で、参照関係を意識して整理したものがドメインモデル。結果、データクラスが置き換わった形になるが、業務ロジックはドメインモデルに凝集することになる


ここらへんの話はわかる。ロジックの書く場所を意識しないと、あっちゃこっちゃにロジックが散らばるよね。コードも肥大化していくし。将来の変更容易性・スケールアップを考慮して、最初から薄く小さく保つ。心がけたい。



CHAPTER4 ドメインモデルの考え方で設計する

・業務経験者との対話から、業務を的確に捉える用語を見つけ出し、プログラムの名前にしていく
→結果、ソースコードが業務内容を表現するドキュメントになる 。プログラムの自己文書化
ドメインモデルの設計は、小さい部品から組み立てていく。前述の対話から、重要・必要不可欠な部分から組み立て、それらを組み合わせて機能を実現する、ボトムアップのやり方
・業務の関心事はヒト・モノ・コトの3つに分類する
コトに着目すると全体の関係を整理しやすい。コトはヒトとモノの関係として出現する。コトは時間軸に沿って明確な前後関係を持つ
・早い段階から実際にコードを書く→修正・追加を繰り返してコードを成長せさていく
・業務の経験者だけが持つ感覚をうまくキャッチして、プログラムの設計に取り入れるほど、現場で役に立つソフトウェアになる


現場のユーザーと業務理解が異なる・会話に齟齬が出るような状態で、良いアプリ・ソフトウェアになるわけないよね。そして最初から完璧に理解することも難しい。であれば、初期段階から小さく作っていき、対話を重ねるなかで理解を深め、より良いプロダクトへ改善していくわけか。
コトに着目すると整理しやすい、っていうフレーズがしっくりきた。どうしてもヒトとモノに注目しがちな気がする。その間にあるものをうまく捉えてコードにしてやることで、全体の整理がしやすくなると。



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

アプリケーション層は業務の進行調整役。プレゼンテーション層からの依頼に基づき、ドメインオブジェクトに処理の指示を出して、受け取った結果をプレゼンテーション層に返す。データソース層に記録や通知の入出力を指示する。
・業務サービスを提供するという意味でサービスクラスと呼ぶ。
・サービスクラスはごちゃごちゃしがちなので、業務ロジックはドメインモデルに記述することを徹底する。ドメインモデルは修正・追加を繰り返して育てていく。
・サービスクラスは登録系と参照系(副作用の有無)で小さく分ける。
・それらの処理の組み立てはプレゼンテーション層で行わない。複合サービスクラス(シナリオクラス等)で組み立てる。
・サービスを利用する側と、サービスを提供する側とで、サービス提供の約束ごとを決め、設計をシンプルに保つ(契約による設計)。
・データベース操作に引っ張られたプログラムは変更がやっかいになる。業務の関心事とデータベース操作を分離して、データベース操作を隠蔽する。
・具体的には、業務の視点からの関心事をリポジトリとしてインターフェース宣言する。リポジトリドメインオブジェクトの収納場所。メモリ上に保管していつでも取り出せる仕組み。


Spring Frameworkを実際に扱ったことがないので、詳細が分からない部分はあるが、とにかくサービスクラスはシンプルに保つ!ということ。それぞれの役割をはっきりさせ、記述場所を限定することで、全体の見通しをよくする。通底する考えはこの章でも同じ。



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

・テーブル設計には基本の3つの制約(NOT NULL、一意性、外部キー)を、丁寧に徹底して用いる。
・テーブルは小さく分割する。記録のタイミングが異なる事実は、後からカラムは追加せず、別のテーブルに記録する。
・過去のデータをUPDATEしない。取り消しデータと新データをINSERTする。
・良いテーブル設計のコツは「コトの記録」の徹底。状態の更新はコトの記録とは独立させる。 コトの記録を起点にして、派生する様々な情報を目的別に記録する(イベントソーシング)。
・オベジェクトはデータとロジックの整理、テーブルは元データの管理の役割をもち、別物である。設計の動機ややり方が基本的に異なる。


データベースでも「コト」に注目して整理していくのは同じ。ドメインオブジェクトとテーブルの設計は分けて考える。コトを起点にして派生を〜〜というところはイメージが湧きにくいので、もうちょいビジュアライズして解説してほしかったな。テーブルを小さく保つのは意識してなかったので、今後気をつけたい。



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

・画面の表示ロジックと業務ロジックは混在させない。条件分岐による画面の表示分け等は、業務ロジックに書く。
・何でもできる汎用画面ではなく、用途ごとの小さくシンプルな画面に分ける(タスクベースのUI)
・画面とドメインオブジェクトは「利用者の関心事」として一致するし、一致させるように改善することが、ドメインオブジェクトを洗練させる。


ちょっとここらへんから読むの辛くなってきた。業務に精通しているなら分かるのかも。初心者には辛い。文書だけだと抽象的なので、図とか実際の画面とかほしい。
あと、これは全体に言えることだけど、同じような内容の文書の繰り返しが多くて、読みにくいし頭に入って来にくい...。情報を扱う画面を小さく分けた方が扱いやすいよ、というのは理解できる。



CHAPTER8 アプリケーション間の連携

・4つの連携方式:ファイル転送、データベース共有、Web API、メッセージング。Web APIが広く使われている。
・後者ほど実現できる機能の選択肢や、処理性能などの非機能要求に対応できる範囲が広がる。
・肥大化したWeb APIは使う側も提供する側も負担が大きなるので、小さなAPIに分ける。
・利用者のニーズに合わせて、基本API・拡張(基本の複合)API・個別対応APIに分ける。利用の状況に応じてグループ分けを移動する。
・マイクロサービスは、初めから分けて設計するのは難しい。1つのアプリケーションの中で、境目がはっきりして設計が安定したところから分けいくのが実施的なやり方。


RailsAPI構築したことあるので参考になる話だった。とはいえ小規模なものなので、規模が大きなると小分けにしたりグループ分けが必要になるんだろうな。バージョニングは不要で、小さなAPIをそれぞれ更新すればよいというのは盲点だった。バージョニングは必要なものだと思い込んでた。



CHAPTER9 オブジェクト指向開発プロセス

・要求の分析と設計の工程を分割せず、同じ人間(あるいはチーム)が担当する。分析しながら設計を進める。フェーズ分けしない。
ソースコードがドキュメントになる。従来のフェーズごとの意思伝達や進捗管理ソースコードで表現できる。
・開発で重要になるのは、対面の質疑応答、ラフスケッチ、質疑応答とその記録。
・更新すべきドキュメントは利用者ガイドや業務マニュアル。
・開発者が業務の言葉でソフトウェアの説明ができることが品質保証。


開発プロセスと技術者の資質について述べた章。分析と設計が同時に行う活動なら、それを担当する人も一致するよね。フェーズで分業すればするほど、フェーズ間の意思伝達が難しくなるのは自明の理。経験ないので、本当にソースコードだけでドキュメント不要になるのか実感がないけど、更新するドキュメントが減るのはメリット。



CHAPTER10 オブジェクト指向設計の学び方と教え方

・机上では学びにくいので、実際を書きながら習得する。
・既存のコードをリファクタリングして、短いメソッドと小さなクラスを作り改善していく。
・極端なコーディング規則を用いて体で覚える(1メソッドにつき1インデント、1行につき.(ドット)は一つ等)。


あとは他に良い書籍がいっぱいあるから学んでね、ということでした。やっぱり実際書かなきゃ身につかないよね。



前半は良い内容で参考になるが、後半は文章の冗長さもあいまって読むのに苦労した。Springの実態も分かってないのもある。
この本は一定の業務経験を積んだ中級者以上向けの内容でした。今後経験を積む中で理解を深めていきたい。