『良いコード/悪いコードで学ぶ設計入門』を読んでみた【コラム】

goodcode-badcode-architectureコラム

今回は2022/4/30に@ミノ駆動さんが出版された『良いコード/悪いコードで学ぶ設計入門 ― 保守しやすい成長し続けるコードの書き方』を読んでみましたので内容をまとめつつ、私が感じたことなどをまとめてみました。

Bitly

私は今まで一人の先輩エンジニアの方が設計していただいたソースコードを見習って実装していくことが多く、特に疑いを持たず自分も実装を進めてきました。
私が携わっていたプロジェクトは他プロジェクトからも参考にされることもあったので悪い設計とは思っていませでした。

しかし、実際に何がどう良くて何がどう悪いのかをあまり理解はできていなかったため、自分が関わっているプロジェクトの何がよくてどうすればもっと改善できるだろうかと知る必要があるなという思いから当書を読もうと思いました。

本記事では『良いコード/悪いコードで学ぶ設計入門 ― 保守しやすい成長し続けるコードの書き方』のざっくりとした内容を紹介しつつ、私が感じたことを最後に書いています。

ざっくり要約

当書はオブジェクト指向型の言語を元に書かれています。
そのため対象者としてはオブジェクト指向プログラミング言語の基礎知識があり、設計をしっかり学びじめようと考えている方とされています。

当書でいう設計とは保守性、特に変更容易性の向上を目的にした設計手法が主に紹介されています。

まずは何がどう良くない構造なのかを知り、次に変更に強い良い構造を知ることで設計の改善が可能になります。

そして良い構造を把握するために設計の基本的な考え方や具体的なクラス設計、実際の改善例などをコードを元に解説してくれています。

後半部分では、設計への向き合い方やコード以外の開発プロセスで気をつけるポイントなどの解説があります。

最後には当書を読み終えた後に読むべき設計に関係する技術書等の紹介がされています。

内容

1章 悪しき構造の弊害を知覚する

良いコードを書くにはまず悪しき構造を知ることから開始することが必要。

それによって何が悪いのかが理解でき、なにか対処しなければという意思が設計を良くするためのはじまり。

  • 意味不明な命名
  • 条件分岐のネスト
  • データクラスの不用意な扱い

上記例などが様々な弊害を引き起こす。

2章 設計の初歩

基本的な設計の考え方が書かれている。

無理に命名を省略せず意図した名前を設計する。
変数は使い回さず目的ごとの変数を用意する。
意味のあるまとまりでメソッド化したり、関係するデータ、ロジックはクラスにまとめる。

3章 クラス設計

オブジェクト指向設計の基本を解説。

クラス単体で正常に動作するように設計する。
ドライヤーやヘッドホンなどの家電のようにそれ単体で正常動作するように設計する必要がある。

コンストラクタで確実に正常値を設定する。
インスタンス変数をイミュータブル(不変)にすることでコンストラクタでのみ代入を可能にし、意図しない値に書き換わることを防ぐ。

引数の型を指定することで意図しない値が渡されないように。
インスタンス変数が不正な状態にならないように設計することでバグを回避する。
バグは不正な値が混入することで発生する。

4章 不変の活用

変更を最小限にする設計の中で不変が大きな役割を果たす。

可変にしていると意図しないことが発生するリスクが高くなるため、不変にすることで予期しない動作を防ぐ。
デフォルトは不変にし、状況に応じて可変にする。
可変にするときはパフォーマンスに問題が生じるケースなど。
例えば大量データの高速処理や画像処理など。

5章 低凝集

低凝集は重複を生みやすい。

共通処理クラスはロジックが雑多に置かれがちになるため、結局何をするクラスなのかわかりくにくなる。
引数が多すぎるメソッドは低凝集に陥る良くない構造。

ログ出力やエラー検出など横断的な関心事に関しては共通処理としてまとめても良い。

6章 条件分岐

条件分岐の多量なネストは可読性を低下させ、仕様変更に弱い。

早期returnを意識してネストを防ぐ。
interfaceを使いこなし条件分岐を減らす。

7章 コレクション

コレクション処理は自前で実装せず言語の標準ライブラリのメソッドを使うのが吉。
ループの中で条件分岐をネストするのではなく早期continueでネストをなくす。

8章 密結合

単一責任の原則を守る。

疎結合を意識したことによって同じような処理が書かれているクラスが存在することもあるが、DRY原則(Don’t Repeat Yourself)を誤用してはいけない。
同じようなロジック、似ているロジックであっても、概念が違えばDRYにすべきではない。
概念的に異なるものどうしを無理にDRYにすると結果、密結合になる。
継承は要注意であり、継承より委譲を意識する。
利用したいクラスを継承するのではなく呼び出す。

9章 設計の健全性をそこなうさまざまな悪魔たち

設計の健全性を損なう事例を紹介。

・デッドコード
・将来使われるだろうで実装しない→結果デッドコードになる
・マジックナンバー
・nullを返さない、渡さない
・例外の握り潰し
・サンプルコードのコピペ

10章 名前設計

命名をないがしろにすると、責務が入り乱れて密結合になったりクラスが巨大化する。

広義な意味を持つ言葉には注意が必要。「管理」など
大雑把な命名だと様々な関心事と結びついたロジックを持ってしまい密結合になる。

目的駆動名前設計を意識する。

プログラミングにおける名前の役割は、可読性を高めることだけではない。
可能な限り具体的で、意味範囲が狭い、目的に特化した名前を選ぶ。
命名とロジックが対応していることが大事。

11章 コメント

コメントを退化させないようにコメントも実装と同時に更新が必要。
ドキュメントコメントは良い。

12章 メソッド(関数)

メソッドは必ず自身のクラスのインスタンス変数を使うよう設計するのが大事。
例外もあるがこれが原則。

13章 モデリング

モデルはシステム構造の説明に用いるため、まずシステムが何であるかを理解する。
目的別にモデリングする。
一責任の原則とは、単一目的の原則。
クラスを特定の目的に特化して設計することで、変更に強い高品質な構造になる。

14章 リファクタリング

外から見た挙動を変えずに構造を整理する。

・ネストを解消する
・意味ある単位にロジックをまとめる
・条件を読みやすくする→論理否定をあまり使わないようにして条件文を書く
・ロジックを目的を表すメソッドに置き換える

ユニットテストを書くことでリファクタリングのミスを防ぐ。
注意として機能追加とリファクタリングを同時にしない。
どっちをやっているのかがわからなくなるし、コミットもどちらが目的なのかがわからなくなる。

15章 設計の意義と設計への向き合い方

設計とは課題を効率的に解決するしくみづくり。
当書は保守性に関係する設計。
特に変更容易性の向上を目的とした設計手法。
エンジニアにとっての資産は技術力。

費用対効果を考えて設計することも大事。
構造的に粗悪であっても機能が安定していて仕様変更がほとんどない箇所をリファクタリングしてもかけた労力が無駄になってしまう。

16章 設計を妨げる開発プロセスとの戦い

設計品質をおとしめてしまう開発プロセスの問題。

・スキル不足以外
・心理的要因
・コミュニケーション要因
・組織的要因

厳密すぎる設計ではなく、サイクルを回し続ける

17章 設計技術の理解の深め方

設計技術書の紹介。
インプット2、アウトプット8で学習する。

実際のコードをローカル上でリファクタリングしていく。
教材を使うのではなく実際動いているプロダクションコードをリファクタリングすることで実践レベルで使える設計力を養える。

感想

先輩エンジニアの教えもあり、この本で紹介されていることは割とできていることがあるなと感じました。

ただ、できていないことやあまり意識できていないこともあったため、今後その辺りも意識していかないといけないなと思いました。

特に名前設計の部分はあまり考えずに伝わるしいいだろうくらいで命名することもあったので、広義な意味を持つ名前は使わないなど意識する必要がありそうです。

ケースバイケースなのでこの本に書かれていることがすべて正しい、こうしなければいけないということではないと思うので状況に応じて取り入れるべきポイントは考える必要があるなと思います。

また、個人的には本の中でも度々登場していたクソコード動画が悪い構造を把握するのにはわかりやすかったので、他の動画も見たいと思います。

私はタイミング的にクリーンアーキテクチャーなどを勉強したいと思っていたので、その前にこの本を読むことができてよかったです。

ただの実装者から全体の設計のことも考えられるようにステップアップするためには必読かなと思いました!
社内でも共有しようと思います。

ありがとうございました。

コメント

タイトルとURLをコピーしました