# クリーンコード 第3章,第4章 ## 第3章 関数 ### 小さいこと! **関数の第一規則は「小さくせよ」第二の規則は「さらに小さくせよ」** 透明性が高く明瞭で、数行に収まる関数にするのが最も望ましい。 #### ブロックとインデント ネストはできる限り無くす。あって1つに抑える! ### 1つの関数で1つのことを! 「**関数では1つのことをおこなうようにせよ。その1つのことをきちんと行い、それ以外のことを行ってはならない**。」 では、「1つのこと」とはどこまでを指すのか。「1つのこと」=「いくつかのステップを含む1つの抽象レベル」である。 関数を書く目的は、広い概念から、抽象レベル単位のいくつかのステップに分解することである。 1つの抽象レベルにある**複数のステップは順序立って**おり、そのレベルから無理なく分割することが不可能である。 関数が「**1つのこと**」のみを行っていることを確実にするには、その関数内の文が**1つの抽象レベルにある**かを確認する必要がある。 **本質的な概念と、実装の詳細をごちゃ混ぜにしないこと!** #### コード通読:逓減規則 コードは**上から下へと、物語のように読める必要がある!** また、抽象レベルの降順で並んでいる必要がある。これを逓減規則という。 **小さな関数が、次から次へとreturnで繋がっていくように書くことで、明快かつ流れるような読みやすさのコードとなる。** ### switch文 switch文は、冗長性の塊のようなものであるが、小さくするのは難しい。 選択肢の追加時に変更が必要という厄介な問題も抱える。 しかも、同じ構造を持つ大量の関数がいくつも生成可能なため、余計に冗長性が増してしまう。 これらの解決策として、switch文を抽象レベルの最下層である抽象ファクトリに置き、人の目に触れないようにカプセル化を行うことである。 ### 内容をよく表す名前を使う 名前をつける際は、関数が何を行うかを良く表現する名前をつけること。 内容をよく表す長い名前は、短い名前や長いコメントよりも優れている。 複数の単語を使用した、簡単に読める関数名をつける。 同じ言い回し、名詞、動詞を使用する。 ### 関数の引数 引数として渡すパラメータの数は、最も望ましいのは0, 次いで良いのが1, 2である。 3つ以上は望ましくない。 引数は大量の概念上の力を持っている。引数と関数名は抽象レベルの観点で異なる。 引数を目にするたびに、その引数はどこからきているのかについて知る必要が生じるためである。 また、引数が複数あると、テストケースの作成パターンが膨大になってしまい、厄介である。 引数が関数を通じて出力されるケースにおいては更なる混乱を生じやすいため避ける。 #### 共通モナディック形式 引数を渡すパターンとしては以下のパターンがある。 * 引数を通じて照会を行う。(処理判定等) * 引数を通じて型変換を行う。(String型のint型への変換等) * イベントを発生させる。(void型。イベント発生であることを明確にする命名を行う必要がある。) #### フラグ引数 boolean型の引数としての利用(フラグ引数)は避ける。 そもそもbooleanはtrueとfalseで2つのことをやっている。 引数で分けるのではなく、2つに関数を分割する! #### 引数が複数個以上の関数 引数が複数個以上あると、格段に理解が難しくなる。 座標値(0,1)のような複数個を組み合わせて1つの値を構成している場合を除き、格納順序が決まっておらず、混乱を招きやすい。 複数個の使用にはリスクがあること、そして引数を減らす方法を理解する必要がある。 #### 引数を減らすための方法 * 引数オブジェクトの使用:引数をあえてオブジェクト化し、1つの概念を作る。 * 引数リストの使用:引数をリスト化して、List型で指定された1つの引数にする。 #### 動詞とキーワード より洗練された命名にするには以下の工夫がある。 * 動詞+名詞の組み合わせを用いる。(例:writeField(name)) * 名前に引数名を引数順で組み込む。(例:assertExpectedEqualsAqtual(expected, actual)) ### 副作用を避ける 副作用とは、関数が1つのことを行うことを保証しつつ、隠れて別のことを行う事である。 代表例が、他のことを行う関数の呼び出しである。 時間軸上の関連を形成しており、思わぬ形で呼び出されて思わぬ動作をする恐れがある。 また、出力引数はオブジェクト指向言語ではほぼ不要となった。関数がvoidで変数で戻り値を返すことは避ける。 ### コマンド・照会の分離 関数は何らかの処理を行うか、何らかの応答を返すかのどちらかのみを行うべきである。 setterによる値のセット等の処理と、if文の判定を混ぜると、setの解釈が分かれてしまい混乱を招く。 コマンドと照会は分離すべきである。 ### 戻りコードよりも例外を好む エラー値は、戻り値で処理するよりも例外を出したほうが良い。 例外が発生した時点でコードが正常処理と分離されるため、コードは簡潔になる。 #### try/catchブロックの分離 try/catchブロックはそれ自体が不格好である。こうした場合は中身を関数として外に出してしまうのが良い。 関数名にthrows Exceptionをつけることで実現できる。 #### エラー処理も一つの処理 エラー処理も一つの処理のため、他のことを行ってはならない。 #### エラーコードを返す場合の依存性 エラーコードを返す場合は、どこかにすべてのエラーコードが定義された関数が存在することになる。 こうした場合、依存性が高く変更時に手間がかかる。 例外処理は、こうした依存性によらず実現できる。 ### 重複排除の原則 重複は、たとえアルゴリズムにおいても修正の手間が必要である。 この重複は、インクルードメソッドを使うと軽減できる。 ### 構造化プログラミングとリファクタリング 構造化プログラミングは、入り口と出口を1つにすべきという概念である。 しかし、関数が小さい場合はあまり役立たない。 関数が小さければ、break文や複数returnはあまり害にならない。 ### なぜこのように書くのか リファクタリングは、文章の推敲に等しい。 最初はうまく構成されていなくても、リファクタリングを行う事によって洗練できる。 話して聞かせるストーリーを崩さず、小さく読みやすくするために必要なのである。 ## 第4章 コメント コメントは「純粋に良い」ものではない。 コードでうまく表現できなかった場合に、それを補うために利用するのが正しい。 コメントは常に失敗なのである。 コードは進化していくが、コメントは置き去りにされる。 過去の解釈で置き去りにされたコードは、存在するだけで混乱を招きやすい。 どれだけコメントを書こうと、真実はコードの中にある。 コメントは最小限にする努力をしなければならない。 ### コメントでダメなコードを取り繕うことはできない コメントでいくら説明したところで、雑然としたダメなコードはどうにもならない。 コメントに時間をかけるより、コードの混乱の片付けに用いるべきである。 ### 自分自身をコードで説明する コメントで説明するよりも、同じ内容の名前を付けた関数を作るほうがより簡潔になる。 ### コメントを書いてよいもの #### 著作権の明示 著作権及び著作者の明示は必要不可欠である。 但し、契約や法律書ではなく、標準ライセンスやその他外部ドキュメントへの参照を上げるべきである。 #### 情報を与えるコメント 関数を理解するために、必要な情報をコメントによって与えるものである。 こうしたコメントは時に便利な場合があるが、より良い表現を行ってコメントを削除するとなお良い。 #### 意図の説明 なぜこの処理を行うのかについての意図を説明する場合、読み手に意図が伝わりやすくなり有益である。 #### 明確化 あいまいな引数や戻り値の値を解釈可能なように変更する場合である。 通常であればあいまいな引数や戻り値の命名変更で対処するが、 一部ライブラリにおける変更不可のものである場合に有益である。 但し、そのコメント自体が間違っている可能性もあるため、十分な注意が必要である。 #### 結果に対する警告 特定の結果に対して警告する場合である。 現在では利用しない関数には@ignore(コメント)をつけるが、 過去のコード規約のものである場合にコメントをいれるのは有益である。 #### TODOコメント 「あとでやる」ことを書き残すために、//TODO:を付け加える。 将来的な機能拡張や機能削除のための備忘録であることが多い。 当然放置して良いものではないため、これらを検索してTODOをつぶしていく必要がある。 #### 強調 一見筋が通らない処理の場合に、注意書きとして強調する場合である。 #### 公開APIによるJavadoc 公開されたAPIを書く場合は、そのための優れたJavadocを書く必要がある。 ### 良くないコメント #### ぶつぶついう 要するに適当に書かれたコメントのこと。 意図が伝わらず、いちいち他のモジュールを調べる必要のあるコードは邪魔なだけである。 #### 冗長なコメント いちいち処理内容を説明しているようなコメントのこと。 コード自体を上回る情報が提供されていないため、コードを読んだほうが早い。 こうした無駄なコメントが大量にある場合、ただただ目障りである。 #### 誤解を招くコメント 言葉で正確に表せておらず、誤解を生じる可能性があるコメントのこと。 #### 命令コメント すべての関数や変数にJavaDocやコメントの記述を強制するもの。 雑然で誤解を招くため不要である。 #### 日誌コメント いわば手動の更新ログ。 古いシステムで見られるかもしれないが、現代のソースコード管理システムを使えば不要。 #### ノイズコメント コードを見ればすぐにわかるような情報を、わざわざコメントに書いているもの。 邪魔なだけでなく、コードの変更によりすぐに嘘と化してしまいやすい。 #### 関数に変換できるもの コメント内容が関数に変換できる場合は、関数をつくってコメントを削除する。 #### 道しるべ コード内で目印をつけるようなコメント(バナー)は大抵は不要になる。 つけるとすれば、その効果が最大になる時のみである。 #### 閉じカッココメント 長い関数において、終わりの閉じカッコを明確にするために記述したコメント。 短い関数では不必要。 #### 属性と署名 だれがいつ何を作ったかを示したもの。 こちらも日誌コメントと同じく、ソースコード管理システムを使えば不要である。 #### コメントアウトされたコード コメントアウトしたコードを使う予定が無いのであれば、ただのスペースの無駄遣いである。 #### HTMLコード コメントの中にHTML文が含まれるもの。読みにくさを招いてしまう。 #### 非局所的な情報 コメントがシステム全体に及ぶ情報を示している場合、局所的なコメントにしないこと。 #### 多すぎる情報 情報をひたすらに詰め込んだコメントは、ただただ理解に苦しむのみである。 #### 不明確なつながり コードで示しているものと、コメントで示しているもののつながりが不明確な場合。 何を指しているのかを明確にする必要がある。 #### 関数ヘッダ 正しい名前さえつけられていれば、小さい関数に特別な説明は必要ない。 #### 非公開コードのJavadoc 公開されていないコードでのJavadocは邪魔なだけである。 ###### tags: `読書`