何が書いてあるか
読んだ本の要約化で理解と記憶の定着化を目指します。
あくまで個人のエッセンスの列挙になります。実際の内容はこの何十倍も示唆に含まれている素晴らしい書籍です。この素晴らしさを一人でも多くの方が知るキッカケになれば嬉しいです
読んだ本
良いコード/悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方
仙場大也著
2022年に出版された本です。
出会ったきっかけ
具体的な名前は忘れましたがLGTMランキングTop20の読むべき書籍20選の記事で知りました。
本編(要約)
第1章「悪しき構造の弊害を知覚する」
・弊害には、コード読解コストが高い、バグの埋込やすさ、構造劣化の負のスパイラル。
・技術駆動命名、連番命令の弊害、人間が理解できる意味をコードから外部化したときの同期漏れが混乱を招く、
・欲しい機能が実装済みであることが把握しずらい弊害。可読性が悪かったり、ネーミングが悪かったり、低凝集だったりが要因。
・未初期化状態が発生するクラスは生焼けオブジェクトの弊害。
第2章「設計の初歩」
・ネーミングで対処、再代入はやめて混乱しないように、意味のある単位で区分けする、関係するものは近い距離(同一クラス)に納める。
第3章「クラス設計」
・関心の分離が重要。クラス、表明、総称性、継承、多相性、動的束縛から構成される。
・単体で動作する区分けであること。
・自分の身は自分で守る、自己防衛責務が果たせること。
・ガード節でネストを浅く保ち読みやすく。
・引数をプリミティブ型からクラス型にして、渡し間違いを防ぐ。なるべく具象化する。
・インスタンス変数を不正な状態にしないための仕組みづくりである。
・高凝集、カプセル化。
・完全コンストラクタ、値オブジェクト、ストラテジ、ポリシー、ファーストクラスコレクション、スプラウトクラスの設計パターン。
第4章「不変の活用」
・一時変数は使い回さないこと。
・関数の外にある状態が変わる副作用に注意を払う。
・インスタンス変数は不変にし、更新処理は新しいインスタンスを生成することで行うようにする。
・原則は不変とするコーディング規約が良い。パフォーマンスを上げたい時、局所的なスコープ内では可変とする。
・不確実性をはらむコード外とのやりとりで発生する悪影響を局所化する方法としてリポジトリパターンがある。これは永続化処理をカプセル化するもの。
第5章「低凝集」
・凝集度はデータとロジックの距離の近さ。
・static修飾子をつけてコンパイルが通る関数は低凝集のままである。
・ファクトリメソッド化し、インスタンス生成ルートをクラスに内包させて、混沌化をなくす。増えすぎて可読性が落ちてきたら生成ロジックをファクトリクラスとして分離する。
・ユーテリティクラスはstaticで書きがちだが、単に似たようなものをまとめているだけだと低凝集に陥る。思考停止にならずどのクラスに書くべきかを意識すれば再利用性と高凝集度の両方が得られる。
・staticにしても良いのは横断的関心事。
・引数が多くなっている場合は関心事を絞れていない兆候。
・プリミティブ型執着は指定誤りを見落とす確率が増えたり、秩序がもたらされないので重複コードができやすくなる。
・利用するオブジェクトの中身を知る必要にかられたら、それは設計がおかしい。デメテルの法則。
・尋ねずに命じるだけで利用できることが大切。
第6章「条件分岐」
・早期リターンの活用
・単一責任選択の原則により、switch分の重複コードを回避する。つまり何かの選択肢で分岐する処理はひとつのswitch文にまとめる。これでヌケモレが防げる。さらに良いのはinterface化で分岐内容をクラスに内包させる。
・何をinterface化するかは、なんの仲間であるかの問いかけで行う。
・interfaceを用いて処理を一斉に切り替える設計をストラテジパターンという。
・interfaceが実装、クラス継承が汎化、クラス内でメンバ変数としてもつのは関連、メソッドスコープで依存先が留まっているのが依存。
・業務の関心事ルールをinterface化するのがポリシーパターン。
・リスコフの置換原則にもとづいてinterfaceを使った実装に誤りがないかをチェックする。つまり他の継承型に置換して問題なく動作するかで確認する。
第7章「コレクション」
・コレクションライブラリの活用。
・ファーストクラスコレクションを活用し低凝集化を防ぐ。コレクションをインスタンス変数にもたせ、不正な状態を防げるように操作をメソッドで設ける。
・参照目的で外部にわたす場合はコレクションを不変化させて返す。JavaならunmodifiableList()。
第8章「密結合」
・単一かつ明確で信頼できる表現になっているかで構造を判断する。
・安易な継承はスーパークラス依存で密結合を生み出す。委譲によるコンポジション構造がベター。
・アクセス修飾子はpackage privateをデフォルトとする。(C#ならinternal)
・private修飾子が増えてきたら、単一責任の原則から外れてきていることを疑う。
・高凝集と疎結合の両面をケアする。
・巨大データクラス、トランザクションスクリプトパターンが出ないようにする。
第9章「設計の健全性を損なうさまざまな悪魔たち」
・デッドコードのクリーン化を心がける。
・YAGNIの原則。最適な形はそのときにならないとわからないから必要になったら作れば良い。
・マジックナンバー、文字列型執着、グローバル変数、局所化できない、例外握りつぶし、メタプログラミング、技術駆動パッケージング、銀の弾丸
・nullを業務の初期状態に用いてはいけない、nullは言語仕様上の状態を表すものなので。言語仕様としてnull安全が設けられているものもある、非許容型。
第10章「悪魔を呼び寄せる名前」
・目的駆動設計であるべき。関心事で分ける、関心事でより具体的な呼び名にする。 例)商品→配送品、予約品
・名前設計の便益には、可読性向上、疎結合高凝集の実現がある。
・具体的か、存在ベースでなく目的ベースの名前か、関心事の分析、声に出して話してみる、利用規約を読んでみる、置き換え可能かの検討、疎結合高凝集かがチェックポイント。
・技術駆動命名の弊害。驚き最小の原則に従う。
・コマンドクエリ責務分離(CQRS)のアーキテクチャパターン。
・状況によって意味が変わる言葉には注意。例)アカウント
・関心事のコンテキストの違いを考慮するべき。この場合はパッケージで分ける。
・「動詞+目的語」形式の名前になる時は関心事が異なっている兆候あり。この場合は目的語の概念をクラスで表現し、動詞の概念でメソッドを設ける。
・boolean型メソッドの追加の際は「クラス名is状態」の形に読み変えて自然な英語で読めるかで判断。
第11章「コメント」
・コメントが退化し、書かれていないほうが良い場面がある。挙動をなぞるだけのコメントは退化しやすい。具体的すぎて変更に振り回されやすいから。
・どんなに尽くしてもコメントはコードの劣化コピーにしかならない。構成と命名でわかりやすいコードにするのが良い。
第12章「メソッド」
・自身のクラスのインスタンス変数を使うようんい設計するのが原則。
・getter/setterは使わない。
・データと操作ロジックは呼び出される側に閉じ込め、呼び出し側には手続きのみ公開する。
・コマンド(変更)とクエリ(取得)は分けてメソッド化する。
・引数は不変化する、フラグ引数は使わない、nullを渡さない、出力引数は使わない、引数の数はなるべく少なくする。
・戻り値の型もなるべくプリミティブ型ではなく意図を織り込んだクラス型とする。
・エラーを戻り値で表すことはしない、例外で表現すること。
第13章「モデリング」
・動作原理やしくみが伝わりやすいように、特徴や関係性を図式化したものをモデル、このモデルを作る行為をモデリングという。
・社会活動をコンピュータ内で実現するために、活動がもつ現実の構造をシステム内にも導入し、現実の変化に追従するものを作ろう。
・最低限考慮が必要な要素を備えたものがモデル。属性を厳選してモデリングすることが大切。
・システム内に投影されるべきは現実世界の概念のみ。処理しているのは概念的なやりとり。
・同じものを表現するのにも、目的に応じて名前や形態が違っている現実を踏まえる。
・現実の存在とモデルが1対1の関係になるとは限らない。
・モデルはモノではなく目的達成手段と捉える。モノだと抽象的すぎて詰め込みになりやすいので。
・特定の目的に特化させる。
・モデルは1つ以上のクラスで構成される。
・最初からうまいモデリングができることはない、日々改善が大切。
第14章「リファクタリング」
・否定の否定の命名は、ひっくり返して肯定ですんなり読めるようにする。
・意味がすんなり伝わるように、関数でラッピングする。
・どちらの帽子を被っているのかを意識して、機能追加とリファクタリングを同時に行わないようにする。
・動的型付け言語は静的型付け言語よりリファクタリングの難易度が高い。
第15章「設計の意義と設計への向き合い方」
・ソフトウェアの品質特性、機能適合性、性能効率性、互換性、使用性、信頼性、セキュリティ、保守性、移植性。
・一生懸命働いた感より成果を出しやすい構造に設計する。
・エンジニアの本質的な資産は技術力。レガシーコードは誤った導きになる。スキル向上の機会を奪ってしまう。
・理想形が定義できない、説明できない状況でのむやみな練習はしないほうが良い。理想形を知ることで技術的負債が知覚できるようになる。
・計測はコードメトリクスにもとづいて行う。
・コードが一つのメソッドに網羅サれていたほうが読みやすいというのは、信頼性が低いのが根本原因。標準ライブラリのような信頼性が確保できればこの問題はクリアになる。
・条件分岐やループ処理の増加、ネストが深くなるなどの構造的読みづらさは、循環的複雑度として計測できる。
・凝集度を表すメトリクスとしてLCOMがある。
・短期に記憶できる数は4個であり、マジカルナンバー4という。記憶単位をチャンクという。
・コード分析ツール、Code Climate Quality、Understand、Visual Studioのコードメトリクス計測機能がある。
第16章「設計を妨げる開発プロセスとの戦い」
・コンウェイの法則、プロダクトの構造と組織構造は似てくる。
・心理的安全性、発言に対して恥じることや拒絶されることなどの不利益を被ることがないことを共有できている心理状態。
・実はテストコードも書くTDDの方が最終的なコードを完成させるまでの時間が短い。
・改善のサイクルを回し続けること、意思決定もその時のベストであり、実現されたら見直し対象となることをチーム内で共有しておく。
・多数決や全会一致で意思決定はしない。レベルの低い方に合わせた基準になってしまうから。
・ジョシュア・ツリーの法則、名前がないものや名前を知らないものは存在を知覚できない。
第17章「設計スキルを高める学び方」
・紹介本の網羅率は6割程度。いくつか買い足しました。
最後までお読みくださりありがとうございました。