まずは、プログラミング以前の問題として、顧客が何を欲しがって発注してく るか、ところから始めましょう。
1次発注でない限り(下請けということね)、何らかの形で「仕様書」という ものが渡ってくるわけですが、この仕様書というやつ、かなり不完全なもので あることが多いのです。
ひどいときは、A4、3ページの仕様書(しかもほとんどが図)でプログラム を作ったこともありました。
で、プログラミングに先立って、この「仕様書」をまず熟読します。まず1 回読んだだけでは、何を作れば良いのか、さっぱりわからないはずです。
#仕様書を安易に信じるな
仕様書上は簡単な処理かな?と思われる部分に意外な落とし穴があったりし ます。たとえば、「XXXを測定する」「統計処理を行う」といった項目があっ たとしましょう。
ふむ、どちらも簡単じゃん。と思って読んでいくと、どうもこの2つの機能 が「同時に」動かなければならないことになっていたらどうでしょう?マルチ タスクの処理であっても、セマフォやキューなどを駆使する必要が出てきます し、ましてDOSでなどといったら、かなり難易度の高い仕様に変貌します。
場合によっては、この「同時」が明記されていないことがあり、それは、行 間を読むことで初めてわかることだったりするのです。
#仕様書には書いていない機能が必ずある
さて、仕様書に書いてある機能を実装すれば、プログラムは出来上がるので しょうか?そんなことはないんですよね。必ず機能的な不備があります。場合 によっては、この隠された機能が全体の半分を占めていた、なんて言うことも ありますから、注意しましょう。
#顧客は簡単なことと難しいことを逆に考えていることがある
お客様はプログラマではありません。よって簡単にできることと難しいこと の区別はつきません。中途半端な知識で仕様書を書くことも多いのです。
で、当然のこととして、「XXXでは実現している」(XXXは某マイクロ ソフトの商品名)なんて当然のごとく言ってくれたりします(ここで切れてはい けません^^;)。
まあお客さんと打ち合わせしてると「うがぁ」と唸って切れそうになること もあるはずですが、そこはお客様と割り切って冷静に対応しましょう。
これでは、ラチが明かないはずなので、その仕様書から、「何をしたいのか」 を洗い出します。往々にして、仕様書を作成するほうでは「何をしたいか」は 自明なこととして、半分「機能」に翻訳してから、仕様書を書いてくることが 多いので、この作業を怠ると、矛盾した機能がつまったがらくたが出来上がり ます。
ここで、必要な技量として、「行間を読む」という技量が必要になります。 普通、プログラムを依頼するほうは、何がほしいのかきちんと把握していると 思いますよね、普通。
しかしです。その実態はというと、ほとんどの顧客が何が欲しいかを正確に はつかんでいないのです。お客さんは、「こんな機能があれば...」とか「こ ういう風にすれば...」と考えて、仕様を作ってくるのですが、本当のところ、 何が目的なのかを十分把握しないまま、仕様書を作成して出してくるのです。
ここで、見極めを誤ると、その仕事自体が「失敗」ということになり、最悪 の場合、お金にならないばかりか、逆にお金を取られてしまったりします(恐 いですねえ)。
で、行間を読むというのは、仕様書の端はしから、「プログラムの目的は何 か」を見極めることにあるのです。これは、明確には書いてありません。まし てや一時発注の場合は、仕様書すらありませんから、この時点での整理が非常 に重要になります。
#限定的な表現に注意
「基本的には」とか「XXXの場合」とか限定的な表現に出会ったら注意し ましょう。「基本的には」なんてのは、よく使いますけど、仕様書上では言語 道断な表現ですよね。
あとは、機能に矛盾がないかどうかよく検討すべきですね。お客さんが想定 しているモデルに潜在的なバグが含まれている場合があり、この場合には、小 手先では対処不可能なことも多いのです。
#何が重要か
実現したい機能には重要度の軽重があります。これをきちんと把握していない と、本当は重要な機能なのに、おまけ的に実装してしまったり、ということが あります。
さて、「何をしたいか」がはっきりしたところで、それを実際のプログラム になるよう機能にブレークダウンする必要があります。
私の場合、ここでは2〜3日ぼけーと考えたりします。側からみると「こい つ遊んでるんじゃないか?」と思われたりしますね。たばこ吸いながらぼーっ としてますから。
でも、これが重要なステップだったりします。何というか、豆腐が固まるよ うに、仕様書から読み取った機能が、徐々に固まって来る時期なわけです。
ここでは、大まかなブロックをどう作って、どう組み合わせればよいか、ど ちらかというと、トップダウン的な解析を行っているわけです。といっても、 完全なトップダウンでは、最下層との擦り合わせができなくなるおそれが出て きますから、それも多少は考えながら、プログラムが頭の中で固まって来るの を待ちます。
#例外処理はなるべく少なく
これは、プログラムのモデルを構築するときに非常に重要になります。場合 によっては、例外処理の塊になる場合すらあります。この場合は、一つ上のメ タモデルを考えて、それで処理するようにするといった方策が必要になるかも しれません。
#きちんとしたモデルを考える
GUIで自動計測をしたい、などという要求があった場合には、普通のプログ ラムではなく、マクロ言語を搭載した処理系などを考えたほうが良いかもしれ ません。
大幅に仕様が変わる機能のくせに「自動で計測できること」と1行ですまさ れることも多いので、「自動」という言葉は要注意だったりします。
まあ、1つの言葉で全体がひっくり返ることもあるという例ですけど、この ような場合でもきちんとしたモデルを考えれば対処できるはずです。
十分頭の中でプログラムが発酵してきたら、次に機能仕様書を作ります。チー ムでやる場合はきちんとしたものを作る必要がありますが、一人に近い場合は、 疑似コーディングのようなもので十分です。ただし、疑似コーディングだと、 コーディング規則に縛られてしまう場合があるため、私はよく、次のようなド キュメントを書いていました。
・XXXを測定する {
・測定インターフェースの初期化 { ・シリアルポートの初期化 ・リセットコマンド出力 } ・測定パラメータの読み込み { ・パラメータファイルのPATHを得る ・パラメータファイルを開く { ・"measure"タグ検索 ・"measure"ブロックの読み込み } } ...
}
{}はブロックですね。このようにトップダウン的に機能を{}で細分化しなが ら、適当と判断できるところまでやるべきことを書いていくわけです。if文な どもC言語ライクにブロックで書きます。
書き方は、問題ではありませんが、きちんと機能を細分化できるように書い ていくわけです。
このようにして、機能を書き下していくと、所々に同じ機能が現れますので、 そのパターンを見つけたら、関数の形に直して書いていきます。
このようにして、自然とモジュールが出来上がっていきます。
#似て非なるものに注意
機能レベルでは、非常によくにているのだけれど、細かなところの違いで、 同じ処理にはすべきでない場合もあります。
これを、むりやり一緒にしてしまうと、悲劇の始まりになったりしますから、 本当に類似した処理なのか、十分検討するべきでしょう。
あとは、コーディングするだけです。すでに機能は整理されているので、ほ とんど機械的に仕様書をプログラム言語に翻訳していくだけです。なれてくれ ば、仕様書上はかなり大まかな機能で書いても、翻訳はできるようになります よね。
#自動書記
コーディングレベルになると、昔は「自動書記」状態でコーディングしてい ました。集中してコーディングすると、だいたい3〜4時間で600行から700行 程度のコーディングはしていたように思います。
これが結構大変な作業ですね。場合によっては、「テスト仕様書」を作るこ とがあります。
デバッグは、機能単位で行う、「単体テスト」と全体を通して行う「結合テ スト」があります。
最近では、ユニットテストを行うツールなどもありますから、多少は楽にな りますが、すべてのテストケースを想定することは非常に困難です。どうして も抜けが出ますから、十分なテストが不可欠です。
#プログラマは、常にバグを避けるテストを作る
「マーフィーの法則」ですね。自分ではなるべく気を付けてテストしている つもりなのですが、どうしてもこの法則に引っかかります。まあ、仕方がない かな?とは思っていますが。
まあ、心構えはこれくらいにして、ちょっと今までの経験の中から、お話し することにしましょう。
まあ、かなり昔の話になりますが、計測用の画像処理の専用システムの一部 を請け負ったことがありました。
いまでこそ、画像処理なんて、メインCPUでやったほうが早いですが、当時 は16ビットの時代ですから、画像処理は専用CPUに任せる、というのが一般的 で、高価な(500万程度)の画像処理ユニットがあったんですね。
このCPUがとても曲者で、いわゆる「フォンノイマン型」ではない、アクター モデルに基づいた「データ駆動型」のCPUだったわけです。
プログラミングといえばフォンノイマン型しかやったことがなかったわけで、 最初はどうプログラミングすれば良いのやら?という状態だったのです。幸い、 本屋によったら、該当CPUの解説書があったので、即購入して読みました。
で、何とか見当がついて、プログラムを作ろうとしたら、専用のエディタが バグだらけで、使い物にならない(;_;)。まあ、どちらかと言えば、CADに近い ツール(回路図を書くようにしてプログラミングする)だったのですが、一度間 違うと取り消しがうまくできないことがあり、これには泣けました。
で、どうしたかというと、テキストで書くための言語を作って、そのコンパ イラを作って、アセンブラをに落として、という手順を取る事にしました。要 するに専用エディタは使い物にならないから、捨てて、自分で開発環境を作っ たわけです。
まあ、自分で開発環境から作るなんていうのは、そうそうあることではあり ませんでしたが、バグだらけのCADで作るよりははるかに効率的にプログラミ ングすることができるようになりました。
幸い、プログラム自体はかなり簡単なもので(指定された矩形領域の濃度平 均を得る)、確か30個ほどの部品で作れたプログラムだったように記憶して います。
このように、時には開発環境から作らなければならないこともあるという、 非常にまれな経験をしたわけです。この経験は、のちのち「やってできないこ とはない」という自信につながるわけです。
ただし、このような判断を行った背景には、
という、要素があったわけで、どちらかがかけても、使いにくいCADで書く 羽目になったか、仕事自体を放棄することになったはずです。
もともと言語には興味があって、algol 60の本とかを読んでいたので、比較 的抵抗なく、簡単な言語処理系を作ることができた、ということで、日頃のお 勉強がひょんなところで役に立つ、という話でした。
某社の形状計測システムを請け負うことになったのですが、何をどう間違っ たか(やっぱり私が悪かったのかなあ)自作のウインドウシステムを使って測定 プログラムを作ることになってしまったお話しです。
時期としては、Windows 3.1が出るか出ないかという時期で、「やっぱりGUI がいいよね」「でもDOSじゃできないし」「Windowsでは測定自体が難しいぞ」 ということで、潜在的な需要はあると見込んで「DOSで動くGUI」を開発してい たわけです。
それを元請けの担当者に見せたところ「使いましょう」ということになって しまったわけです。
で、ここからが大変でした。一応デモできる程度にはできていましたが、ウイ ンドウシステムも作りながら、の作業になるわけですから。
一応作業分担として、ウインドウシステムは私のほうで作成し、その上で動作 するアプリケーション(実際の測定プログラム)は元請け側で作成する....という ことになってはいたのですが、案の定、元請け側がハングアップしてしまって、 すべて私が作るハメになってしまいました。できたてのシステムを実際の仕事に 使う場合には、こんなこともあるわけです。
こんなことをするのは、はっきりいって「無謀」ですね。まあ、若いからこそ できた暴挙だったとは思いますけど、時には暴挙も必要でしょう。苦労はしまし たが、その分の経験はできたのではないかと思います。
さて、ここまではRubyは一切出てきませんでしたが、ここからはばんばん出て きますよ。ということで、SGmailとSGumapのお話しです。
今までの話は、まあ下請けの悲哀というか、苦労話というかそんな話でしたけ ど、SGmailやSGumapは完全な自主開発プログラムですから、下請けとはまた違っ た苦労(楽しみ?)をすることになります。
この講演の打ち合わせで出てきた話として、なぜRubyを使ったのか、という質 問がありました。で、この答えは「全くの偶然です」という答えになります。
もともと、SGmailは、プロトタイピング言語で作成し、評価を行ったら、本番 用言語(CもしくはC++)で作り直す予定だったのです。
で、プロトタイピングですから、コンパイルが必要な言語は避けたいというこ とで、
あたりが候補で、最初のうちはRubyという言語があることすら知らなかったの ですが、
ということになり、なんとか別の使える言語は無いかと探しているうち、 Rubyに出会ったというのが僕とRubyの最初の出会いだったわけです。
ということで、Rubyの特徴である「オブジェクト指向である」とか「プログラ ミングが楽しい言語」なんていうのは二の次であって、「Tkがまともに使えるイ ンタプリタ」であったためにRubyで作ることになったわけです。
Perlは知っていたので「同じような言語」かな?と最初のときは思っていたの ですが、SGmailを作るために、調べていくにつれ、非常に面白い言語であること がわかったわけですね。
ちょっと拍子抜けかもしれませんが、これがRubyを使ってSGmailを作った経緯 です。
そもそも、SGmailを作ろうと思ったのはなぜという、質問もありましたね。こ れも「無かったから」というのが答えではありますが、ちょっと説明が必要かな?
実は、SGmailは2つの要求が合体して作ろうと思い立ったのでした。その2つ の要求というのは、
というもので、最初の目的はまだ果たせていないのですが、2番目の目的であ るIMAPを使うためのクライアントとしてSGmailを作りはじめたわけです。
もちろん、IMAPを使うためであれば、IMAP対応のクライアントがあればそれを 使っていたはずですが、当時、Windowsのクライアントはありましたが、 FreeBSDで動くクライアントはほとんどなく、かろうじてNetscapeとpineが対応 していた、という状態でした。
で、結論としては、どちらも使い物にならなくて、SGmailの誕生となったわけ です。
SGmailを作りはじめて、最初のころは極内輪の仲間だけに公開していたのです が、まつもとさんに見つけられてしまって、急遽体裁を整えて、公開する事になっ てしまったのですが、このときメーリングリストも作って、いろいろな要望を聞 いて、その機能を実装していったわけですが、要求を実現しようと、整理もせず に作っていったので、3回も作り直すハメになってしまいました(^^;)。やっぱ り、きちんと整理しないとだめですね。
最初のころは、Ruby/Tkで実装していたわけですけど、やっぱり速度的に遅い とか、インターフェースが貧弱だとか、いろいろ不満があって、2.xxからは Ruby/Gtkのインターフェースも追加することになりました。
SGmailの特徴としては、この2つのインターフェースを持たせるために、 core機能と、GUI部分の分離を図った、というのがありますね。これが後の SGumapのサーバクライアント方式につながっていくわけです。
SGmailはできるだけ多くの人に使ってもらいたかったので、いろいろ機能を追 加しましたが、これが仇となって、どうもバランスの取れない機能も目立つよう になってしまい、根本的な作り直しが必要になってきましたが、ふと、
「IMAPを使うのが目的か?」
という、疑問が沸いてきたんですね。私はIMAPが使いたいわけじゃなくて IMAPが実現しているサーバ・クライアント方式のメールシステムがほしいだけで だ、ということに気がついたわけです。
そんな視点でIMAPを改めて見直してみると、
などの欠点が見えてきたわけです。実際SGmailが使用しているIMAPのコマンド は全体の3割程度で、この3割の機能さえあれば、十分事足りるわけです。
IMAPサーバを作ろうとすれば、非常に大変なわけですが、この3割程度のコマ ンドを実装するだけなら、比較的簡単だし、GUI向けの機能なども附加できるは ず、ということで誕生したのが、SGumapです。
まず、IMAPのSELECTコマンドは非常に使いにくかったので、排除しました。そ のため、モード遷移がなく、クライアントが作りやすくなりました。
次に考えたのが、POPをサポートするための方法でした。SGmailを作っていて わかったのですが、やはりIMAPは一般ユーザにはそう簡単に使えるサーバではな いなあ、ということです。
IMAPを使いなさい、というのは簡単なのですけど、一般のプロバイダを使った り、簡単にすまそうとした場合、やはりPOPを使うのが現実案なのですよね。
でも、一方で、メールはサーバ側に置きたいという要求がありますから、 POPを使いつつも、メールの管理はサーバで行う方法が必要であるということで す。
ということで、SGumapでは、特殊なフォルダを使えるようにして、ここにアク セスすれば、POP,SMTPが使えるという、エージェント方式というか、プロクシ的 な方法というか、そういった方向で仕様を考えました。この方法であれば、 POP before SMTPなどにも簡単に対応できる、ということもありますし。
でも、特殊なフォルダって結構曲者、なんかやだなあと思ったわけです。で、 解決策としては、特殊なものを特殊でなくしてしまえばいいわけですね。
そこで考えたのが「オブジェクト指向のフォルダ」です。完全にRubyに毒され ていますね(^^;)。
さて、フォルダをオブジェクト指向にすると何かいいことがあるのでしょうか? という疑問がでますよね。
これは、フォルダごとに機能を持たせることができるようになる、ということ につきます。想像以上のメリットがあるはずです。
先程のPOPであれば、POP、SMTPのアクセス機能をつけたフォルダを作ればいい はずですし、IMAP対応だって同じ方法でできます。
SGmailではアドレス帳をサーバ側に置くことができ、非常に便利だったのです が、この機能もオブジェクト指向フォルダで実現できそうです。
検索だってフォルダで実装できないか?ということで、SGumapではFIND型フォ ルダを実装しています。
Web日記インターフェースを実装する何てこともできますよね。特定のフォル ダに入れられたメールは日記として扱い、そのデータからWebページを作成すれ ばいいわけです。
などなど、さまざまな応用が考えられるわけです。
さてやりたいことは決まったし、あとは実装すればよい、というわけにはいき ません。
サーバ・クライアント型のシステムですから、何らかのプロトコルが必要にな ります。しかも、サーバはオブジェクト指向ですから、使えるコマンドが動的に 変化する可能性があったりするわけですよね。
うーむこまった。さてさて、どんなプロトコルにすればいいのでしょう?結構 悩みましたね。
POPやSMTPは扱うコマンドやデータが決まっていますから、このコマンドの場 合は、このデータを扱えばよい、ということが暗黙的に決定しているわけですが、 UMAPプロトコルでは、そのような仮定すらできないわけです。
ということで、いわゆる「形式的なプロトコル」でコマンドやデータに関りな く、通信できるようにいわば「閉じた」プロトコルを考案することになりました。
SMTPなどでは、エラーがあったりすると、"550 xxxxx"といたレスポンスを返 してクライアントにエラーがあったことを知らせます。
また、データ送信の前には、"300 End of data is <cr><lf>.<cr><lf>"といっ たデータ受信要求のレスポンスを帰します。
このようにある程度、レスポンスコードを使用した形で、処理を行うことはで きますが、十分なものではありませんでした。
そこで、UMAPでは、
という、レスポンス形式を決め、このレスポンスさえ、見れば通信ができるよう にしているわけです。一部データ形式の情報をレスポンスに含んでいますから、 1次的なデータの加工も可能になっています。
まあ、あまり機能的な部分に突入しても話が長くなるだけなので、このへんで SGmailとSGumapについての機能については切り上げますが、ここでいくつか設計 や実装でどのような事を考慮したかについて整理して見ましょう。
まず、「何が目的なのか」を十分考えることです。SGmailからSGumapへの変遷 のように、目的によっては、新たなプロトコルやサーバを実装したほうが結果的 に簡単になる場合もあるわけですから。
このあたりの、良い参考書としては、ちょっと古いですけど、G.W.ワインバー グの「ライトついてますか」という本がお薦めです。何がしたいのか、何が目的 なのか、誰が使うのか、どのような状況で使うのか、そういったことを十分に検 討すれば、思わぬ解決方法があったりするということが、面白く書かれています。 確か、共立出版から出ていたはずです。
次にその「設計」では、言葉では表しにくいのですが、「スマート」「クール」 といった形容詞で現されるような、設計を心がけるべきだということです。 SGumapはオブジェクト指向にしなくても、その目的は果たせます。しかし、スマー トではありません。
もちろん、時と場合によって、このような「こだわり」を持つことは良くない 場合もあります。すぐに使いたいという場合は、それが最優先になりますから、 このようなこだわりはじゃまですね。
何をもって、「スマート」だとか「クール」だとか言うかというと、人それぞ れ意見が違うと思いますが、私の場合、
といった事を総合的に判断して、善し悪しを決めているんじゃないかと思います。
自分で言うと恥ずかしいんですけど、その昔は「スーパープログラマ」と異名 を取っていました。なぜ「スーパー」かというと、元請けが「だいたい3ヶ月か な?」と思っていた仕事を、「1ヶ月」程度でやってしまっていたからです。
これは、いろいろ理由がありますが、自作の「ライブラリ」が豊富にそろって いたことが一番大きな要素であったのではないかと思います。
日頃からライブラリにできる部分に気をつけて、これはライブラリになるかな? と思ったら、それを蓄積し、再利用の効率を高める工夫をしていれば、自ずと作 業効率が上がります。
SGmail、SGumapでも、いくつかライブラリは作っていて、結構いろいろなとこ ろで流用しています。
で、効率が上がった分、早く仕事を切り上げて、あとは「遊ぶ」わけです。遊 ぶといっても会社にいたりするわけですから、これは「研究」の意味です。
で、日頃から興味のある分野やシステムを研究していれば、時には本業の仕事 に使える場合も出てくるわけです。場合によっては、私的研究成果がそのまま 「仕事」になることだって十分あり得ます。
まあ、会社によってはこのような事をすると、「時間があるなら仕事をしろ」 と言われる事もあるかと思いますが、このような事を言う会社は、プログラマを 単なる「工員」として扱っているわけですから、そうそうに見切りをつけたほう がいいかもしれません(^^;)。
同じ仕事をするのにも、義務的に「やらなくちゃ」と思って仕事をするのと、 「ふんふん、るんるん」とするのとでは、作業効率も俄然違いますよね。
で、そのコツはといえば、「面白みを探す」ということにあるのではないかと 思います。
何てことをやると、同じ仕事でも面白くなってきます。まあ、場合によっては 失敗するかもしれません。その場合は、なじんだ方法でやればいいだけですから、 それほど被害はないでしょう(納期さえ守っていればですけど)。
まあ、いろいろとしゃべってきましたけど、プログラマの現場というものを多 少は理解していただけたかな?と思います。
将来皆さんが、どのような仕事をしていくのか、それぞれ違うとは思いますが、 分野は違ったとしても、方法論的な部分では結構共通した部分があるのではない かと思います。