DebTab

  • ホーム
  • DevTabとは
  • 記事一覧
    • きたえる
    • かえる
    • つくる
    • みちびく
    • たばねる
    • つたえる
かんたんログイン
Githubでログイン
Githubアカウントでかんたんにログインして、DevTabをもっと便利に使おう。

DebTab成長しつづけるデベロッパーのための情報タブロイド

DebTab

ログイン

検索 検索

リファクタリングのエッセンス

写真増田 亨

つくる

2016.10.17

ポイントポイント

1

ギルドワークスの増田です。

ソフトウェア設計の目的は「変更コスト」を下げることです。 変更が容易なソフトウェアは、発展性に富み、生き生きとした活力を保ち続けます。変更がやりやすいソフトウェアは、事業やサービスの成功をもたらす原動力になります。 変更がたいへんなソフトウェアは、しだいに活力を失っていきます。誰もさわることができなくなり、しだいに、事業やサービスの足かせになっていきます。

変更コストの大きな違いを生むのは、プログラミング言語/フレームワーク/開発ツールの違いでありません。ちょっとしたコードの書き方の違いの積み重ねが、ソフトウェアの変更コストに大きく影響します。

※注意:この記事は2014年9月9日にGuildWorks Blogで公開したエントリを移行したものです。

変更がたいへんになりそうなコード

  if(date.isBefore(SUMMER_START)||date.isAfter(SUMMER_END))
      charge = quantity * winterRate + winterServiceCharge;
   else
      charge = quantity * summerRate;

冬季と夏季で異なるサービス料金の計算をしています。 このコードは、それほど複雑ではありません。しかし、場合分けが増えたり、計算ルールが追加されると、if文が入れ子になったり、条件文の論理演算式が、膨らんでいきそうです。

このまま、このコードを変更し続けると、しだいに、コードがわかりにくくなり、変更が困難なプログラムになりかねません。

変更をやりやすく改善したコード

 if(notSummer(date))
      charge = winterCharge(quantity);
  else
      charge = summerCharge(quantity);

...
private boolean notSummer(LocalDate date)
{
    return date.isBefore(SUMMER_START)||date.isAfter(SUMMER_END);
}

private int winterCharge(int quantity)
{
    return quantity * winterRate + winterServiceCharge;
}

private int summerCharge(int quantity)
{
    return quantity * summerRate;
}

これは、マーチンファウラの「リファクタリング」にでてくる「条件記述の分解(p.238)」です。 条件の記述/then部/else部を、それぞれ「メソッドに抽出」した例です。

改善前のコードと比べてください。 改善前のコードは、条件判断の論理演算式と料金の計算式を、そのままべた書きしています。 リファクタリング後(設計改善後)では、メインのif文は、メソッドを呼び出すだけに単純化しました。それぞれの演算式の詳細は、メソッドに隠ぺいしました。

設計改善後のコードのほうが、変更がやりやすくなっています。

  • 場合分けの構造がわかりやすい(場合分けの変更がやりやすい)
  • それぞれの計算式を分けて宣言しているので、独立して変更しやすい

変更する時に、うっかりバグを混入させるリスクも減っていそうです。

さらなる改善

メソッドの抽出による変更のやりやすさの改善は、手続き型プログラミングのスタイルの延長にある改善方法です。 オブジェクト指向の設計スタイルだと、このコードは、さらに、変更に強く改善できます。

notSummer()メソッドは「変更コスト」を考えると、いやな臭いがします。 冬季・夏季の判断が、プログラム全体の中で、このクラスのこの場所でしか必要ないなら、このままでも良いでしょう。 しかし、実際には、あちこちで、冬季・夏季の判断が必要になりそうです。そして、あちこちに、同じような論理演算式が重複して登場しそうです。

冬季・夏季を判断する式の重複は「変更地獄」のはじまりです。夏季の判断ルールが変更になったとき、プログラムのあちこちを調べまわって、すべての重複した判断式を、まちがいなく変更しなければなりません。重複が増えるほど、対象箇所の見落としや、変更の間違いのリスクが膨らんでゆきます。

コードの重複を防ぐためのオブジェクト指向らしい改善


if(date.notSummer())
charge = winterCharge(quantity);
else
charge = summerCharge(quantity);

...

class ServiceDate
{

  private final LocalDate date;
  ServiceDate( LocalDate date )
  {
    this.date = date;
  }
...

  boolean notSummer()
  {
    return date.isBefore(SUMMER_START)||date.isAfter(SUMMER_END);
  }
}

サービスを実行する日を表現するServiceDateクラスを作成しました。 夏季か冬季かの判断の論理演算式を、元のクラスから、ServiceDateクラスに移動しました。

ServiceDateクラスにロジックを移動したことにより、プログラムの中で、冬季・夏季の判断式が登場するのは、このクラスだけになります。プログラムのあちこちで冬季・夏季の判断ロジックが重複する心配はありません。 こういう構造になっていれば、冬季・夏季の判断ルールの変更は、簡単で安全な作業になります。

オブジェクト指向設計とは、こういうちょっとした工夫を実践的に積み重ねることです。コードをわかりやすく整理し、コードの重複をなくし、プログラムの変更を楽に安全にする実践的な工夫がオブジェクト指向設計なのです。

現場で、コードレベルで、実際に

ギルドワークスでは、こういう設計の考え方ややり方を学ぶためのワークショップやセミナーを定期的に開催しています。また、みなさんの現場に出かけて実際のコードを題材にやってみるオンサイトのワークショップにも力を入れています。 ご興味を持たれた方はギルドワークスのホームページからお気軽にお問い合わせください。

共感した

ポイントポイント

1

取り消す

この記事に共感したら、何度でも押してこの記事のポイントをみんなでアップしよう。

自分の感想を残す

この感想は、サイトに公開されることはなく自分にしか見えません。自分の考えのログを残すために感じたことを登録し、のこしておきましょう。あとで振り返ったときに、あのとき自分はこう考えていたのかということを知ることにより、あなたの成長へとつながります。

Githubでログイン

Githubアカウントでかんたんにログインして、DevTabをもっと便利に使おう。

  • ひとつ前の記事

    みんなの気持ちを揃えるための「ミーティング」まとめ

  • ひとつ後の記事

    if文の条件式の書き方

この記事もどうですか?

状況判断で駆動する「機略型のアジャイル開発」

見積もりができない。どうする?  見積もりって大事ですよね。見積もりは何のために行なうものでしょうか…

つくる

たばねる

2017.12.24

ポイント
4

「場合分け」の書き方あれこれ

ギルドワークスの増田です。 以前に書いたリファクタリングのエッセンスの続編です。 場合ごとのロジック…

つくる

2016.10.19

ポイント
1

キャンバス・マップをまとめてみる(前半)

ギルドワークスの佐々木です。 今回はIT業界に出回っている様々な「キャンバス」や「マップ」をまとめて…

つくる

2016.11.11

ポイント
0

シェア
  • Twitter
  • このエントリーをはてなブックマークに追加
  • Google Plus

ログインして
ブックマーク

  • Twitter
  • このエントリーをはてなブックマークに追加
  • Google Plus
  • ログイン
LINE@

新しい記事が出たときや、注目の記事などを
定期的にLINEでお知らせしていきます

LINEで登録

LINEイメージ

DevTab
成長しつづけるデベロッパーのための情報タブロイド

株式会社ギルドワークス
https://guildworks.jp
  • プライバシーポリシー
  • お問い合わせ

Copyright © GuildWorks Inc. All Rights Reserved.

ページのトップへ