Entry

プログラムの設計と実装に必要な API 感覚の話

2011年11月19日

言うまでもないことだけれども,ひとつのプログラムは,たくさんの要素が関わって実行されます。要素というのは,例えばハードウェアや OS それにネットワーク環境といった低水準のものから,コンパイラや VM,ランタイムのような処理系/実行環境,高水準なフレームワークやコンポーネント(COM など)ライブラリ,それに具体的なソースコードにいたるすべてを指しています。しかし,これまた言うまでもないことですけれど,あるプログラムに対して,これら全ての要素が同じ抽象性を持っているわけではありません。一般に,ハードウェアに近い技術ほど,汎用的に適用できるように作られている。そうすることで,システム全体が柔軟に内部構成を変更できるようになるからです。

例えば,同じハードウェアアーキテクチャ(x86 系や EM64 系など)であっても,それより水準の高い OS のレイヤでは異なる OS を乗せられるし,.net のような実行環境の上に乗っかる処理系には C++(CLR) や C# のように異なる開発言語を使うことができます。あまりアプローチする人はいないみたいだけれど,Java VM 上で動く Java 言語以外の開発言語を定義することもできます(実際にやっている人もいる)。つまり,低層にあるレイヤーの抽象度が高いほど,高水準のレイヤーにおいてカスタマイズしやすくなるわけです。これも,よく知られた話。

このように,機能を抽象度に基づく「層」によって構成/管理するアプローチは,通常 layered approach と呼ばれていて,コンピュータ開発には欠かせない基本的な発想になっています。層で管理するモデルといえば,TCP/IP がよく知られているけれども,それだけではない,と。

で,このような考え方で,キーになる概念が「インターフェイス」です。インターフェイスというのは,機能と機能,層と層の間で情報をやり取りするための窓口/約束事のことです。ある層を設計するということは,そのインターフェイスを設計することで機能それ自体と層の境界を定義することができる。逆に,インターフェイスを適切に設計することは,機能それ自体や内部ロジックの変更に対してロバストな技術を定義するための必須技術だと言えます。

一方,ソフトウェア開発,なかんづく,プログラミングの世界では,一般にインターフェイスを API(Application Program Interface)と呼び,具体的な機能実装を隠蔽する手法をカプセル化と言います。呼び出し側は,公開されたインターフェイスの規約に従いさえしていれば,内部ロジックが変更されてもほとんど全く影響を受けることがなくなります。つまり,ロバストなプログラムを書くことができるということです。言い換えれば,API を適切に設計することが,継続的に安定してプログラムを開発/保守するための第一歩ということになります。

この点,一般的なプログラマが,API の設計/開発についてどれだけ意識しているか,詳しいところは知らないのだけれども,最もエンドユーザに近いアプリケーションソフトの開発者はあまり API を意識していない印象があります。また,学校などで研究/実験を主に行っているところも,そうした感覚はあまりないんじゃないかと思う(偏見だけれども)。アプリケーションソフトを作るところは,定義された要件を実装することが第一の目的になるし,研究/実験ではプログラムの保守/再利用よりも研究の実証が第一目的になることから,それはそれでいいのだと思います。

しかし,仕事としてソフトウェアを作るあるいは継続的な趣味としてプログラムを作る場合,API に基づいて機能レイヤを管理することは,非常に重要な要素になります。というのも,それは,直接的にはユーザの要望に対して迅速に対応するための発想だし,さらに高度なプログラムを開発するための作業になるからです。特に,ソフトウェアでお金を稼いでいるところは,大事な食い扶持を守るための発想になります。

API について極々簡単な具体例を挙げると,例えば,C++ で文字列を表すクラスを設計するとき,バッファの内容を直接ユーザ(この場合はクラスの利用者==開発者)に触らせないように,API を定義することができます。機能のみを抽象化することで,バッファの生成方法や管理方法をカプセル化できます。また,知っての通り,テンプレートを使うことで,文字要素の型も抽象化できる。これも,大きな意味では API と言えそうです。何度も繰り返すけれども,このようにソフトウェアの機能を抽象化することで文字列クラスを柔軟に運用できるようになるわけです。

通常,継続的に保守することを予定するプログラムは,この層を多く作ることで将来生じうる変更に備えます。例えば,STL はコンテナ(std::vector や std::list)のロジックと,メモリ管理のレイヤーを分けて定義しています。std::allocator は,コンテナに対して明らかに低水準のレイヤにあります。同じ名前空間にあるからといって,両者を同じ水準にある機能として理解してはいけない。さらに,その std::allocator も直接定義せずに抽象化されている。たまたま最近読んでいた Boost の uBlas ライブラリを見ても,バッファ管理とベクトルや行列クラスを明確に分離して異なる層に配置している。普通のプログラマにベクトルを定義してもらう場合,さすがに直接配列を定義して「できた」とかいう人はいないだろうけれども(目的にもよるが),ここまで機能の抽象度を細分化する人もあまりいないんじゃないかと思います。STL や Boost ほどの汎用性を元から求めていないのかもしれないけれど,巷のプログラムを読む限り,もう少し抽象度の高い層(低水準の層)を作った方がいいんじゃないかと思うことも少なくない。偏見かもしれないけれども,layered apploach はあまり意識されていないんじゃないかと思っています。

もちろん,知っての通り,層の数を増やすほど,プロトコルを変換するためのオーバーヘッドがかかります。それを意識して抽象度を細分化しないアプローチも十分説得力があります。しかし,見ているプログラムや解説の中には,そもそもそういう発想がないんじゃないかと思えるようなものもあります。

さらに,もっとそもそも論にしてしまうと,そもそも巷のプログラミング本(設計だけでなく実装も扱った書籍)で layered approach や API の設計そのものについて専門に扱っている書籍は,ほとんどありません。あたしが知っていて読んだものでは,最近書かれた,『API Design for C++』くらいしか思い当たらない。

API Design for C++
API Design for C++
posted with amazlet at 11.11.20
Martin Reddy
Morgan Kaufmann
売り上げランキング: 4774

他には,『プログラミング作法』がかろうじて挙げられるけれども,直接専門的にプログラムの抽象性を扱っているわけではないので,勘の良い人しかその意味するところを理解するのは難しいと思います。

プログラミング作法
プログラミング作法
posted with amazlet at 11.11.20
ブライアン カーニハン ロブ パイク
アスキー
売り上げランキング: 5655

なぜこの手の書籍が少ないのか。それもこれも,巷のプログラミング本(特に邦書)が,継続的に保守する予定のある比較的大きなプログラムを開発した経験が乏しいか全くない人,あるいは,そのようなプログラムの全体ではなく一部しか設計/実装したことがない人,または自分でプログラムの仕様をほぼ全て決められる立場にいる人によって書かれているからだとも思う。こうしたノウハウは,現状,ソフトハウスの開発現場に蓄積されていることがあるけれども,あまり外には出てきません。

外部の人が知る手段は,上記の書籍(『API Design for C++』)を除くと,実際にソースを読むことくらいしかありません。C++ では,GCC の STL 実装なんかはかなりきれいに構成されているし,Microsoft のテンプレートライブラリもある程度きれいに書かれている。Intel の TBB も参考になるはずです。おおむね,きれいに書かれたライブラリなりアプリケーションは,低層と上位の層に分かれているはずです(規模が大きいものは,中層も見受けられる)。

こういうアプローチに対する問題意識は,おもちゃプログラムから(有償/無償を問わず)製品と呼ばれるプログラムを作れるようになるには必要なんだけれども,なぜかノウハウが共有されない不思議。知ってる人は当たり前のようにそのようなアプローチを取るのに対して,知らない人はずっと知らないままでいる。業界全体にそうした意識がないのかとえば,そんなことはないと思うんのだけれども,なぜか明文化されないし,その重要性を強調する人もあまりいない。当たり前のコトすぎて共有されていないのかもしれない。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN