わかりにくプログラムの特徴
メソッドが長い
理解するのが大変。特にif-elseが入り組んだメソッドは理解が骨が折れる。
引数が増えるたびにメソッドも長くなりif文も増える。
クラスが大きい
関心ごとを詰め込みすぎないこと。
引数が多い。
どの引数が関係し、どの引数が関係しないか見極めに時間がかかる。
最初からわかりにくいわけではない。
プログラムが改修されるたびにどんどんメソッドや変数の追加などを後付けでしていくので、時間と共にどんどんわかりづらくなっていきます。
改善策
一つの変数を使い回さずに、用途ごとに変数を用意する。
第三者への説明にもなる。
重複コードはメソッドとして切り出す。
クラスが大きくなったら関連するクラスだけ抜き出す。
基本的には、メソッドがどのインスタンス変数を使っているかで判断するのが良いでしょう。
パッケージを使ってクラスを整理する。
クラスの数が増えてくるとどこに何が書いてあるか見つけにくくなります。それを整理するのがJavaで言えばパッケージです。
なお、パッケージ内のクラスの数が増えてきたらさらにサブパッケージに分けると良いでしょう。
また、パッケージ名が長くなるようであれば、階層化して一つ一つのパッケージ名を短くすることを検討すると良いでしょう。
データクラスをそもそも作らない。
getterメソッドとかも不要です。インスタンス変数を加工した結果を返すメソッドであれば問題ないです。
インスタンス変数を使わないメソッドを作らない。
インスタンス変数を使わずに、引数だけを使うメソッドをもし見つけたらそのメソッドは無意味になります。そういうメソッドを見つけたら、引数を渡している側のクラスに移動させるなど検討した方が良いでしょう。
データクラスと機能クラスに分けない。
ロジックとデータは同じクラスに持たせる。クラスを使う側のクラスでロジックが呼び出された場合は、業務クラス側にロジックを預けるよう書き直す。
業務に対応したクラスを作る。(ドメインオブジェクト)
業務データと業務ロジックを一つにまとめたオブジェクトを「ドメインオブジェクト」と呼びます。
値を扱う専用のクラスを作る。(値オブジェクト)
基本的に不変であるべきです。(setterとかで書き換えられないようにするべき)
特徴
- インスタンス変数はコンストラクタで生成時に行う。
- setterは作らない。
- 別の値が必要であれば、別オブジェクトを作る。
電話番号型
普通のStringとかにしてしまうと思わぬ値が来ることになったりする。
相手のシステムとやり取りするインターフェース
コレクションや配列を扱う場合は専用のクラスにする。
コレクションや配列を操作するロジックなどは、普通に実装する場合かなり複雑になるため。専用のクラスを作る。(Reactで言えばuseReducerや、Redux)
1 |
例:Customerの配列だけ持ったCustomersクラスを作るなど。 |
特徴
インスタンス変数は該当のコレクションだけにする。
コレクションへの操作はメソッドで行う形にする。
元の値をそのまま変更させず、渡す場合はnewで必ず別オブジェクトを渡すようにする。
getListなどでコレクションをそのまま外部に渡してしまうと、外部からでもコレクションを色々操作できてしまうためコレクションの状態が不安定になってしまうため。(元のオブジェクトは直接は弄らせないという副作用を起こさせない。Reduxと同じ思想)
「区分」や「タイプ」の実装方法
if文やswitch文が増えます。
対策
判断のロジック(isXXX)と、計算ロジック(calcXXX)をメソッド化する。
後述するelseを書かないというためにもこれは使えます。
elseを書かない。
できるだけ「早期リターン」します。(「ガード節」ともいうらしいです。)、場合分けのコードがすっきりして読みやすくなります。
- if (isXXX) return calcXXX
- if (isYYY) return calcYYY
複文が単文にもなり疎結合になるので非常にわかりやすくなりますし、順番を並び替えてもうまく動きます。
区分クラスを作ったり、インターフェイスを作る。
また、ほぼ似ているクラスができるのであればインターフェイス化して、呼び出す側からポリモーフィズムなどで効率的に呼び出せるようにしましょう。
この記事へのコメントはありません。