(インターフェースを切る事と実現可能なソフトウェア規模についての話)どうやったらもっとまともにソフトウェアを書くことができるようになるのか?僕も若い頃、いや、まだ若いんだけど、本当にどうやってソフトウェアを書いてゆけば良いのかわからなくて、とにかくダラダラダラダラダラダラダラダラ「きっとやらなくてはいけない処理」を羅列したものだった。それも膨大な量のコードを。・・・と書こうと思ったのだが、実は自分自身はそうではなかった。以前書いた「アセンブラでこんなに美しく書ける方がいるんだ!」という純粋な感動体験が完全に邪魔をして、職業でソフトウェアを書く時に美しさに何かの美学を見出していた若かりし自分は、とにかくいかに美しく問題を解決するのか?についてひたすら毎日考えていた。このおかげで、人よりも余計な苦労をしなくてはならなかったのと、まだ若かった自分には設計や実装に関する知恵も知識もなかった上に余計なことに思慮を巡らせるものだからとにかく時間がかかっていた。本当にあれは今でも周囲にとっては単なる迷惑な新人だっただろうと想像できる。新しくソフトウェアを書こうと思う人にとっての最初の疑問は、どうやったらもっとまともにソフトウェアを書くことができるようになるのか?ということかもしれない。少なくとも自分はそうだった。インターフェースを切れるようになること「どうやったらもっとまともにソフトウェアを書くことができるようになるのか?」という疑問に対する答えのひとつは「インターフェースを切れるようになること」だ。「インターフェースを切る」というのは、つまり、対象物が何であるのか、というのと、それをどうするのか、という二つの事を分析して理解した上で、使う側と使われる側の双方の立場で物事を考えなければならない。この分析を経てようやく何かのインターフェースを策定できるようになる。この分析から理解、理解から策定に至るまでの道筋を立てられるようになると、インターフェースを切れるようになってくるのだけど、インターフェースが切れるようになってくると、大きな設計対象物でもそれらを部分に分割し、適切な階層構造を構築できるようになる。適切な階層構造を構築できるようになると、全体も部分もそれぞれの粒度で理解できるようになる。階層構造で設計対象物を見れるようになることでソフトウェアの全体構造を見る視点が養われる。この時点で規模の大きなソフトウェアを実現できるようになってくるんだ!この段階に入ってくると、設計対象物を様々な見方で分析して理解できるようになってくる。データの流れで全体構造を見たり、論理的な階層構造から全体構造を見たりすると楽しいものなんだ。何よりも大切なのは、楽しいと自分がやりたくなるっていうこと。苦労だけすれば良いってものではないからね。インターフェースを切るということは、全体を部分に分割するのに必要不可欠で、分割することで大きな規模のソフトウェアも実現できる。それだけではなく、全体を部分に分割する中で、関係のあるものと関係のないものを分離することが可能になり、よりソフトウェアが洗練される。何かのソフトウェアを書いていて「この処理は他でも使えるな」という処理があったとする。いう処理は一度書いておけばどんどん使えるネタとして持っておくことができるようになるんだ。インターフェースを切っていると出来る芸当もあって、インターフェースを切っていることで、何かの変更が必要になった時にコンパイラに助けてもらうこともできる。インターフェースに新しい機能を追加したくなったとする。インターフェースの定義を変更するだけで、そのインターフェースを使っている上位層をあぶりだすことができるんだ。変更して形の変わったインターフェースを使おうとしている上位のコードは、必ずコンパイルエラーになるでしょ?こんな風に、インターフェースを切るという話を始めただけでも、色々な側面の話が出てくるってこと。頭の片隅にあっても良いかもしれない。「教科書に載らない」と書くからには、教科書に書かれないような(でも非常に大切なこと)ことを書こうと思う。働き始めて直ぐに横にいた先輩は、とある業務用ビデオ装置のディスク制御ファームウェアを書いていた人だった。この先輩は日本語の使い方しかり、話し方しかり、色々と事細かに注文を付けてきた。入社したての自分にとっては煩いだけの先輩だったのだけど、今思うと非常に大切なことをここで学んだように思う。このシリーズの冒頭では、同じことを指示しているような一つの単語があったとしても、見方や認識の差から結果的に全く異なる場所に行きついてしまう点について書いた。実はこの先輩も同じような事を言いたくて若い頃の自分に事細かに指導をしてくれていたのだと思う。ここ約20年ほど、様々なソフトウェア開発者の設計や実装を見てきて、如実に実力の差が明らかになるのは、インターフェースの定義と実装の詳細についての明確な思想が育っているか、という点だ。経験の浅いソフトウェア開発者、あるいは経験はあるはずなのに一向に技術レベルが向上しないソフトウェア開発者には共通して「インターフェースの定義と実装の詳細を明確に区別できていない」という問題があった。この区別を最初に身に付けておくだけでも、相当なレベルの差になりそうだから、ここで非常に重要なこととして「インターフェースの定義と実装の詳細」について述べておくことにしたい。したら、とても重要でかつ唯一といって良いかもしれない。したらこのシリーズは既に今日の内容で終わってしまうことになるが、それはそれで良いだろう。インターフェースの定義インターフェースとは、ある面と別のまたある面の境界にある出入口のことだ。その出入口にはそれぞれ定められた規則があって、その規則に従う限り何かを通すことができる。”何か”っていうのがポイントだ。この通すものや規則を具体的に定めるのがインターフェースの定義。この定義に従う限り面と面を接続できる。これはソフトウェアの言語に依らない考え方ではあるのだけど、具体的な例が欲しいのでここではC言語で書いてみようと思う。*stream);例えば、上記の関数があったとしよう。この関数はFILEへのポインタを第一引数に取り、intを返値に持つ。この関数の実際の動作はインターフェースを定義した際に具体的な挙動が決められることになる。この関数はlibcの標準ライブラリだが、実際にこの一見簡単に見えるインターフェースでさえ、インターフェースの定義が明確になっていない限り、どのような動作になるのか見当もつかないはずだ。例に挙げるとstreamにnullを与えるとどうなるの?streamに与えるFILEへのポインタとは一体なんなの?streamのFILEへのポインタは開かれていないFILEだったらどうなるの?返値のintはどういう規則で返されるものなの?のように細かな動作を決めるのはインターフェースの定義に含まれる。いずれにせよ重要なのは外部から見た出入口の振る舞いを決めるということだ。このインターフェースの定義は何もソフトウェアに依らない。ハードウェアでも同じように考えることができる。このチップはI2CバスとSPIバスの橋渡しをするデバイスだ。インターフェースにI2CバスとSPIバスを取っている。実装の詳細とは、インターフェースの定義で定められた振る舞いを実現するためのものだ。乱暴に言うと、インターフェースの定義で定められた振る舞いさえ提供できれば、中身の実装がどんな風になっていても構わない。実装詳細の具体的な内容は時と場合によって正解もあり間違いも当然ながら存在するが。二つの数を与えると加算して返す関数があったとする。インターフェースの裏側にある実装の詳細がコンピュータで実現されていても良いし、小人さんが10人で寄ってたかって一生懸命計算していても良いし、紙テープで何か不思議な計算処理をしていても良い。インターフェースの定義に従っていさえすれば良い、というのが実装の詳細の基本的な考えだ。ここまででここまででインターフェースの定義と実装の詳細について簡単に説明した。具体的なイメージは上記の説明だけでは不十分で、これから先のシリーズでより具体的な設計や実装のイメージをつかめるようにしていきたいと思う。「教科書に載らないソフトウェア開発入門」なのだから、当然のように最初からソフトウェア開発の何たるかについてツラツラと書き記したい気持ちがあるのだが、やっぱり先の記事と同様に少しだけ寄り道をしようと思う。いうのも、15年ほどソフトウェア開発をしてきて振り返ると、今でこそ考えた通りに動作するソフトウェアが出来るようになったものの、始めた一年目なんかは本当にひどい状況だった。書くソフトウェアの全てが100%の確率で思った通りに動かない。動かないならまだしも、そもそもコンパイルも通らないしリンクとか言われてもワケがわからない。本当に詰まらないというか何をやっているのか自分でわからないような日々が続いた。そもそも自分がソフトウェア開発をやることになったのは、自分で設計した基板に載せていたマイクロコントローラのファームウェアをアセンブラでスラスラと書いているのが間違ってソフトウェア開発を統括する人の目に留まってしまったからだ。これは失敗だったと当時は何度も思った。そんな動きもしないソフトウェアを何年も作り続ける日が続いたのを今では懐かしく思うが、当時は本当にこれは駄目だなと何度も思った。手掛かりになればと色々な書籍やウェブを読み漁ったけど、どれもこれもピンと来ない。当時はなぜなのかわからなかった。何かのきっかけ物事にはきっかけというものがあるみたいだけど、自分のソフトウェア開発の状況を徐々に改善するきっかけになったのは、やっぱりこれも「どうしようもなく動かないソフトウェア」を作ってしまった時だった。本当に納品することになっていたソフトウェアを担当していた自分は、先輩から言われた前提条件に従って限定的に動作するソフトウェアを書いていた。この前提条件に従う限り、確かにソフトウェアは動作した。まずかったのは、その前提条件があまりにも厳しく、殆どの場合で適用できなかったことだ。そんなソフトウェアを納品に持って行った結果、御客様の落胆度合いは半端でなかった。不運にも、というか当然の結果として御客様の環境はその前提条件に該当しなかった。ソフトウェアについての説明を加えながら実際に動作をさせていったところ、あらゆる処理で例外が発生した。これには本当に作っていた本人が参ってしまった。当然ながら御客様はそれ以上に参ってしまった。今でも表情を思い出せるくらいの落胆さを示された御客様は、お引き取り下さいだったか何かを仰っていたように思うが、もう当時のこの瞬間を思い出すことも出来ない。記憶から消してしまったのだろう。この厳しい前提条件で限定的に動作するソフトウェアは、本当に世の中に何の役にも立たず、もっと言うと様々な人に害を与えるために世に生まれてきてしまったのだった。この話を聞きつけた上司(彼がその厳しい前提条件で良いと話していた)は、顧客と同様に激しく落胆し、私を担当から外して別の人間に修理させようといった内容の話をしていたようだ。その話を聞いた自分は落胆に落胆を重ねた落胆パレードに参加しているかのような錯覚に陥った。ひどく参って次の日は一日休んで何かを考える日に使った。心に決めたこと休んだ一日は本当に何をやっても手に付かなかったし、自分のボロボロのソフトウェアを修正する担当を逆恨みしたりした。出来ない人の典型みたいだ。