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

レガシーコード生産ガイド

私に教えられることなら

Squeakでオブジェクト指向の練習

Squeak Smalltalk

Twitterで度々呟いてるんだけど、オブジェクト指向できていますか?というスライドを見て「これは……」と思ったので練習してみた。

枠として使うMorphの中に、好きなMorphを突っ込むと、重力をうけつつ跳ねまわるようにしたい。

特に守ったルールは

で、できた。

f:id:phaendal:20150716123952g:plain

コードはgithubに上げた。sarとかにしたほうがいいのかな?

f := Morph new.
f openInWorld.
f color: Color black.
f width:  400.
f height: 400.
r := MorphRainer new.
r target: f.

こうやって準備しといて

r add: StepArrowMorph rand.
r add: ((CircleMorph new) color: Color random).

という風にMorphを追加すると跳ねだす。

r initVで全てのMorphを初期位置に戻せる。

感想

今回は最初から制約を守って作ったけど、「このオブジェクトはもうひとつ状態いるな、インスタンス変数3個目だ、継承しよう」を繰り返して脳内のスタックが深くなっていくと、今何やってたか把握しづらくなって辛かった。最初は5個ぐらいに緩くして作って、ある程度動いてからテスト書いてリファクタリングした方が多分楽しい。

インスタンス変数の数を制限する、つまりオブジェクトが持つ状態を極端に減らすのはかなりいい指針だった。これは後で書く。

「こういうコードはこうリファクタリングしよう」という手法も参考になるんだけど、変数の数とかメソッドの行とか、具体的な目標があると取り組みやすくて良かった。というかそれが無いと、しばらくできたかどうかを拙い経験で判断することになって成長が遅そうだ。

作り終わったあとには、後で使えそうな汎用的なクラスが9個と、今回の目的に特化してるけど後でも使えそうなクラスが3個と、悪くない設計に感じる。

バグも結構出たし、まだかなりありそうだけど、どこに目をつければいいか特定しやすくてそこまで負担には感じない。

あとはSqueakのブラウザがな、、クラスメソッドインスタンスメソッドを切り替えなきゃいけないのと、一度にメソッド一つしか表示できないのがかなり不便。12インチの小さめのノートで使ってるので尚更。これあれか、自分でエディタ作るべきか。。

余談

「全てはオブジェクト」という考え方を、ある程度大きなオブジェクトがいっぱいあるイメージで考えてたんだけど、今回のやり方で「どこまで分解してもオブジェクト」という視点を得た。

例えば換気扇ならファンとカバー、ファンは羽とモーター、モーターはコイルと……みたいに、どこまでも分解していく。そしてプリミティブなデータをラップするとこまで行ってから、それらを構成していく(構成の際につなぎ合わせるオブジェクトも作る)イメージ。

そういうやり方・見方で作っていくと、最終的に汎用的に使える多数のユーティリティオブジェクトと、問題を解くための糊付け用のオブジェクトが手に入る、かもしれない。

あと、自分にとってプログラムをわかりやすくするために必要なのは、一度に頭の中に入れておく「状態」を減らすことなのかな、と思った。

Clojureを使って、殆ど副作用無しでローグライクを作ろうと挑戦したことがあるんだけど、一つの関数を見るときに頭に入れておかなければいけない状態が巨大、という設計にしてしまって、最終的にREPLでのテストが極端に難しくなって諦めてしまった。

JavaScriptで大きめのローグライク作ったときは、バリバリの破壊的変更なコードだったんだけど、そこそこオブジェクトが持つ状態が少なくて、巻物とか杖とか魔法とかいろいろ実装できた。(ちなみにそれも凍結したんだけど、その原因は全部イベント駆動にしてしまって、どれがどういう順番で起きるかを把握できなくなったから)

今回はあるオブジェクトをいじるとき、常に2つの状態だけを考えていればいいので楽だった。何か問題が起きたら、その問題を担当しているオブジェクトにフォーカスできた。

オブジェクト指向を使わず関数やワードで組み立てていくやり方も相当好きなので、なんとか応用できないかなと考えている。例えばClojureで、ひとつの関数はマップを分配して受け取らない、マップの深さは1つ分しかいじらない、とかそういう。何かパラダイムシフトがありそうだな、何か。。

広告を非表示にする