プログラム作成、或いは設計における、共通化への一考

結論から。
おおよそプログラム言語の種類を問わず、共通化は基本的且つ重要な設計スキルである。
共通化をしない場合のデメリット、した場合のメリット、さらには共通化の方法への考察までをまとめて行う。

共通化をしない場合のデメリット

共通化をしない、という方向は、さらにいくつかに細分化される。それぞれについて、考察を行う。

関数化していない

main一本でかかれているプログラム。シェル系、Perl、VBで比較的多く散見されます。無論、CやC++でも十分な数、存在はするのですが。
「(主としてシェル/スクリプト系言語で書かれる)ごく短いプログラム:規模としては10行以内、くらい」である場合を除き、絶対に止めましょう。「関数って何?」という人は、初級の本で確認/習得してください。
関数化は、少なくとも「職業的プログラミング」をする場合、基礎以前の問題です。したがって、デメリットへの考察はなし。

カット&ペーストで同じ記述を繰り返す

関数化していない、に近いものがあるのですが。これは結構あちこちで散見します。言語問わず。
問題点は非常に簡単。「ミスがあった場合の修正が大変」。関数化すれば一ヶ所で住むはずの変更が、何十箇所にも散らかりかねません。「エディッタの置換で一発」とか考えていると、大抵「変換ミス」「比較的大きな変更や追加」ではまります。
言語を問わず「カット&ペーストで問題がない」ことは絶対にありません。カット&ペーストが発生しそうな瞬間に、きちんと関数化を考えましょう。

モジュール化しているが、同一モジュールの複数バージョンが散らかっている

一見「きちんと共通化されている」っぽく見えている辺りに問題の根の深さが見え隠れします。
モジュールは、大抵の人が(得てして無意識に)「ちゃんと動くもの」であると考えます。しかし、散らかっているモジュールは、当然の如く「ちゃんと動く」とは限りません。理由は「各人が勝手に修正している」から。
本来モジュールの利点であるはずの「問題点は一意に解決される」部分が完全に無視されています。また、こういった状態の場合、得てして「まともにテストされていない」ことが多いのも問題点。
モジュールは「きちんと管理されて」こそのモジュールです。最新版がどこにあるかわからない、最新版モドキがちらかっている、では、何の意味もありません。

共通化をした場合のメリット

開発の一部分が省略できる

きちんとテストまでされているモジュールであれば、ただそれを「使う」だけですみます。テストすら不要です(結合テストは必要ですが)。
そのため、全体の工数が大きく削減できます。

問題が一意に解決される

例えば、ある処理手順でバグ(とか最近の流行だとセキュリティーホールとか)があったとしましょう。
全員が同じモジュールを使っている場合、気づいた誰か一人だけが「修正/テスト」を行えば、全員のプログラムの信用性が同時に向上します。

作成物の品質が向上する

上記の重複にはなるのですが。工数が削減できれば、重要な部分のテストによりいっそうの重きをおく事が出来ます。問題点がモジュール部分に出ても、誰かが修正すればすぐに反映できます。
そうやって、作成物の質が向上してきます。

モジュールの管理

モジュールを作るのはいいのですが、作ること以上に大切なのが「管理」です。
しかし、管理に大量の工数が取られては、モジュール化のメリットは大きく減少します。
よって、ここでは「簡単に」かつ「確実に」管理できる方法を模索していきます。
で、何はともあれCVS。
別にほかのバージョン管理システムでも良いのですが、最近情報が入手しやすいので、CVSであるとしておきます。CVSがわからない人は、検索エンジンででも調べてくださいませ。
一人で開発しているときでもできるだけ使う癖をつけましょう。「一時間前の自分は他人同然」ですから。

普段モジュールを使うとき

指定されたレポジトリから、モジュールを落としてきましょう。コンパイル系ならそのまま落として使う、で基本的にはOKです。
インタプリタ系(Perlとか)の場合、出来ればモジュールを格納する場所を、マシンごとに一箇所に決めておくとよいでしょう。たとえ「使うだけ」とはいえ、何箇所もソースが散らかると面倒なので。一行目の「/usr/bin/perl」の後に、-Iスイッチでディレクトリを指定することで任意のディレクトリからモジュールが取り込めるようになります。

モジュールを作る

出来るだけ簡単な手順にしましょう。
上記のうち、何が何でも忘れちゃいけないのは…全部です。ですが、忘れやすいのが「テストプログラム」。絶対に作ってください。これだけは、どんなに手間であるとしても。
文字通りテストに用いるほか、基本的な使い方もこのプログラムで理解が出来るので。

モジュールにバグが出たら/機能追加したいときは

出来るだけ簡単な手順にしましょう。
ここで重要なのは「cvs update」。これを忘れると「ほかの人の修正を上書きする」といった事象に見舞われます。気をつけてください。

モジュールの作り方

んと。まともに書いていくと書籍一冊分…ではすまないほどのボリュームになるので、ポイントポイントを軽く抑えていきたいと思います。
ちと面倒なものも含まれますが、結果的に「楽になる」と思いますので、適宜採用していただければ。

一つ一つはシンプルに

モジュールの、特に関数ごとの機能は「シンプルに」。目安は「一言で説明が出来る」こと。
ちと複雑そうな関数は、シンプルな複数の関数に切り分けましょう。

依存関係をシンプル/明確に

以下、私が良く使う切り分けです。案外便利なので、よかったら使ってみてください。モジュールが簡単に整理できるようになります。
なお、基本的にはより数字の若いカテゴリに収まるように、モジュールを設計する癖をつけてください。
第一カテゴリ:何者にも依存しないモジュール
ものすごく基本的なモジュールがココに分類されます。ただ、案外「実は第二カテゴリ」である場合も多いのですが。ここには、本当にシンプルなものが収められています。
第二カテゴリ:第一カテゴリの1モジュールにのみ依存するモジュール
基本的なモジュールは、実は多くがココに分類されます。第一と第二があふれ返ると、大分充実した「ライブラリ」になってきます。
第三カテゴリ:第一カテゴリの複数モジュールに依存するモジュール
若干好ましくないのですが、この辺まではまだよし、といったところでしょうか。依存関係が複雑になりやすいので、その辺りに気を配ってください。
第四カテゴリ:第二、第三カテゴリの1モジュールにのみ依存するモジュール
どっちかというと「より便利な」ものを目指しての、ラッパー系のモジュールになることが多いです。
第五カテゴリ:第二、第三カテゴリの複数モジュールにのみ依存するモジュール
あまり好ましくないモジュール分類です。やはりラッパー系のモジュールでしょう。
第六カテゴリ:上記に当てはまらないモジュール
基本的に、ここに属するカテゴリは出来るだけ作らないようにしましょう。やむを得ず作るときは、依存関係、目的などを明確に。

「今使う」機能を実装する

後で使うかも、という理由で機能を実装すると、大抵後でそれは「ゴミ」になります。必要なものだけを最低限実装するようにしましょう。

内部データは直接触らせない

C++であれば内部データはprivateに。Cであればstatic(外部的なstaticにしてファイルごとに管理すると楽)。Perlであればmyで。内部データは直接触れない場所においておきましょう。
オブジェクトを実装している言語なら、Class化を一度は考察してみるとよいでしょう。
で、データに触るための、get系、set系の関数(メソッド)であるアクセッサ、セッターを作成しましょう。

慣れましょう

共通化は、とどのつまり「なれ」です。どんな風に切り出したら「使いやすく」「変更しやすい」かは、最終的には体で覚えるほかありません。
たくさん共通化して、失敗して、そこから何かを学び取ってください。

まとめ

共通化、或いは現在の時流にあわせる言い方をすればクラス化は、重要とかなんとかいうレベルの問題ではなく、現在「デフォルトで必要なスキル」として捕らえられつつあるのが現状である。しかしまた一方で「出来ていない現場が多い」ことも見逃せない。
不出来な共通化は無駄なコストを増やすが、よく出来た、或いは少なくとも致命的な問題がない共通化は、そのレベルに応じた工数の削減と品質の向上に役立つ。
会社のためにも、それ以上に自分のためにも、共通化のスキルは身につけ、磨きをかけることに意義があると、私は考える。
この駄文が読者諸氏の考察の一助になれば、筆者望外の幸いである。


戻る 
Copyright 2003 M-Fr Net All Right Reserved
E-Mail:info@m-fr.net