プログラムの設計

 少々大規模な(という表現はちょっとおかしいですが)案件に対しての設計について幾つかメモをしておこうと思います。大規模設計になるとブログなんかにはごく一部しかその技術やメモが公開されないので、特に秘密というわけじゃないですけど、あんまり巷では書かれていないことをメモしておこうと思います。

分業とライブラリー

 大規模な設計で特に必要なのは、その機能(Function)の使い回しです。車輪の発明は行ってはならないというわけです。そういうわけで一度使った作業プロセスを保存しまた後から使えるようにするという機能が各言語に必ず備わっています。言語によってその言い方は様々ですが、それらをユーザー定義関数と言ったり、単に関数と言ったり、サブルーチンと言ったり、ファンクションと言ったり、いろいろですが要は全く同じ機能を概念化したものです。これらの機能にはいわゆる「引数」と「返り値」があります。引数や返り値にも様々な言い方があります。パラメーターとかリターンとか...。そもそも西洋産なので翻訳にバラツキがあったりそもそもの原語も違ったりで用語が錯綜しておりますが、これも要は全く同じ機能です。これらの
  • 引数(パラメーター)
  • 関数(ユーザー定義関数)
  • 返り値(リターン値)
は、3つ合わせてはじめて機能します。勿論引数のない関数もありますし、返り値のない関数もありますが、大規模な開発の中では引数や返り値がない関数は殆どないと言っても過言ではありません。それは原因と結果の概念と同じだからです。ある原因(引数)はある事情(関数)を通してある結果(返り値)を生み出します。そしてその最後の結果は次の事情の原因になるわけです。プログラムでも同様で、ある返り値は次の関数の引数になります。これらの連鎖と分岐が複雑で大規模な開発につながってゆきます。
 それらの関数が上手に使いまわせるようにするためには、機能ごとに役割を分散させる必要があります。これらの機能の分散化を「クラス化」といってもよいと思います。それぞれの機能は、その機能特有のデフォルト値を持っています。例えば連番を発生させる関数には何も指定しない限り「0からスタートさせてください。」というような決まりをつくるとします。もしかしたらプログラムの概念ではなくて日常生活の概念を主に扱う連番の発生を望むのなら、「1からスタートさせてください。」という命令が9割を占めるかもしれません。そういう場合には、スタートさせるための0とか1とかいうデフォルトの値を持っていなくてはなりません。そういった値をクラス変数として定義することができます。この変数はその機能(関数)に特有の値なので通常の変数とは別扱いにします。それらのクラス変数を使った関数のことをメソッドという言い方をしたります。つまり、
  • 引数(パラメーター)
  • クラス変数(その機能特有の変数(値))
  • メソッド(その機能)
  • 返り値
という4つの流れといいますか動きを使ったものが「クラス」というものです。これはオブジェクト指向とかいったりもします。これらの概念は大規模な開発には必ず必要です。

 さて、なぜに関数化、クラス化(オブジェクト化)するのがよいのかというと、ある機能をブラックボックス的に使用できるという分業化が可能だからです。例えばあなたがあるプログラムを作成中に連番を発生させる必要があるとします。手の空いている誰かに連番を発生させる関数を作って、返り値は配列に入れて渡してね、といいます。手の空いている人はそれらの機能を本体から分離させて作成することができます。そして作成したらライブラリーに収めます。あなたはライブラリーからその機能を呼び出して、返り値の配列だけを取り出せばいいわけです。勿論実際はもっと複雑です。もっと複雑な機能を関数やクラスに落とし込んで使うのです。これらの関数やクラスは大量に作成され、ある一定の場所にカテゴライズされ整然と保存されます。これをライブラリー化といいます。図書館のように必要なときに訪ねて借りて、不必要になったら返すわけです。

デバックとエラーログ

 このブラックボックス化というのは、ある引数を与えて期待する返り値が出力さえすればそれでよいという単純な発想です。あなたが誰かに電話をします。そしてその誰かと話すことができます。あなたは電波のことやコンデンサーのことやキャリアのことや機器のメンテナンスについて何も知る必要がありません。しかしそれぞれの機能はそれぞれのタイミングできちんと行われているのです。関数やクラスもそれぞれに与えられた仕事をしているだけです。
 大規模な開発ではプログラム言語は実に人間の組織のように設計されます。各機能は分業され、それらの連結で作業が進みます。各機能の長は時折ミーティングします。またそれぞれの部署(機能)に問題がないか監査するというのも組織の役割の一部です。プログラムの開発ではデバック(監査)が欠かせません。それぞれの関数(部署)が問題があればエラーログを吐くという機能を開発段階で盛り込まないと後から犯人を捕まえることが不可能になります。

可逆性と不可逆性

 数学や科学の世界では不思議なことがあります。水を冷却すると氷にすることができます。また氷を温めると水に戻ります。これは可逆性があるからです。やさしい数学の世界では可逆性のある性質が殆どですが、実際の現実や複雑な数学になると不可逆性が起こります。MD5やSHA1といった暗号化のアルゴリズムは不可逆性の性質をもったアルゴリズムです。暗号なので可逆性によって読み解かれてしまったら困るのです。これはちょっと難しい世界の話ですが、プログラムを実行して走らせると複雑な処理になればなるほど可逆性を保つのが難しくなります。詳細な設計図や並外れた暗記力、または独創的な天才の一人舞台以外の場所では可逆性を維持することにも努力を払うことになります。つまりある設定や実行後の状態を元に戻すことができるという機能です。
 例えばコマンドにはその可逆性が装備されています。MySQLのSQL文は、データベースの「作成」<=>「削除」が可能です。しかしこのコマンド...一度削除してしまったら同じものを作成するこはできません。しかし開発段階ではこの作業が必要になってきます。作成したら削除する機能。削除したら(程度にもよりますが)もう一度作成できる機能が必要です。これらの作業の種類には、
  • 「作成」<=>「削除」
  • 「変更」<=>「戻す」
という風になります。ここで必要になってくる機能が「バックアップ」です。
 プログラムというものは魔物でして、例えば「変更」<=>「戻す」<=>「変更」...という作業を数千回繰り返してもきちんと前後に正しく機能するという関数を作ったとしましょう。例えばエポックスタンプから時間。時間からエポックスタンプという変換を行うとそれらはきちんと機能します。しかしエポックスタンプが2038年に達した時には正しく機能しないのです。2038年問題といわれていますが、これは困ります。これはかなり先の未来の話ですが、プログラムという魔物を侮ってはいけません。正しく機能しているつもりがどこかでバグるのです。
 少なくともDatabaseを自動作成する関数を作成した場合には、自動的に削除する関数も必要になるわけです。