構造化設計?*2

最近、仕事でひたすら、人の書いた C 言語のプログラムをハックして、書き直す。そんな事ばかりしている。*1プラットフォーム・OS は Linux で 言語は C 。会社に入ってからは、プログラミングの作業は殆どが Windows 上で、しかもここ5年以上は Java が中心だった。C は学生時代に Sun Sparc 上で組んでいた事はあるが、それ以来10年以上はご無沙汰している。

最初は C++ で全部書き直そうかと思ったが、人の作った C のソースファイルである。すぐに諦めた。お世辞にも分かりやすいとは言えない物が殆どだった。オブジェクト指向適用以前に、構造的にもおかしい。*2

  • 長すぎる関数。
  • 大量の重複するコード。未使用の変数、コード。
  • 戻り値が void で引数へ副作用として、演算結果を戻す関数群。どれが入力でどれが出力か分からない。
  • やたらに挿入してあるコンパイルスイッチ用のプリプロセッサ。(デバッグ用とか、テスト用とか。**用とか。)
  • あちこちのヘッダファイルに散在している構造体の定義。

リファクタリングだ。*3いい加減、気の滅入る作業が多かったが、色々と気付く事も多かった。慣れてくればそれなりに楽しいものだ。

  • Java のような API リファレンスに慣れていたので、最初は関数をどうやって調べようかと思っていたが、emacs で該当する関数にカーソルを置き、M-x man で該当する Manual が起動!!ちょっと感動してしまった。*4 ある意味、JavaAPI リファレンスより便利だし、人間っぽくてよい。
  • 元々、信号処理系のシステムなので、全体の構造は関数の流れで記述した方が便利だと感じる。局所的には C++ のクラスを使う事があっても、大局的なモジュール構成は、演算機能を担う関数でまとめた方が分かりやすいかも
  • ただ関数分割を行う上で、何が大切か。やはりデータフローの把握と、入出力でやり取りするデータの構造だろうなと思う。そういう意味では、C で適切な構造化設計を行うには、操作方法による分類やデータ構造の関連性を中心に、まず構造体の設計をしっかりとやっておく必要があると感じた。*5
  • 上記のデータ構造の最適な設計が出来れば、処理全体の適切な粒度を持つ関数への分割は比較的楽だ。
  • 関数の設計を中心に、データ構造を ad hoc に作っていくとどうしても関数が単なる手続きに堕ちてしまうようだ。そのまま、長い行数の関数へと不吉な匂いがきつくなっていくのだろう。

後、複数のシリアル入力を統合するなんて処理も入っている。従来のソースはプロセス間通信を使って、1入力、1プロセスで同期を取りながら、処理を行っていた。ただなんか挙動がいまいちなんで、スレッドで書き直そうかと思っていたが、調べてみると select なんて関数がある。 なんか発想が異質で面白い。実装依存な部分で移植性にはかけるかもしれないが、常識的に複数のスレッド、プロセスに依存しなくても良いのは利点だと思う。所々マクロが使ってあるので、こういうのはクラスで隠蔽するなりした方がきれいなんだろうと思う。だいたい、プロセスや I/O 周りなど状態を持つような対象はオブジェクトとして扱った方がきれいに書けるのかもしれない。
JM Project 辺りに行けば結構、情報も揃っているので、Linux での C のプログラミング。それなり楽しいかもしれない。次は Java でお世話になっている xUnit 系のテストフレームワークの導入か。

そんな感じで、もうすぐ夏休み。ちょっとまじめに構造化設計手法も勉強してみようかと思う今日この頃であった。前にも書いたが、オブジェクト指向にどっぷりだったので、少し違う所からシステムの設計・実装を眺めてみるのも、視野が広がって良いかもしれない。そう感じる。

構造化分析とシステム仕様<新装版>

構造化分析とシステム仕様<新装版>

*1:予算不足で外注作業員を雇えないと言うのも大きな理由の一つだったりする。

*2:いわいるスパゲッティだ。

*3:厳密にはオブジェクト指向プログラムでないと、この言葉使ったら駄目なんでしょうかね?

*4:ただし、Manual の section 番号の指定はどうすれば良いのかが分からない。

*5:いわいるデータ構造の抽象化でも言うのかな?