読者です 読者をやめる 読者になる 読者になる

Line 1: Error: Invalid Blog('by Esehara' )

または私は如何にして心配するのを止めてバグを愛するようになったか

>> Zanmemo

あと何かあれは 「esehara あっと じーめーる」 か @esehara まで

プログラミングにおける過度な抽象化についての、若干のメモ

はじめに

 少し思うところがあって、『コード・シンプリシティ』を読みかえしている。

 というのも、この本には「一般的すぎるコードを書く」という項目があって、そのことがここ最近引っかかっているからだ。なぜ引っかかるのかというと、それはたびたび「抽象化」というか「共通化」という部分に対するアプローチにおいて、どこかモヤモヤすることがあって、それが何処から来るものなのかな、というのをちゃんと自分の中で言語化しておきたかったからだ。

継承

 クラスベースのオブジェクト志向の場合、「継承」という概念がある。とりあえず、Web上に散らかっている適当な解説には、次のように書いてある。とりあえず、疑似コード的なものをPythonで書いてみよう。

class Animal(object):
    pass

class Human(Animal):
    pass

class House(Animal):
    pass

 通常、このように「動物」というクラスが存在し、そしてその配下に「人間」と「馬」というクラスが原則ほどには存在する、といったように説明される。確かに、これは「継承」の説明としては正しい。このように実装しておくことによって、HumanとHouseに波及させたい変更は、Animalに書き、そしてそれぞれ特有の役割に関しては、各Classに書けばよい、というのが一般的な継承の説明だと思う。

 ……と思うのだけれども、しかし、最近考えているのは、説明としては正しかったとしても、実はこの方向性というのは、「実装の方向」としては逆向きなんじゃないんだろうか、という風に思い始めている。

YAGNI原則

 DRY原則ほどには余り言われないことの一つとして、YAGNI原則、つまり「あなたにそれは必要がない」と呼ばれる原則がある。これは、プログラマーが未来の実装にあれこれ考えすぎることに対して諌めるための原則という風に理解している。どうしてYAGNIが言われるようになったのか。これは実際の例を読んでの推測にすぎないが、要するに、「必要でないことがたびたびのコーディングの邪魔になる」という側面がある、ということだ。

 例えば上記の場合を考えてみよう。例えば、何らかのアプリケーションでクラスとして「人間」と「馬」が必要になる、と事前設計のときに解ったとして、「おっ、じゃあこれは動物としてまとめたほうが良さそうだぞ」という風に考えるかもしれない。しかし、それは余りにも早すぎる抽象化かもしれない。

 例えば、貴方が作っているアプリケーションが「どれだけの荷物を運べるか」というのを調べるためのアプリだったとしよう。そこで運ぶ人には「人間」と「馬」がいる。確かに、この二つは「動物」としても抽象化できるが、しかしこの二つはむしろ「運搬者(Carrier)」として抽象化したほうが、この二つのクラスが「何として抽象化されるべきなのか」ということが明確になる気がする。

 さすがにこんな極端な例は無いとは思うんだけれども、しかし最初に思っていた「こういう風に抽象化したらよさそうだ」ということと、実際にコーディングをしてみてむしろ「こうだったらよかったんじゃないか」ということが発生したりする。そういう無駄というのは起きるし、またその無駄を書き直せない場合だってある。

インクリメンタルな開発とデザイン

 ではこれを避けるためにはどうすればいいのか。

 『コード・シンプリシティ』では、インクリメンタルな開発とデザインを推奨している。つまり、一つずつ設計し、構築していくというやり方だ。つまり、小さく作っていくことで大きな全体像を浮かび上がらせる、ということだ。そして、もしその回転の中で、抽象化できそうな部分があれば、抽象化し、親クラスとする。

 このやりかたは、たぶん「テスト駆動開発」とも相性が良い。テスト駆動開発のメリットというか、重要な点の一つとして、何度も強調されていることの一つに、「リファクタリングしやすくなる」ということだ。リファクタリングしやすくなるということは、つまりそのようなクラスの再整理も比較的やりやすいことを示している。ここで、ボトムアップ的な抽象化が行なわれる(個人的には、このようなボトムアップ型で作っていくほうが好きではある)。

 もちろん、インクリメンタルな開発だけがすべてではないわけで。例えば、次のような考え方だって出来る。

多くの人々が事前設計によって問題を部分に分割する方法(今なら、問題をクラスに分割する方法)を編み出しているが、私に言わせれば、事前の判断は間違っている。

私は、広くかんがえられていることとは逆のことをアドバイスしたい。できる限り早くコーディングを始めよ、ということだ。問題を見つめているときに、まず誤ったコードを各のである。

私がプログラミングするときは少数の大きなクラスでプログラムを作る。そして問題をよりよく見通せるようになったところで、本番コードを書く。今のプログラマたちは昨日明日への分割を事前に行い、十分な情報がないときに作った構造に実装を押し込めようとしすぎることが多い。(p28)

プログラマのためのサバイバルマニュアル

プログラマのためのサバイバルマニュアル

あと単純な自分の理解の足りなさ

 あと、やっぱりどうしても自分は、いきなり抽象的な部分にステップアップするとよくわからなくて、合間にある程度は具体的な、それがどういう実装に結びつくのかというロールマップというか、あるいはそれって役に立つのかしらねー的な部分で、自分自身がいまいち経験の部分というか、想像が出来ないという部分もありそう。あとは、変に疑心暗鬼になったりとか。その辺は開発者同士の信頼とかになるのかなという気はする。

まとめ

 この辺りに関しては、本当にさじ加減が解らない。現実的な解答としては、「テスト駆動で実装→リファクタリング」を繰り返しながら、ある程度まで共通化できそうな見通しが立ちはじめたら、そこで上位に抽象化したモデルを持ってくる、という感じのスタイルが自分には合っている気がするなあ。あとやっぱりドメイン駆動開発とか、その辺の部分を理解することでもう少し見通しが出来そうな気もしている。

参考