mochieee
3/15/2020 - 6:53 AM

code smells

code smells

  • アンチパターンの特徴、理由、改善方法についてまとめる。
  • アンチパターンに共通して言えることは、
    可読性が悪く、修正しづらい
    ということ。

Couplers ( 不適切な結合と分離 )

Feature Envy

  • 特徴
    • メソッドが、自クラス内のデータよりも、別オブジェクトのデータに頻繁にアクセスしている
  • デメリット
    • 別オブジェクトとの結合度が高い → 別オブジェクトの影響を受けやすい
  • 対策
    • 問題となっているメソッドを別オブジェクトに移動する( Move Method )
    • メソッドの一部のみが別オブジェクトのデータにアクセスする場合はその箇所のみ移動(Extract Method)
    • メソッドが他のいくつかのクラスの機能を使用する場合、まず、最も頻繁に使用するデータがどのクラスのものなのかを判別します。次に、判定したクラスへ移動(Move Method)か、メソッドを複数の部分に分割して適宜配置する(Extract Method)。 リファクタリング例:https://mhtnim1023.hatenablog.com/entry/2019/12/22/210230

Message Chains

  • 特徴
    • オブジェクトを呼び出した際、そのオブジェクトがまた別のオブジェクトを呼び出し処理がチェーンする
  • デメリット
    • オブジェクトがナビゲートを行う場合、ナビゲートする過程の構造にクライアントが影響を受ける
  • 対策
    • 「移譲の隠蔽」が使えるが、これだけだと middle man 問題が発生する
    • そのため、返されるオブジェクトが使われている部分を「関数の抽出」で取り出し、「関数の移動」で連鎖を短くまとめる

Middle Man

  • 特徴
    • メソッドの大半が別のオブジェクトに委譲しているだけのクラス
  • 対策
    • 「仲介人の除去」や、仲介人メソッドがわずかな場合には「関数のインライン化」で呼び出し側にその部分を埋め込む

Mysterious Name

  • 特徴
    • 名前から目的や意図が推測できない
  • デメリット
    • 目的を確認するにはコードの詳細を確認する必要がある。
    • いい名前が思いついてない = 設計がまだ固まってない兆候
  • 対策
    • 関数宣言の変更、変数の名前変更、フィールドの名前変更

Bloaters (膨れ上がったコード)

Long Method

  • 特徴

    • コードの行数が多すぎるメソッド.一般的に10行以上のメソッドはリファクタリングを検討したほうが良い
  • デメリット

    • メソッドの目的が理解しづらく、メンテナンス性が低い
  • 対策

    • 関数名をわかりやすくする
    • 関数の抽出
      • 抽出前に一時変数やパラメータを減らす
        • パラメータや一時変数が多すぎる関数は、抽出が難しい。引数が増えて可読性も改善されない。
        • そのため、「問い合わせによる一時変数の置き換え」や「問い合わせによるパラメータの置き換え」を組み合わせる。
        • それでも一時変数やパラメータが残る場合は「コマンドによる関数の置き換え」を実施
      • 関数抽出の手法
        • コメントを探して関数として抽出。コメントはコードの意図が伝わりにくい点を補うために書かれていることが多いため、コメントで挟まれたコードがあった場合、コメントに書いてある意図を関数名とする。
        • 条件分岐は「条件記述の分解」
          • 同じ条件でswitch文が複数あった場合は「ポリモーフィズムによる条件記述の置き換え」を適用。
        • ループはループ部分とループ内部のコードを抽出して、独立した関数にできる。
          • 抽出したループに名前をつけることが難しい場合、ループだけでない別のことをしてるからかも。その場合は、「ループの分離」で、独立したタスクに分解する。

Long Prameter List (Many Parameter List?)

  • 特徴
    • 処理で扱うパラメータが多い
  • デメリット
    • その処理を関数として抽出しづらい
    • コード量が多い
  • 対策
    • パラメータで渡されるオブジェクトに問い合わせることで、 パラメータリスト中の他のデータ を取得できる場合、 「問い合わせによるパラメータの置き換え」
    • 既存のデータ構造から多くのデータを取り出している場合、「オブジェクトそのものの受け渡し」
    • 複数のパラメータが常に一緒に渡される場合、「パラメータオブジェクトの導入」

Data Clumps (データの群れ)

  • 特徴
    • 異なるコードで全く同じ引数グループが存在
  • デメリット
    • コード量が多い
  • 対策
    • 「クラスの抽出」でオブジェクト化する。そのあと、「パラメータオブジェクトの導入」や「オブジェクトそのものの受け渡し」でメソッドの呼び出しを単純化

Speculative Generality (疑わしき一般化)

  • 特徴
    • 将来を想定してクラスや変数が実際には使われてない状況
  • 対策
    • 大した働きをしてない抽象クラスの場合、「クラス階層の平坦化」
    • 意味のない委譲の場合、「関数のインライン化」、「クラスのインライン化」

Loops

  • 特徴
  • デメリット
  • 対策
    • 「パイプラインによるループの置き換え」

Duplicated Code

  • 特徴
    • 2つのコードがほとんど同じにみえるケース
  • デメリット
    • 修正には、重複している全てのコードに反映する必要がある

Object-Orientation Abusers(未熟なオブジェクト思考)

Temporary Filed

  • 特徴
    • インスタンス変数の値が、特定の状況でしか設定されないクラス※ 通常、オブジェクトは全ての属性を必要としていると考える
  • デメリット
  • 対策
    • 「クラスの抽出」で変数をあるべき場所に移動、「関数の移動」でその属性を使っているコード郡を移動で新たなクラスを作る。

Alternative Classes with Difference Interfaces

  • 特徴
    • 2つ以上のクラスが、名前は異なるが機能は同じメソッドをもつ
  • デメリット
    • 他のクラスへの置き換えができない?
  • 対策
    • 関数宣言の変更
    • 関数の移動」でインターフェースが同じになるように振る舞いを適切なクラスに配置する
    • 上記で重複したコードが発生するようであれば「スーパークラスの抽出」を使う

Dispensables (なくていよもの)

DataClass

  • 特徴
    • フィールド(クラス内の変数)とgetter, setterのみを有するクラス
  • デメリット
    • データクラスがある場合、大抵は間違った箇所に振る舞いが定義されている。
    • ハッシュ以上の役割を有してないので、ハッシュでいいじゃんとなる。
  • 対策
    • 「レコードのカプセル化」
    • get or set メソッドが他のクラスのどこかで使われるか調べ、「関数の移動」でdata classに振る舞いを移せないか検討
    • 関数全体が移せない場合でも「関数の抽出」によって移動できる部分を取り出す

memo

  • プログラムのモジュール化にあたっては、内部でのやり取りを最大に、外部とのやり取りは最小になるようにコードを分割する。
  • コメントの必要性を感じた時にはリファクタリングを行って、コメントを書かなくとも内容がわかるようなコードを目指す

あとで調査するcode smells

  • Primitive Obsession (基本データ型への執着)
  • Insider Trading
  • Large Class
  • Global Data
  • Mutable Data
  • Divergent Change (変更の偏り)
  • Shotgun Surgery (変更の分散)
  • Lazy Element (怠け者の要素)
  • Refused Bequest (相続の拒否)

参考