2013.05.17
「Primitive Obsession(基本データ型への執着)」を克服するリファクタリング
ウィキペディア - コードの臭い
http://ja.wikipedia.org/wiki/%E3%82%B3..

<コードの臭い(英: Code smell)とは、コンピュータプログラミングにおいてプログラムのソースコードに深刻な問題が存在することを示す何らかの兆候のことを言う>。

プログラミングにおける「コードの臭い」とは、かんたんに言うと、「ダメな設計のパターン」である。

このウィキペディアの解説ページでは、「重複したコード」「長すぎるメソッド」「巨大なクラス」など、9個の「コードの臭い」が紹介されている。

ここに出ていないもので、よく知られた「コードの臭い」として、「Primitive Obsession(基本データ型への執着)」というものがある。

c2.com - Primitive Obsession
http://c2.com/cgi/wiki?PrimitiveObsession

<Primitive Obsession is using primitive data types to represent domain ideas. For example, we use a String to represent a message, an Integer to represent an amount of money, or a Struct/Dictionary/Hash to represent a specific object.>

(大意:「基本データ型への執着」とは、ドメイン(問題領域)の概念をあらわすのに、基本データ型を用いることを指す。メッセージをあらわすのに文字列を使う、金額をあらわすのに整数を使う、なんらかのオブジェクトをあらわすのに構造体・ディクショナリ・ハッシュを使う、といったものが、その例である。)

メッセージをあらわすのに文字列を使い、金額をあらわすのに整数を使うのは、あたりまえじゃないのか?と考える人は、すでに「基本データ型への執着」という病に冒されているかもしれない。

有名ブログ「Coding Horror」の「Code Smells」という記事(2006年5月)では、「Primitive Obsession」が次のように説明されている。

<Don't use a gaggle of primitive data type variables as a poor man's substitute for a class. If your data type is sufficiently complex, write a class to represent it.>

(大意:基本データ型を寄せあつめて、貧者のためのクラス代用品として使うべきではない。対象のデータ型が十分に複雑ならば、それをあらわすクラスを書いたほうがいい。)

つまり、もし文字列がなんらかのメッセージをあらわすのであれば、メッセージは文字列として扱うのではなく、Messageというクラスを作って、Messageのインスタンスにしたほうがいい、という話だ。

Messageというクラスにしておけば、例えば文字列中のなんらかのパターンを置換するメソッドとか、一定の長さで打ち切るメソッドなどを、Messageクラスに付け加えることができる。

もしメッセージが文字列のままだと、こういう処理をオブジェクト自体に持たせられないので、データから離れた場所に、メッセージ処理用の関数がバラバラに置かれることになる。これだと、プログラムのメンテナンス性が下がるし、将来の変更にも弱くなりやすい。

ファウラーの『リファクタリング』にも、「コードの臭い」のひとつとして、この「基本データ型への執着」が出ている。ファウラーはこう書いている(81ページ)。

<オブジェクト指向を始めたばかりの人は、小さなオブジェクトを使ってちょっとしたことをさせるのを嫌がる傾向があります。金額と通貨単位を組み合わせたMoney(貨幣)クラス、上限と下限を持つRange(範囲)クラス、電話番号や郵便番号を表すための特殊な文字列クラスなどがこの例に該当します。ほら穴から抜け出し、日の当たるオブジェクト指向の世界の住民となるには、個々のデータに対して「オブジェクトによるデータ値の置き換え」を行うことです>。

「オブジェクトによるデータ値の置き換え(Replace Data Value with Object)」は、ファウラーがこの本でとりあげているリファクタリングのひとつで、ファウラーの「Refactoring Home Page」にも解説ページがある。

Refactoring Home Page - Replace Data Value with Object(オブジェクトによるデータ値の置き換え)
http://refactoring.com/catalog/replaceDataValueWithObject.html



リファクタリングの前は、「Order(注文)」というクラスが、文字列で顧客情報を持っている。これを変更して、「Customer」というクラスをつくり、顧客情報はCustomerのインスタンスとして持つようにリファクタリングしている。

このようにして、いったんクラスを作ってしまえば、そのオブジェクトに手を出している処理のうち、このクラスのメソッドにできるものが、けっこう見つかる。こうして、データとそれを扱う処理を、同一クラスにまとめることができるわけだ。

じつは私自身も、この「Primitive Obsession(基本データ型への執着)」からなかなか抜け出せないでいる。つい、文字列やリスト、ディクショナリなどを、そのまま使ってしまうのだ。

これが「貧者のためのクラス代用品(a poor man's substitute for a class)」とは、うまい表現だと思う。「貧者のための」というのは、わざわざクラスを作らなくても、かんたんに手に入るという意味だ。しかし、けっきょくはそれを処理するロジックがあちこちに散らばるので、あとで苦労することになる。ダメな設計というものは、まさに「技術的負債」である。


関連エントリ:
デザインパターンよりも、まずリファクタリングを学んだほうがいい
http://mojix.org/2013/02/10/design-pattern-refactoring
ケント・ベック『実装パターン』(2008年) 実装パターンの6つの原則
http://mojix.org/2012/11/21/beck-impl-pattern