これについては少し異なる見方をします。多くの場合、コアライブラリは優れたアイデアです。
2つの別々のプロジェクトがある場合、それらは2つの別々のコードリポジトリにある必要があります。現在、それらは共通の機能に依存しています。例として、パケット処理アプリケーションを考えてみましょう。共通の機能には次のものがあります。
- メモリアロケータ
- アドレス解決プロトコル
- AVLツリー
- バイナリプロトコルのシリアル化コード
- 動的配列
- 単一にリンクされたヘッドと二重にリンクされた中間ノードを持つLinuxカーネルスタイルのハッシュリスト
- ハッシュ表
- TCP / IPヘッダー処理コード
- 二重にリンクされたヘッドと二重にリンクされた中間ノードを持つ通常のリンクリスト
- ロギングライブラリ
- その他(私を信じてください、あなたは小さくて些細なもののためにこれが必要です、またはあなたの異なるモジュールの数は100と同じくらい素晴らしいでしょう!)
- パケットキャプチャライブラリ
- パケットI / Oインターフェイスライブラリ
- パケットデータ構造
- スレッド間通信のブロッキングキュー
- 乱数ジェネレータ
- 赤黒木
- ある種のタイマー実装
現在、異なるパケット処理アプリケーションでは、これらの異なるサブセットが必要になる場合があります。1つのソースコードリポジトリで1つのコアライブラリを実装する必要がありますか、またはこれらのモジュールのそれぞれに18の異なるリポジトリがある必要がありますか?これらのモジュールには相互依存関係がある可能性があるため、これらのモジュールのほとんどは、その他のモジュールなどに依存している可能性があります。
コアライブラリを1つ持つことが最善のアプローチであると私は主張します。多くのソースコードリポジトリのオーバーヘッドを削減します。それは依存関係の地獄を減らします:メモリアロケータの特定のバージョンは、雑多なモジュールの特定のバージョンを必要とするかもしれません。その他2.5に依存するメモリアロケータバージョン1.7と、その他2.6に依存するAVLツリーバージョン1.2が必要な場合はどうでしょうか。その他の2.5とその他の2.6を同時にプログラムにリンクできない場合があります。
したがって、先に進み、次の構造を実装します。
- コアライブラリリポジトリ
- プロジェクト#1リポジトリ
- プロジェクト#2リポジトリ
- ...
- プロジェクト#Nリポジトリ
構造からこの種の構造への切り替えを確認しました。
- プロジェクト#1リポジトリ
- プロジェクト#2リポジトリ
- ...
- プロジェクト#Nリポジトリ
非コピーペーストメカニズムによるメンテナンスの削減とコード共有の増加につながりました。
次の構造を使用したプロジェクトも見ました。
- メモリアロケータリポジトリ
- アドレス解決プロトコルリポジトリ
- AVLツリーリポジトリ
- バイナリプロトコルリポジトリのシリアル化コード
- 動的配列リポジトリ
- 単一にリンクされたヘッドと二重にリンクされた中間ノードリポジトリを持つLinuxカーネルスタイルのハッシュリスト
- ハッシュテーブルリポジトリ
- TCP / IPヘッダー処理コードリポジトリ
- 二重にリンクされたヘッドと二重にリンクされた中間ノードリポジトリを持つ通常のリンクリスト
- ロギングライブラリリポジトリ
- その他のリポジトリ(信頼してください。小さくて些細なものにはこれが必要です。そうしないと、さまざまなモジュールの数が100にもなります!)
- パケットキャプチャライブラリリポジトリ
- パケットI / Oインターフェイスライブラリリポジトリ
- パケットデータ構造リポジトリ
- スレッド間通信リポジトリのブロッキングキュー
- 乱数ジェネレーターのリポジトリ
- 赤黒木リポジトリ
- ある種のタイマー実装リポジトリ
- プロジェクト#1リポジトリ
- プロジェクト#2リポジトリ
- ...
- プロジェクト#Nリポジトリ
...そして依存関係の地獄とリポジトリ数の急増は本当の問題です。
今、あなたはあなた自身のものを書く代わりに既存のオープンソースライブラリを使うべきですか?あなたは考慮する必要があります:
- ライセンスの問題。20のライブラリには通常20人の異なる著者がいるため、提供されるドキュメントで著者にクレジットを与えるという単なる要件が多すぎる場合があります。
- 異なるオペレーティングシステムバージョンのサポート
- 特定のライブラリの依存関係
- 特定のライブラリのサイズ:提供された機能には大きすぎませんか?提供する機能が多すぎませんか?
- 静的リンクは可能ですか?動的リンクは望ましいですか?
- ライブラリのインターフェースはあなたが望むものですか?場合によっては、希望するインターフェイスを提供するラッパーを作成する方が、コンポーネント全体を自分で書き換えるよりも簡単な場合があります。
- ...そして私がこのリストで言及していない他の多くのこと
私は通常、プログラマーの専門知識を超えて何かを必要としない1000行未満のコードはすべて自分で実装するという規則を使用しています。注:1000行には単体テストが含まれています。したがって、単体テストで追加の10 000行が必要な場合は、自分で1000行のコードを書くことはお勧めしません。私のパケット処理プログラムの場合、これは私が使用した唯一の外部コンポーネントが以下であることを意味します:
- 標準のLinuxディストリビューションによって提供されるものすべて。コード行が多すぎるため、Linuxを再実装しても意味がありません。Linuxの再実装の一部も、私の専門知識レベルを超えています。
- LALR解析は私の専門知識レベルを超え、1000行を超えるコードであるため、Bison / flexです。自分で再帰的降下パーサーを作成することは確かにできますが、Bison / flexは非常に便利なので、便利だと思います。
- 1000行を超えており、私の専門知識レベルを超えているため、Netmap
- DPDKからのスキップリストベースのタイマー実装です。コードは1000行未満ですが、専門知識レベルを超えているためです(スキップリストを使用しない別のタイマー実装があります)。
シンプルであるために自分で実装したものには、次のようなものも含まれます。
- MurMurHash
- SipHash
- メルセンヌツイスター
...これらのカスタム実装は重いインライン化を可能にし、パフォーマンスの向上につながるためです。
私は暗号化を行いません。自分で作成した場合は、ある種の暗号ライブラリをリストに追加します。自分で暗号アルゴリズムを作成すると、公式のアルゴリズムと互換性があることが徹底的なユニットテストで示されても、キャッシュタイミング攻撃の影響を受ける可能性があるためです。