書く

 一日寝て起きると微妙に忘れている。一日バイトしたら結構忘れている。

前陣速攻が一日練習を休めば取り戻すのに一週間はかかる。
三日練習を休めば使い物にならない。

松本大洋『ピンポン』より

 オシムも「休みは何も生み出さない」と言っていた。しかしややこしいのだが、オシムは長いオフを否定したりはしていない。卓球選手にだって長いオフは必要だ、というのは『ピンポン』のオババも分かっているだろう。

 身体に染み付いた技術の勝負なら、長いオフの後でもきっちり身体を作り直して試合勘を取り戻せば、また上にいける。なんか戻らないこともあって、一年だけはすごくいい成績だったけど、その後は平凡な選手になってしまう、ということもあったりはするが。野球の松井とか小笠原とか、シーズンが始まってしばらくして、夏ぐらいにならないと本来の調子が出ないという選手もいるが。

 プログラミングだと、一日休むと取り戻すのに半日ぐらいかかったりする。計算機を動かすわけだから何をどうするか完全にわかってないとちゃんと動いてくれない。しかし完全に分かっているということはあまりなくて、九割ぐらいわかったら書き始め、わかってない一割は即興で埋めていく。即興の部分がちょっとでもずれていればバグる。しかしプログラマが論理を誤るというのはとても稀なことだ。「ややこしいアルゴリズムでちょっとした分岐のミスをした」とか、「ライブラリの仕様が思っていたのと違っていた」とかで上手く動かないことはあるが、プログラマがまともなら、事前に考えていた九割に間違いというのは起こらない。

 しかし寝て起きると、九割だったものが八割になってたりする。自分でも何をどのくらい忘れてるか分からないので、なんか微妙に分かってない気はするのだけど、とりあえず書き始める。どうもしっくりいかない。リファクタリングを何度か繰り返してるうちに思い出してくるのか、新たに理解しなおすのか、わからないけどだいぶいい感じになってきて、動かしたらちゃんと動く。ちゃんと動くのはまあ当たり前で、どこまで分かりやすいクラス分割モジュール分割を行い、ややこしいアルゴリズムをきっちり書いて隠蔽し必要な全てのケースで再利用できるようにしておき、というのをどこまでやれるかが勝負だ。ちょっとでも忘れてしまうとたいがい一発できれいにはいかない。

 きれいに書けていれば、長いオフの後でも一週間ぐらいで全容を思い出せる。自分のパターンがきっちり出来ていれば、「書くべき機能」と「書かれたソースコード」はほぼ一対一で対応する。機能さえ思い出せれば何を書いたかも思い出せる。機能をどのように分割し、どのようにソースコードに落としたかは、全体の機能からほぼ完全に推測できる。

 しかし自分のパターンは変わっていくものなので、変わってしまった後に自分のソースを見てもよく分からない。どうにかしたかったら今の自分の価値観でおかしいところを書き直していってあげることになる。

 それでも変わらない物はあって、勝負どころになるのはパブリックメンバをどこまで減らせるか、パブリッククラスをどこまで減らせるか。

 ある機能を使うために必要なのは、機能にアクセスするインターフェースと、引数として渡すクラス、戻り値として返って来るクラスだけだ。機能を実現するクラスは全て実装の詳細だ。機能を使う側から見たら関係ない。

 そういうクラスはinternalにして隠す。C#では、internalはアセンブリを分割しないと隠せない。しかしアセンブリは相互参照できないので論理的に参照、被参照関係が定まる大きなモジュール以外でやると致命傷になる。

 しかしモジュールはもう少し細かく分けたい。名前空間で隠すことになる。usingする名前空間としない名前空間を決めて、usingしない名前空間のクラスはinternalに、機能にアクセスするinterfaceと引数、戻り値クラスをpublicにする。そうすると、実装の詳細がpublicクラスからはみ出す時にコンパイラが警告してくれる。internalはアセンブリを分けなくても大概上手く働く。publicクラスのinternalメンバは名前空間で隠してはくれないが、そこを隠すためだけにもう一つラップしてもそんなに間違いにはならない。