共通ライブラリは良いアイデアですか?


16

私はいつも「共通ライブラリ」が良いアイデアだと思っていました。つまり、いくつかの異なるアプリケーションでしばしば必要とされる共通の機能を含むライブラリを意味します。コードの重複/冗長性が少なくなります。

私は最近、これは実際には悪い考えであり、「アンチパターン」であると言ったほどの記事を見つけました(今は見つかりません)。

このアプローチには利点がありますが。バージョン管理と変更管理は、このライブラリを使用するアプリスイートの回帰テストを意味します。

私は、新しい(Golang)プロジェクトにちょっと不満を感じています。コードの重複排除は長年にわたって私に打ち込まれてきましたが、今回はそれを試してみるべきだと思います。

これを書いている間、私はこの「共通ライブラリ」アプローチがアーキテクチャのスキミングの結果であると考え始めていますか?おそらく私の設計にはもっと考えが必要ですか?

考えを聞いて興味を持っています。


2
私の2セント...あなたは、システムの用途の一つは、それがその変更が必要な場合は、APIやライブラリが全く共通ライブラリではないことを、その後、共通のAPIに変更を加える必要がある場合
ラジャAnbazhagan

1
コードの複製と結合の間には基本的なトレードオフがあることがわかりました。あなたの質問はその典型的な例です。あなたが両者の間ストライキのバランスは、おそらくあなたのコードが最終的に実行される環境に依存します。
ジョエル・コルネット

私が知っているほとんどのC開発者は、「ツールボックス」と呼ばれるユーティリティのコレクションを持っています。ただし、通常、1つの組み込み可能なライブラリに収集されません。それはより「選択して選ぶ」ことです。
マークベニングフィールド

2
誰かがApacheを呼び出して、この狂気を修正します。アパッチコモンズ
ライヴ

回答:


21

ライブラリと再利用は絶対に良いことです。彼らには1つの大きな欠点があります。注意深く管理しないと、キッチンの引き出しに相当し、他のどこにも行かないすべての可能性と終わりを保持します。

これは、64ビットシステムへのビジネスユニット全体のコード(主に新しい)の最初の移植を担当し、ビルドとパッケージングの完全なオーバーホールを行い、その多くが行われたときに、実際に実行されました。 *私たちは、アプリケーションのスタックから出荷したものを構築する傾向がありました。クライアントは、「A、B、D、Fに加えてMを実行するシステムが欲しい」と言うでしょう。そして、あなたはまだやっていなくて、それらをすべて統合するわずかに異なる接着剤です。」すべてが共通していたのは、数十年にわたって**人々が再利用すべきだと思うすべてのものを蓄積していたジャンク引き出しライブラリーでした。長い話を短くするために、ライブラリ内のコードの一部は。実際に必要なわけではなく、共通ライブラリがインストールされるように、これらの依存関係の構築と維持に多くの貴重な時間を費やしていました。

教訓は、ライブラリをクラスのように扱う必要があり、過度の責任でオーバーロードしないことです。作成しているすべてのプログラムが両方を使用している場合でも、JSONパーサーを線形代数関数と同じライブラリに配置しないでください。

それらを個別に保持することには多くの利点がありますが、最大の利点は、ジャンクドロワーとそれに付属する荷物を含めるのではなく、開発者とパッケージャーが自分の製品に実際に必要なものを詳細に説明することを強制することです。ビルドされたパッケージを使用してシステムをセットアップすると、きめ細かな依存関係により、必要な部分のみがインストールされます。リポジトリを無視して、古くて汚いものをコンパイルし続けたとしても、もはや使用されていないものは何でもあなたが出荷するものに漏れません。

もちろん、libc多くの関数を1つのライブラリに詰め込んでいるような例外もあります。これは、X以外の方法は常に悪い習慣であると主張する熱狂者を盲目的にホールに注意を払うのではなく、そのように行うことの利点を推論できるケースの1つです。


*その過程で、私は渡されたバイナリを発見し、6年間でゼロから再コンパイルされていませんでした。

**数十年前のコードには何も問題はありません。私たちには、非常によく証明された多くの重要なアルゴリズムがあり、近代化のためだけにそれらを書き換えるのは愚か者だったでしょう。


1
私の経験則では、ライブラリに「common」などの名前を付けようとすると、問題が発生します。
カールビーレフェルト

9

恥ずかしいことに、数十年前のチーム環境で、そのような名前の「共通」ライブラリを導入しました。私は、ほんの数か月のうちに、ゆるやかに調整されたチーム環境で何が起こるかについて、当時のダイナミクスを本当に理解していませんでした。

私がそれを紹介したとき、私はそれを明確にし、それが日常的に有用であると私たち全員が同意するもののためであること、それがミニマリストライブラリであることを意図していること、そしてライブラリは標準ライブラリを使用して、新しいプロジェクトにできるだけ簡単に展開できるようにします。当時の私の考えは、私たちの特定の分野で日常的に有用であることがわかったもののための、標準ライブラリへの私たち自身の小さな拡張だと思っていました。

そして、それは十分に始まりました。私たちcommon/math*は線形代数で重いことが多いコンピューターグラフィックスで作業していたため、私たちは毎日日常的に使用するルーチンの数学ライブラリ()から始めました。そして、私たちはしばしばCコードと相互運用してfind_indexいたので、次のような便利なユーティリティ関数に同意しました。std::findC ++では、C関数の仕組みを模倣したイテレータではなく、シーケンスで見つかった要素にインデックスを返します-この種のもの-少し折ec的ですが、ミニマリストであり、誰もが使い慣れた実用的なままで十分に広く使用されています、そして、すぐに親しむことは、「共通」または「標準」であるものを作成しようとする際に見られるように、非常に重要な基準です。採用と毎日の使用。

しかし、時間の経過とともに、人々が個人的に使用するものを追加するようになったため、ライブラリの設計意図は私の指から外れました。そして、後に誰かが一般的なGL関連ルーチンのOpenGLに依存する関数を追加し始めました。さらにQtを採用し、Qtに依存するコードの追加を開始したため、すでに共通ライブラリは2つの外部ライブラリに依存していました。ある時点で誰かが私たちのアプリケーション固有のシェーダーライブラリに依存する一般的なシェーダールーチンを追加し、その時点でQt、OGL、および私たちのアプリケーション固有のシェーダーライブラリを持ち込まずに新しいプロジェクトにデプロイすることさえできませんでしたプロジェクトの重要なビルドスクリプト。それで、この折this的な相互依存の混乱に変わりました。

しかし、このライブラリに入れるべきものとすべきでないものを議論することで、「共通」であるという非常に厳しいラインルールを設定しないと、「共通」と見なされるものは非常に主観的な考えになりやすいことも発見しました誰もが毎日役に立つと思うもの。規格のゆるみとそれは、誰もが日常的に有用だと思うものから、単一の開発者が他の誰かに有益である可能性のあるものにすぐに劣化し、その時点でライブラリは折fast的な混乱に本当に劣化します。

しかし、さらにその点に達すると、一部の開発者は、プログラミング言語が好きではないという単純な理由で物事を追加し始めることができます。彼らはforループや関数呼び出しの構文が気に入らないかもしれません。その時点で、ライブラリは言語の基本的な構文と戦っているものでいっぱいになり始め、実際にはそうではない簡単なコードの数行を置き換えます。そのような速記を導入した開発者にしか馴染みのない、エキゾチックなコードの簡潔な行にロジックを複製します。次に、そのような開発者は、そのような速記を使用して実装された共通ライブラリに機能を追加し始めるかもしれません。その時点で、共通ライブラリの重要なセクションがこれらのエキゾチックな速記と織り交ぜられ、それを導入した開発者には美しく直感的に見えるかもしれませんが、くて外国人で、他の人には理解しにくいでしょう。そして、その時点で、「共通」と「なじみのない」は正反対の考えであるため、真に「共通」なものを作成する希望は失われることを知っていると思います。

そのため、少なくとも大雑把に調整されたチーム環境には、あらゆる種類のワームの缶があり、「一般的に使用されるもの」と同じくらい広く、一般化された野望を持つライブラリがあります。そして根本的な問題は何よりも緩い調整であったかもしれませんが、数学ルーチンなどを提供することを目的としたライブラリのような、より特異な目的に役立つことを目的とした少なくとも複数のライブラリは、おそらくその点でそれほど劣化しません「共通」ライブラリとしての純度と依存関係を設計します。ですから、振り返ってみると、より明確な設計意図を持つライブラリの側でエラーを起こした方がはるかに良いと思います。また、長年にわたって、目的の狭さと適用可能性の狭さは根本的に異なる考えであることを発見しました。

また、私は少なくとも少し非実用的であり、美学についてはあまり気にしないかもしれませんが、ライブラリの品質(そしておそらく「美しさ」)についての私の考えを理解する方法は、その最も弱いリンクによって判断されます世界で最も食欲をそそる食べ物を見せてくれたのに、同じ皿の上に腐ったものを入れて本当に悪臭がするのと同じように、その最強は、皿全体を拒否する傾向があります。そして、あなたがその点で私のようであり、あらゆる種類の追加を「共通」と呼ばれるものとして誘うものを作るなら、あなたはあなたがその横に何かが腐っているその類推的なプレートを見ていることに気付くかもしれません。それで、同様に、図書館が組織され、命名され、文書化されていれば良いと思います。時間が経つにつれて、ますます多くの追加を招待します。確かに私はあちこちで腐ったものを作成しているので、それはあなたの個人的な作品にも当てはまります。それが最大のプレートに追加されていない場合、それははるかに「汚染」されます。ものを小さく非常に特異なライブラリに分離することは、すべてを結合し始めるのがはるかに不便になるという単なる美徳によってのみ、コードをより良く分離する傾向があります。

コードの重複排除は長年にわたって私に打ち込まれてきましたが、今回はそれを試してみるべきだと思います。

あなたのケースで私が提案できるのは、コードの重複排除を簡単に始めることです。十分にテストされていない、エラーが発生しやすいコードの大きなスニペットまたはこの種のコードをコピーして貼り付けたり、将来変更を必要とする可能性のある非自明なコードを大量に複製したりするつもりはありません。

しかし、特に「共通」ライブラリを作成しようと考えている場合は、広く適用可能で、非常に再利用可能なものを作成することを望んでいると思います。 、場合によっては、このとらえどころのない品質を達成するために、いくつかの複製が必要になる場合があります。複製は実際には分離メカニズムとして機能する可能性があるためです。ビデオプレーヤーをMP3プレーヤーから分離したい場合、少なくともバッテリーやハードドライブなどを複製する必要があります。彼らはこれらのことを共有することはできませんし、分割できないため互いに独立して使用することはできません。その時点で、MP3を再生するだけなら、人々はもはやデバイスに興味を持たないかもしれません。しかし、これら2つのデバイスを分割した後しばらくすると、MP3プレーヤーが、ビデオプレーヤーとは異なるバッテリー設計または小さいハードドライブの恩恵を受けることができるかもしれません。この相互依存デバイスを2つの別個の独立したデバイスに分割できるようにする複製として最初に開始されたものが、後で冗長でなくなった設計と実装をもたらすことがあります。

ライブラリを使用するものの観点から物事を検討する価値があります。実際に使いたいですかコードの重複を最小限に抑えるライブラリ?たぶん、他のライブラリに自然に依存するので、あなたはそうしないでしょう。そして、他のライブラリはコードの重複を避けるために他のライブラリに依存する可能性があります。オーディオファイルのロードや再生などの基本的な機能を取得するために50の異なるライブラリをインポート/リンクする必要が生じるまでは、非常に扱いにくくなります。一方、そのようなオーディオライブラリが意図的にあちこちでいくつかのことを複製してその独立性を達成することを選択した場合、新しいプロジェクトでの使用が非常に簡単になり、チャンスがあるため、ほとんど更新する必要がなくなる可能性があります依存する外部ライブラリが変更された結果、オーディオライブラリが必要とするものよりもはるかに一般化された目的を達成しようとしている可能性があるため、変更する必要があります。

そのため、ライブラリを分離して独立させるために、意図的に少し複製することを意識して選択する価値があります(意識的に、怠ofからではなく、実際には勤勉からではありません)安定性(求心性結合がなくなります)。あるプロジェクトから次のプロジェクトまで、そして何年にもわたって可能な限り最も再利用可能なライブラリを設計したい場合、その範囲を最小限に抑えることに加えて、ここで少し複製することを実際に検討することをお勧めします。そして、ユニットテストを自然に書き、それが実際に徹底的にテストされ、それが何をしているのか信頼できることを確認してください。これは、1つのプロジェクトをはるかに超えるポイントに一般化するために本当に時間をかけたいライブラリ専用です。


3

ライブラリーに入れることを検討する可能性のある関数には、3つの異なるカテゴリーがあります。

  1. みんなのために再利用する価値があるもの。
  2. 組織で再利用する価値があるもののみ。
  3. 再利用する価値のないもの。

カテゴリ1は標準ライブラリ存在するべきものですが、何らかの理由で誰も作成できませんでした(または誰かをしましたか?徹底的に検索しましたか?)。その場合は、ライブラリをオープンソースにすることを検討してください。作業を共有することは、他のユーザーを支援するだけでなく、他のユーザーからバグレポートとパッチを受け取るため、あなたを支援します。誰かがあなたのライブラリに貢献することを疑うとき、あなたは実際にカテゴリ2または3である機能を扱っているかもしれません。

2番目のカテゴリは何度も必要なものですが、世界中の誰もそれを必要としません。たとえば、社内開発のバックエンドシステムと通信するための不明瞭なネットワークプロトコルの実装。その場合、新しいアプリケーションの開発速度を向上させるために、そのようなものを社内ライブラリに入れるのが理にかなっているかもしれません。機能のクリープの影響をあまり受けず、実際にカテゴリ1または3に該当するものが含まれ始めていることを確認してください。さらに、モジュール化に関するBlrflのアドバイスは非常に優れています。個別の機能のために複数の個別のライブラリを作成します。

カテゴリ3は、実装が非常に簡単なため、ライブラリに移動しても価値がないか、別のアプリケーションで同じ形式で再び必要になるかどうかわからない機能です。この機能は、開発対象のアプリケーションの一部である必要があります。疑わしい場合は、おそらくこのカテゴリに属します。


1

ほとんどすべての言語に共通/標準ライブラリがあるため、これは良いアイデアとして広く認識されています。車輪を再発明するのではなく、さまざまなタスクに第3部のライブラリを使用することも、一般的には良い考えと考えられますが、それぞれのケースでコスト/メリットとライブラリの品質を明らかに評価する必要があります。

次に、それ以外の場合は無関係のプロジェクト全体で個々の開発者または機関が使用する「共通ユーティリティ」ライブラリがあります。これは、アンチパターンと見なすことができる種類のライブラリです。私が見た場合、これらのライブラリーは、標準ライブラリーまたはよく知られているサードパーティのライブラリーの機能を、非標準で文書化されていない方法で複製するだけです。


these libraries just replicate functionality from standard librariesこれは完全に悪いことではありません。javascriptには、既存のものを実装するライブラリを追加して古いjsエンジンのサポートを追加します。また、古いSDKなどのAndroidサポートライブラリもあります
。– svarog

@svarog:ネイティブにサポートしていない古いエンジンの新しい標準の機能をエミュレートする「ポリフィル」を考えていますか?これらの目的で利用できる有名なオープンソースライブラリがあるため、これらを自分で記述する理由はありません。
ジャックB

0

チーム間で共有されるほとんどのライブラリは、解決するよりも多くの問題を引き起こします。「地獄への道は善意で舗装されています。」

例外は、以下のほとんどを満たすライブラリです。

  • 安全な長期メンテナンス資金を確保する
  • 専任のサポートチーム/コミュニティがあります
  • バグトラッカーを持っている
  • 広範なテスト範囲を持っています
  • 明確に定義された単一の目的を持つ
  • 標準ライブラリまたは準標準ライブラリ以外の依存関係(ビルド時および実行時の両方)はありません。
  • パブリックAPIと内部構造を明確に区別する
  • すべて/多くのユーザーが新しい機能とリリースに同意するためのコミュニケーションチャネルとプロセスを用意する

典型的な(新興企業ではない)企業内では、チーム間で共有されるライブラリには上記の条件はほとんどありません。それは、ほとんどの企業チームが、図書館ではなく製品を提供するために支払われるためです。一部の企業は、Googleのmonorepoのような成功した共有戦略を持っていますが、これにはインフラストラクチャの構築とテストへの非常に高い投資が伴います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.