The POCO C++ Librariesは、C++でネットワーク中心のポータブルアプリケーションを開発するためのオープンソースクラスライブラリ集です。
POCOはPOrtable COmponentsの略です。これらのライブラリは、スレッド、スレッド同期、ファイルシステムアクセス、ストリーム、共有ライブラリとクラスローディング、ソケットとネットワークプロトコル(HTTP、FTP、SMTPなど)などの機能を網羅し、HTTPサーバー、SAX2とDOMインターフェースを備えたXMLパーサー、SQLデータベースアクセスも含んでいます。
モジュール化された効率的な設計と実装により、POCO C++ Librariesは組み込み開発に適しています。
POCOのソースコードから、コードスニペットを見てみましょう:

この実装には、次の特徴があります:
- 関数のパラメータが少ない。
- 入力が有効であることを確認するためにアサーションが使用されている。
- 変数の命名が理解しやすい。
- メソッドが短い。
- 本体内に不要なコメントがなく、コード自体が説明になっている。
- 関数本体のインデントが適切である。
- 適切な場所で、定評のあるSTLが使用されている。
POCOのソースコードを読み進めると、実装の一貫性が分かります。すべての関数に同じベストプラクティスルールが適用されています。
Let’s take a look inside POCO using CppDepend を使ってPOCOの内部を見て、その設計と実装に関する事実を確認してみましょう。
設計
抽象度と不安定度
Robert C. Martinは、興味深い 記事 を執筆しました。その内容は、設計内のサブシステム間の相互依存という観点から、オブジェクト指向設計の品質を測定するために使用できる一連のメトリクスに関するものです。
モジュール間の相互依存について、彼は記事の中で次のように述べています:
設計を硬直的で脆弱にし、再利用を困難にしているのは何か。それは、その設計内のサブシステムの相互依存である。設計が簡単に変更できない場合、その設計は硬直的である。このような硬直性は、強く相互依存したソフトウェアへの1つの変更が、依存するモジュールでの一連の変更を引き起こすという事実に由来する。その一連の変更の範囲を設計者や保守担当者が予測できない場合、変更の影響を見積もることができない。これにより、変更コストの見積もりが不可能になる。このような予測不能性に直面した管理者は、変更を承認することを躊躇するようになる。こうして設計は硬直的になる。
そして硬直性に対抗するために、求心性結合、遠心性結合、抽象度、不安定度、「主系列からの距離」、「抽象度対不安定度」グラフといったメトリクスを紹介しています。
「抽象度対不安定度」グラフは、保守と進化が困難なプロジェクトを特定するのに役立ちます。以下は、POCOライブラリの「抽象度対不安定度」グラフです:

このグラフの背後にある考え方は、プログラム内で人気のあるコード要素ほど、より抽象であるべきだというものです。言い換えると、実装に直接依存しすぎるのではなく、抽象に依存してください。ここで言う人気のあるコード要素とは、プログラム内の他のプロジェクトから大規模に使用されるプロジェクトのことです(この考え方はパッケージや型にも適用できます)。コードベース内に広く使用される具象型を持つのは良い考えではありません。これによりプログラム内に「苦痛の領域」が生まれ、実装を変更するとプログラムの大部分に影響する可能性があります。そして実装は抽象よりも頻繁に進化することが知られています。
上図の主系列線(点線)は、抽象度と不安定度をどのようにバランスさせるべきかを示しています。安定したコンポーネントは左側に配置されます。主系列を確認すると、そのようなコンポーネントは望ましい線の近くに位置するために非常に抽象的であるべきだと分かります。一方、抽象度が低い場合、「苦痛の領域」と呼ばれる領域に配置されます。
Foundationプロジェクトだけが苦痛の領域に入っていますが、他のプロジェクトから広く使用されているため、これは正常です。
継承
多重継承は複雑さを増大させるため、慎重に使用すべきです。
多数の基底クラスを持つすべてのクラスを検索してみましょう。

青い長方形が結果を表しています。

複数のクラスから派生しているクラスはごく少数です。
型の凝集性
単一責任の原則は、クラスに変更する理由が複数あってはならないと述べています。そのようなクラスは凝集性が高いと言われます。一般に、LCOM値が高いことは凝集性の低いクラスを示します。LCOMには複数の指標があります。LCOMは[0-1]の範囲の値を取り、LCOMHS(HSはHenderson-Sellersの略)は[0-2]の範囲の値を取ります。LCOMHS指標は、凝集性の低い型を検出するうえでより効率的と見なされることが多い点に注意してください。LCOMHS値が1を超える場合は、注意すべき状態と考えるべきです。


凝集性が低いと見なされる型は1%だけです。
遠心性結合
特定の型の遠心性結合は、その型が直接依存している型の数です。TypeCe > 50となる型は、多すぎる他の型に依存しています。そのような型は複雑で、複数の責務を持っています。リファクタリングの良い候補です。
次のCQLinqクエリを実行してみましょう。

結果は空でした。つまり、責務が多すぎるクラスはありません。
最もよく使われる型
どの型が最も頻繁に使用されているかを知ることは有用です。そのためにはTypeRank指標を使用できます。
TypeRank値は、GoogleのPageRankアルゴリズムを型依存関係グラフへ適用して計算されます。平均TypeRankが1になるよう、中心0.15の相似変換が適用されます。
TypeRankが高い型は、より慎重にテストすべきです。このような型のバグは、より深刻な影響を及ぼす可能性が高いからです。

最もよく使われ、かつ複雑な型を検索してみましょう。

結果は空でした。つまり、広く使用されていて複雑でもあるクラスはありません。
階層化とレベル指標
こちらの 記事 では、レベル指標と、それを活用して設計を改善する方法が説明されています。
依存関係サイクルを検索してみましょう。そのためには、次のCQLinqクエリを実行します:


依存関係サイクルを持つメソッドはごく少数です。Zipプロジェクトを例に、その依存関係グラフを見てみましょう。

このプロジェクトには依存関係サイクルが1つだけ存在します。
POCOの実装
コード行数
コード行数が多いメソッドは理解・保守が困難です。60行を超えるメソッドを検索してみましょう。


60行を超えるメソッドは1%未満です。
循環的複雑度
循環的複雑度は、手続き内の独立した経路の数を測定する、一般的な手続き型ソフトウェア指標です。
リファクタリングすべきメソッドを検出するため、次のCQLinqクエリを実行してみましょう。


複雑と見なせるメソッドは1%だけです。
複雑で、コメントも十分ではないメソッドはどれでしょうか?


変数が多いメソッド
NbVariablesが8を超えるメソッドは理解・保守が困難です。NbVariablesが15を超えるメソッドは非常に複雑であり、より小さなメソッドへ分割すべきです(ツールによって自動生成されている場合を除く)。


変数が多すぎるメソッドは8個だけです。
メソッドとフィールドが多い型


メソッドが多い型は3%だけです。
フィールドについても同様の検索ができます。


フィールドが多い型は1%未満です。
POCOは適切に実装されていると結論づけられます。複雑と見なされるメソッドは少なく、型はシンプルでメソッドとフィールドの数も比較的少なく、コードには適切なコメントが付けられています。
