勉強会報告

勉強会(9/14の記事参照)でためになったことの走り書き。
私見をたっぷり含んでいます。そこをふまえてお読みください。

  • 具象クラスは可能な限り継承不可に

継承が本当に必要となるのは、おそらく抽象型による型の同一視の利点を使う場合のみである。
事実、機能の一部のみを使うなら、継承ではなく委譲を使うべきである。
拡張に対して開かれ、修正に対して閉じるというオブジェクト指向原則に従うなら、委譲ができるのであれば、Adapterなどで継承を利用せずにすむはずである。
自分はDecoratorパターンなどを使う場合を除いては、「基本的には」具象クラスを継承すべきでは無いと考えている。
特にJavaであれば、クラスのオーバーライドのされ方の性質により、本来必要であるスーパークラスのメソッドの処理内容が正しく処理されないケースが発生する可能性がある。
「基本的には」と前書きを置いているのは、場合によっては有効な場合があるためである。特に、GUI関連(Javaで言えばjava.awt.Frameなど)や、DBまわりはオブジェクト思考の原則を直接当てはめるには難しい性質を持っている(と考えている)ためである。これらのケースでは、差分プログラミングを行い、LSP(リスコフの置換原則)をあえて破ることで、逆によいコードが生成できる場合がある。
これらの理由から、具象クラスは特に理由がない限り継承不可とした方が結果として良いコードが生産されそうである。

TDDの最大の利点は、先にテストを記述でき、その後の保守がしやすいと主張する人もいる(だろう)。しかし、その場合テストには何を記述するべきだろうか。例えば、0以上100未満の整数を引数に取る関数をテストする場合、TDDを行っているとして、

    • -1
    • 0
    • 正常値(例えば20)
    • 99
    • 100
    • 101

のように、単体テストの用件を満たすコードを記述すべきだろうか。
これは、今後そのコードがリファクタリングされうることを考えれば、するべきではないと分かるだろう。なぜなら、仕様が変更されるだけでこのテスト(と、それを作るために利用した私の労力!)は無駄になるのだから。
これらの単体テストは、むしろそれほどの正確性が必要なクリティカルなシステム(例えば人命に携わるような、決してミスが許されないシステム)において残されていればよいはずである。(現場で働く人間(bleis-tift氏)の声を聞きほぼ確信できた。単体テストが保守作業の人に必ず渡されるわけではないためである。それなのに、変更されて無駄になる可能性が高いというのに、テストを記述するために労力を使いたいか?私は否である!)
断っておくが、私は単体テストを否定しているわけではない。単体テストを記述するタイミングは、テストファーストその時ではないと言っているのだ。単体テストを書くタイミングは、むしろウォータフォールモデルと同じく、コーディング(プログラミング)の後に設定すべきだろう。
むしろ驚くべきは、TDDを行うことで設計の質が向上することであると私は思う。自分の経験では、頭に「これは必ずうまくいく」と思って設計が行えたものは成功する確率が高い。逆に、「これでいいとおもうけど…?」と、少しでも疑問を覚えた場合、TDDを行って「クラス(群)が使われる立場に立ち」、そのクラス(群)が使用されるシナリオを考えることで、設計の段階では思いつかなかったアイデアをひらめくことがある。
このシナリオを考えた結果として、(特にpublicなインタフェースに対して)テストが残る。このテストこそ、TDDを行う際に導入すべきテストである。単体テストまでの完全性を求められないにしろ、テスト記述のための労力を単体テストのそれと比べてみれば、非常に小さいことがわかるはずである。
リファクタリングを行い、結果そのテストが切り捨てられ、別のものに書き換わっても、ほとんど労力を無駄にしていない結果、それはコードの生産力の上昇につながる。
聞いた話だが、Javaのテストでprivateメンバ、フィールドに対してリフレクションを用いて単体テストを行っている企業もあるそうだ。リフレクションはテストで利用すると、変更時に全てのテストがダメになる可能性が高すぎ、使うべきではないと思うのだが……
これを使うなら、よっぽどクリティカルなシステムを開発しているんでしょうねぇ。そうでなしに使っているとすれば……、クラスから自動的に単体テストを作るツールでも導入しているんでしょうか?少なくとも、手動でこれを書いているのは負けな気がします。

  • 古い手法を(大学などで)教えるべきか?

基本情報処理技術者試験などではテキストにいまだ載っていますね。それを歴史として教えるにしろ、やはりそこから変えていかないと、時間が立っても情報業界は良いものにならない気がします。むしろ、欠点を教えてしまうので、極力その情報は教えるべきではないと考えています。
オブジェクト指向の場合、80〜90年代の意見がそのまま記述されている(今はそれが否定されているとしても)ものがあるので、そういった本を改めて作ることを徹底的に廃止すべきだと思います。

  • 自分の能力に見合った仕事を行うべき。(ひどく言うなら、能力の足りない技術者はいらない)

戒めを込めてますが(汗)。ソフトウェアには、納品後の管理・改良と言った保守作業がほぼつき物です。その際に、能力に不相応な人物が元のソフトウェアを作った場合、泣きを見るのは保守作業者です。保守作業者が悪くても、その後の保守作業者が泣きを見るのは目に見えています。
では、能力がない人はどうするべきか。……まあ、一番いいのは実力をつけることでしょう。そうでないなら、例えば先にあげた単体テストなど、ある意味で単調作業ですが、後々に影響をあまり与えないような仕事を行うべきでしょう。

  • 設計者もコード記述に参加すべき

設計だけで満足している設計者の設計は、よくないことが多いはずである。これは経験からで、自分が設計した場合でも、コード記述中にぽんぽんと変更点が出てくることが多々あるためである。中にはほぼ完璧な設計を行ってしまう設計者もいると思うが、そういった人がいるなら、私はその人を尊敬する。「あなたはすばらしい設計者です。今後もプログラマ達に苦労をかけないすばらしい設計を提供してください」と。
責任を丸投げせず、自分の行った設計の過ちを認め、どこが悪かったかということをコーダー達と共に学習することが、プロジェクト全体を良い方向に持っていくための一番手軽な方法だと思う。



少々極端で、もしかしたらあなたの意見とは違う考えかもしれません。そうであるとしたならば、私のどこが間違えているのかを、理由をふまえて教えてくださいませ。私はいまだ学習の途中です。議論をし、重要なものは何か。それを考えることが、成長につながると信じています。