この文書はCode Healt: Obsessed With Primitives?の翻訳です。
プログラミング言語は整数型、文字列型、マップ型といった、多くのコンテキストで便利な基本型を提供している。例えば、文字列型は人の名前からウェブページのURLまであらゆるものを保持するのに使える。しかしながら、コードが特別な抽象化を行わず、基本型に過度に依存すると、理解や維持が難しいものになり得る。
プリミティブオブセッション とは高度な概念を表すのに基本(プリミティブ)型を使いすぎることをいう。 例えば、このコードは形を表すのに基本型を用いている:
リファクタリング前
vector<pair<int, int>> polygon = ...
pair<pair<int, int>, pair<int, int>> bounding_box = GetBoundingBox(polygon);
int area = (bounding_box.second.first - bounding_box.first.first) *
(bounding_box.second.second - bounding_box.first.second);
pair
は適切なレベルの抽象化ではない。なぜなら、あるときはXとYを表すのに用いられ、またあるときは左下(左上だっけ?)と右上(え、右下?)を表すのに用いられるが、フィールド名は一般的なfirst
とsecond
である。さらに悪いことに、バウンディングボックスを計算したり、面積を求めたりといった計算のような領域固有のコードを基本型はカプセル化することはない。
基本型をより高レベルな抽象型で置き換えることはより明快でよくカプセル化されたコードを生む:
リファクタリング後
Polygon polygon = ...
int area = polygon.GetBoundingBox().GetArea();
プリミティブオブセッションの例をいくつか挙げる:
- 一連のmap, list, vectorなどで、値を一つのより高レベルな抽象化によって結合することで、一つのコレクションに容易にまとめることができる。
リファクタリング前
map<UserId, string> id_to_name;
map<UserId, int> id_to_age;
リファクタリング後
map<UserId, Person> id_to_person;
- マジックインデックス/キーによるvectorやmap。例えば、インデックス/キーが0, 1, 2それぞれに対してname, address, *phone #*が対応するようなときは、代わりに、それらの値をより高レベルな抽象化に束ねよう。
リファクタリング前
person_data[kName] = "Foo";
リファクタリング後
person.SetName("Foo");
- 複雜だったり構造を持つテキスト(例えば、日付)を保持するstring。代わりに、高レベルな抽象化(
Date
クラスなど)を用いることで、自己言及なアクセッサ(GetMonth
など)が提供され、正しさが保証される。
リファクタリング前
string date = "01-02-03";
リファクタリング後
Date date(Month::Feb, Day(1), Year(2003));
- 時間(秒など)を保持する整数や浮動小数点数。代わりに、構造化されたtimestampやduration型を使おう。
リファクタリング前
int timeout_secs = 5;
リファクタリング後
Duration timeout = Seconds(5);
任意の型(単なるintから洗練された赤黒木まで)はその役割に対してプリミティブとなりすぎる。 基本型が使われすぎているコードを見たら、リファクタリングするか、作者に丁寧に、より格調高くクラス1を使うよう進言することで、高レベルな抽象型を用いたより明快でカプセル化されたコードになるだろう!
-
classy ↩