C++では、IoTアプリケーションの実装に役立つ多くのライブラリがありますが、そのほとんどは低レベルです。高レベルのSDKとしては、 Macchina.io は優れた選択肢です。特に、IoTアプリケーション開発を簡素化する堅牢なフレームワークを探している場合に適しています。
MacchinaはIoTアプリケーションの強力なソリューションであるだけでなく、設計と実装が優れたプロジェクトでもあり、SDKユーザーがその動作を理解しカスタマイズしやすくなっています。
CppDependを使ってMacchinaのソースコードを覗き、その設計と実装のいくつかの側面を探ってみましょう。
クリーンな設計
整理されたフォルダ構造を持つC++プロジェクトを設計する際は、 モジュール性、 保守性、 スケーラビリティを考慮することが重要です。フォルダでコードを整理すると関心事を分離でき、ナビゲート、変更、拡張が容易になります。
次のDSMからわかるように、Macchina SDKは整理されたフォルダ構造を持っています:

POCOライブラリベースの技術レイヤーは、platformフォルダに分離されています。 POCO C++ Libraries は、デスクトップ、サーバー、モバイル、IoT、組み込みシステムで動作するネットワークおよびインターネットベースのアプリケーションを構築するための、強力なクロスプラットフォームのオープンソースC++ライブラリです。
以下は、POCOライブラリの一部の依存関係グラフです。

Foundationプロジェクトの内部を見て、その構造を探ってみましょう:

ソースコードの名前空間は3つの異なる目的を果たしています:
1- アプリケーションのモジュール化
モダンなC++ライブラリは、コードベースをモジュール化するために名前空間を広範に使用し、「機能ごとの名前空間」アプローチを採用しています。機能ごとの名前空間は、機能セットを反映するように名前空間を使用します。単一の機能に関連するすべての項目(その機能のみ)を1つの名前空間に配置します。これにより、高い凝集度と高いモジュール性を持ち、名前空間間の結合が最小限の名前空間が生まれます。密接に連携する項目は互いに近くに配置されます。
2- 匿名名前空間
無名の名前空間は、グローバルなstatic変数の必要性を回避します。作成した匿名名前空間は、それが定義されたファイル内でのみアクセス可能です。
3- 慣例による詳細の隠蔽
C++では、ライブラリユーザーからpublic型を隠す方法がありません(C#では「internal」キーワードがこの役割を果たします)。そのため、特定の型が実装の詳細であるため直接使用すべきではないことを示すことが有用です。
Boostライブラリの開発者が開拓したモダンC++の一般的なイディオムは、モジュールの実装の一部を形成する(つまり公開APIの一部ではない)が、公開する必要があるシンボルを、慣例的にdetailという名前の別のサブ名前空間に分離することです。
Poco.DetailsとPoco.Dynamic.Impl名前空間は、慣例によって実装の詳細を隠すために使用されています。
より大きな柔軟性のための疎結合
疎結合が望ましいのは、アプリケーションのある領域の変更が、システムの他の部分への変更を少なく済ませるためです。長期的には、アプリケーションの修正や新機能追加に伴う時間、労力、コストを大幅に節約できます。
疎結合は、抽象クラスやジェネリックな型とメソッドを使用することで実現できます。
Macchinaのソースコードには300を超える抽象クラスが含まれています:

例えば、クライアント認証クラスは複数の実装を可能にする抽象クラスであり、ユーザー認証機能に柔軟性を提供しています。

高い凝集度
単一責任の原則は、クラスは変更する理由を1つだけ持つべきであると述べています。そのようなクラスは凝集していると言われます。高いLCOM値は一般に凝集度の低いクラスを示します。LCOMにはいくつかのメトリクスがあります。LCOM値は0から1の範囲です。LCOM HS(HSはHenderson-Sellersの略)値は0から2の範囲です。1を超えるLCOM HS値は警告と見なすべきです。LCOMメトリクスの計算方法は次のとおりです:
LCOM = 1 — (sum(MF)/M*F)
LCOM HS = (M — sum(MF)/F)(M-1)
ここで:
- Mはクラスのメソッド数(staticメソッドとインスタンスメソッドの両方をカウントし、コンストラクタ、プロパティのgetter/setter、イベントのadd/removeメソッドも含みます)。
- Fはクラスのインスタンスフィールド数。
- MFは特定のインスタンスフィールドにアクセスするクラスのメソッド数。
- Sum(MF)はクラスのすべてのインスタンスフィールドにわたるMFの合計。
これらの式の背後にある基本的な考え方は次のように述べられます:クラスは、そのすべてのメソッドがすべてのインスタンスフィールドを使用する場合、完全に凝集しています。つまりsum(MF)=M*Fとなり、LCOM = 0かつLCOM HS = 0になります。
1を超えるLCOM HS値は警告と見なすべきです。

クリーンな実装
コードベースに大きな型が少ない
大きな型は開発と保守が非常に複雑になる可能性があります。そのようなクラスはシステム内の多すぎる他のクラスを制御し、合理的な限界を超えて成長し、「何でもするクラス」になってしまいます。
Macchina SDKのソースコードでは、特に大きな型はわずかです。

メソッドは小さく理解しやすい
複雑な関数を特定するために多くのメトリクスが使えます。NBLinesOfCode、パラメータ数、ローカル変数の数は基本的なものです。
複雑な関数を検出するための他の興味深いメトリクスもあります:
- 循環的複雑度は、プロシージャ内の決定パスの数を反映する、一般的な手続き型ソフトウェアメトリクスです。
- ネストの深さは、メソッド本体内のネストされたスコープの最大深度を表すメソッドレベルのメトリクスです。
- 最大ネストループは、関数内のループネストの最大レベルを表します。
これらのメトリクスの許容最大値はチームの選択によって異なり、普遍的な標準値はありません。
Macchina SDKのソースコードでは、複雑と見なせるメソッドはわずかです。

コードは保守可能
保守性指数 (Maintainability Index)は コードベースが時間とともにどれだけ容易に保守できるかを測定するために使用されるソフトウェアメトリクスです。コードの複雑さ、サイズ、可読性などの要因に基づく定量化可能なスコアを提供し、変更がコードベースの長期的な保守性にどう影響するかを開発者が理解するのに役立ちます。
CppDependのツリーマップを使って、Macchina SDKのメソッドの保守性を調べてみましょう:

メトリクスビュー Metric Viewでは、コードベースは ツリーマップで表現されます。ツリーマッピングは、ネストされた矩形を使用してツリー構造のデータを表示する方法です。CppDependのツリーマップで使用されるツリー構造は、通常のコード階層です:
- C/C++プロジェクトは名前空間を含み、
- 名前空間は型を含み、
- 型はメソッドとフィールドを含みます。
ツリーマップの Size オプションは矩形のサイズを決定し、デフォルトでは コード行数に比例します。また、コードメトリクスはコード要素の矩形の色で表現できます。このケースでは、色は保守性を表します。
ご覧のとおり、赤で表示されているメソッドはわずかで、そのほとんどはテストメソッドです。
結論
MacchinaはIoTアプリケーション開発を容易にすることで知られています。その実装はクリーンで、理解しやすく、カスタマイズ可能であり、IoTアプリケーションの優れた選択肢となっています。
