Revised: 24th/Apr./2004; Since: Oct./14th/2003
パフォーマンスやセキュリティなどの特性は非機能要件なので、プロジェクト全体/システム設計全体で取り組まないと効果が上がりません。機能要件に よって利用可能なアーキテクチャ候補を挙げたら、非機能要件については、プロジェクト規模/工数や実装機能との兼ね合いで、Java/.NET、 UNIX/Linux/Windowsなどの実装レベルで最適解を絞り込みます。Java を実装として選んだ後でも、デザイン/実装レベルで複数の選択肢を挙げて、その中から最適なものを選ぶことになります。
パフォーマンスを意識しないコードは、いかに堅牢であろうとも、企業システムでは現実的ではありません。プロジェクトのコストでは、納入できるハー ドウェアはあらかじめ見積もった上で決められているものなので、お客様の要件変更が無い限り、コスト・オーバランが発生するような追加/変更は、事実上不 可能です。DB をいかにチューニングしても、実行環境のパラメタ設定を効率的に作り込んでも、稼動するアプリケーションがそれら以上に非効率的では、成果を上げられませ ん。
特にパフォーマンスが重要になるのは、共通部品の部分です。最上位の個別のアプリケーションのパフォーマンスが問題視される場合、他チームに影響を 与えずに、当該モジュールに関わるワークフロー内で閉じたコード変更/利用している機能の見直しで決着できます。しかし、ミドルウェア相当の共通部分だと 許容できません。問題発覚時点で、それらを利用している上位層のアプリケーション開発のフローが進んでいるため、手戻りコストが莫大になるからです。
従って、上位アプリケーションでは、他チームが開発した既存のモジュールを組み込む場合は、本当にそのモジュールで適切なのかどうかを、担当チーム の関係者/有識者に確認する必要があります。数値的な裏付け/お客様要件の裏付けがあることが理想です。一方、ミドルウェア相当のモジュールの場合は、実 装を変更しても、上位層のアプリケーションに影響を及ぼさないようにする工夫が必要です。
パフォーマンス志向のコーディング規則は、いつでも魔術的(詐術的)な色彩を帯びます。原理に立脚しない場合は、より下位層のインフラ部分での実装 変更によって、将来的に無意味であり、有害となるケースが多々あります。わずかなパフォーマンス上の利得のために、当初の設計を崩すことは、絶対にやって はいけないことです。
昔は、GC (Garbage Collector) の起動を回避したり、同期化を省くといったパフォーマンスチップスが採用されていました。実際、 JDK 1.1 (Java Development Kit 1.1) の頃は、GC の実行時には、アプリケーションの処理が停止していたため、GC に向けたチューニングが有効でした。また、同期化 (synchronization) も、オーバーヘッドが非常に高かったために、インテグリティ確保のためのロック処理を、アプリケーション側で実装することが有効でした。
しかし、SDK 1.2 (Software Development Kit 1.2) 相当以上の JVM は、パフォーマンスの点で長足の進歩を遂げています。GC は、その他の処理を(ほとんど)止めずに、インクリメンタル/コンカレントに実行されるようになりました。同期化も、マルチ・スレッド間でリソースの競合 が発生しない場合は、ほとんど(あるいは、全く)負荷を掛けません。可用性やインテグリティを危険にさらす場合は、リスクに見合った成果は望めないのが現 状です。
「Java は遅い」という常識は迷信になりつつあります。パフォーマンスが悪ければ、DB のエンティティの切り出し/索引 (index) などの設計や、実行環境のパラメタ設定が不適切である可能性があります。パフォーマンスに関連したコード・レベルのチップスは足が速いのです。
既存のコードを系統的に改善する方法論としては、「リファクタリング」(コードの体質改善)というキーワードで、盛んに研究されています。バギーな 処理/余分な処理を排除すること、モジュールの粒度を高めること、パフォーマンスを向上させることは密接に関連しあっています。戦略を立てて、「ご利用は 計画的に」が肝要です。
これらの要件を実現する工夫として、デザイン・バイ・コントラクト(契約に基づく設計)という思想があります。
デザイン・バイ・コントラクトでは、Java インタフェースを利用します。インタフェースを実装するクラスは、当該インタフェースで公開されているメソッドを通して実装しなければなりません。つま り、当該モジュールを設計した側が、絞り込んで意図的に公開しているメソッド以外は、当該モジュールを利用する外部のモジュールからは利用できません。 従って、ミドルウェア相当の部品でも、外部コードとのインタフェースとなる公開されたメソッドのシグネチャに変更が無ければ、より上位層のモジュールに影 響を与えることなく、実装の変更が可能となります。最悪、より下位層のモジュールを不適切に組み込んでいる場合でも、自分より上位層のモジュールに影響を 与えずに、より適切なモジュールを組み込むように修正することが可能になります。
これらの技術は、特にフレームワークで採用されています。信頼性、パフォーマンス、汎用性の全てをハイレベルで実現するフレームワークを設計するこ とは極めて困難です。むしろ、不可能であり、リリース後の変更があると割り切って、コードのリファクタリング(体系的なコードの体質改善)を想定しておか なければなりません。故に、内部的なコード変更が、上位層のアプリケーションに影響を及ぼさないようにする、デザイン・バイ・コントラクトが必要になるの です。
パフォーマンス向上とは、要するに処理を省くことです。実装すべき機能が確定している場合は、冗長な処理を、より簡略な処理で置き換えることになります。一方、アプリケーションの品質評価は、パフォーマンスよりも信頼性の方が重要です。
一般に、コンピュータ・システムの品質を計る指標を RASIS と呼びます。RASIS は、信頼性 (Reliability)、可用性 (Availability)、保守性 (Serviceabirity)、保全性 (Integrity)、安全性 (Security) を意味します。縮退した形で、 RAS と呼ばれることもあります。コーディングは、RASIS を高めるべく注力するものであり、パフォーマンス向上を目的とした最適化 (Optimization) は、RASIS を損なう危険があれば、厳重に慎まなければなりません。
信頼性を高めるためには、処理を二重化して、重要なポイントでチェック機能を働かせる必要があります。信頼性の高いシステムは冗長であり、パフォー マンスの高いシステムは脆弱です。この二律背反のバランスをとることが重要であり、その指標として、パフォーマンス検証によって数値的な裏付けをとること が必要なのです。