web-dev-qa-db-ja.com

共通ライブラリは良い考えですか?

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

私は最近これを見つけることができないという記事を最近読みましたが、これは実際には悪い考えであり、「アンチパターン」であるとまで言っていました。

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

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

これを書いている間、私はこの「共通lib」アプローチがアーキテクチャをざっと見た結果だと思い始めていますか?おそらく私のデザインはもっと考えが必要ですか?

考えを聞いて興味があります。

16
jim

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

ビジネスユニット全体の64ビットシステムへのコード(主に私にとっては新しい)の最初の移植を担当し、ビルドとパッケージングの完全な見直しを行ったときに、これが実際に実行されているのを見ました。手作業で、時にはあまりうまくいかない場合があります。*アプリケーションのスタックから出荷したものを作成する傾向があり、クライアントは「A、B、D、Fに加えてMを実行するシステムが欲しいそして、Nはまだ実行しておらず、それらすべてを統合するわずかに異なる接着剤です。」そのすべてに共通していたのは、20年以上にわたって**人々が再利用可能であると考えていたすべてのものを蓄積してきたジャンクドロワーライブラリでした。簡単に言えば、ライブラリのコードの一部はどこでも使用されておらず、多くの依存関係が出荷されたすべてのプロジェクトにドラッグされていました。これらの依存関係を構築して維持するために多くの貴重な時間を費やしていたため、実際にそれらが必要だったのではなく、共通ライブラリがインストールされました。

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

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

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


*その過程で、過去に渡り、6年間でゼロから再コンパイルされなかったバイナリを発見しました。

**数十年前のコードに問題はありません。非常によく証明されている重要なアルゴリズムがいくつかありましたが、現代性のためだけにそれらを書き換えるのはばかでした。

21
Blrfl

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

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

そして、それは十分に始まりました。線形代数に重いコンピュータグラフィックスで作業していたため、毎日使用するルーチンの数学ライブラリ(common/math*)から始めました。また、Cコードを頻繁に使用していたため、find_indexなどの便利なユーティリティ関数に同意しました。これは、C++のstd::findとは異なり、イテレータではなく、シーケンスで見つかった要素へのインデックスを返します。私のC関数がどのように機能するかを模倣しました-この種のもの-少し折衷的ですがミニマリストであり、誰もが慣れ親しんでいるために十分に広く使用されており、即時の親しみやすさは、 「一般的」または「標準的」であるのは、それが本当に「一般的」である場合、その幅広い採用と日常的な使用の結果として、おなじみの品質を持つ必要があるためです。

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

しかし、このライブラリーに何を入れるべきか、何を入れるべきでないかを議論することによって、「共通」と見なされるものは、「共通」であるという非常に難しいラインルールを設定しないと、非常に主観的な考えに簡単に変わる可能性があることもわかりました。誰もが日常的に役立つと思うもの。標準が緩むと、誰もが日常的に役立つと思うものから、単一の開発者が役立つと思うものにすぐに低下します可能性があります他の人に有益である可能性があり、その時点でライブラリ折衷的な混乱に非常に速く低下します。

しかし、さらにその時点に到達すると、一部の開発者は、プログラミング言語が気に入らないという単純な理由で追加を開始できます。 forループや関数呼び出しの構文が気に入らない場合があります。その時点で、ライブラリは、言語の基本的な構文と戦っているだけで満たされ始め、実際にはない簡単なコードの数行を置き換えますロジックを複製して、そのような省略表現を導入した開発者だけが知っているエキゾチックなコードの簡潔な1行にまとめます。次に、そのような開発者は、そのような省略形を使用して実装された共通ライブラリにさらに機能を追加し始めるかもしれません。他の人には理解しにくい。そして、その時点で、「共通」と「なじみのない」は正反対の考えであるため、何かを本当に「共通」にする希望は失われていることを知っていると思います。

したがって、少なくともゆるやかに調整されたチーム環境では、あらゆる種類のワームの缶が存在し、ライブラリには、「一般的に使用されるもの」と同じくらい広く、一般化された野望があります。そして根本的な問題は何よりも緩やかな調整だったかもしれませんが、数学ルーチンを提供することを目的としたライブラリなど、より特異な目的を果たすことを目的とした少なくとも複数のライブラリは、おそらくその点で大幅に低下しません純粋さと依存関係を「共通」ライブラリとして設計します。したがって、振り返ってみると、デザインの意図がより明確なライブラリの方を誤るほうがはるかに良いと思います。また、長年にわたって目的が狭く、適用範囲が狭いことは根本的に異なるアイデアであることがわかりました。多くの場合、最も広く適用できるものは、目的が最も狭く、最も特異なものです。それは、「ああ、これはまさに私が必要とするものです」と言うことができるからです。あなたが必要です。

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

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

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

しかし、特に「一般的な」ライブラリを作成するマインドがある場合は、広く適用可能で再利用性の高いもの、おそらく理想的には、10年後と同じように今日でも役立つものを作成したいと思います。 、次に、このとらえどころのない品質を実現するために、場合によっては、いくつかの複製が必要になるか、必要になることさえあります。なぜなら、複製は実際には分離メカニズムとして機能するからです。ビデオプレーヤーをMP3プレーヤーから分離したい場合は、少なくともバッテリーやハードドライブなどを複製する必要があります。彼らはこれらのものを共有することができないか、そうでなければそれらは不可分に結合され、互いに独立して使用することができず、その時点で人々がやりたいことがすべてMP3を再生することである場合、もはやデバイスに興味がないかもしれません。しかし、これら2つのデバイスを分割した後、しばらくすると、MP3プレーヤーは、ビデオプレーヤーとは異なるバッテリー設計または小さなハードドライブの恩恵を受けることがわかります。この時点では、何も複製されていません。この相互依存型デバイスを2つの独立した独立したデバイスに分割できるようにするために最初は重複していたものが、後で冗長性がなくなった設計と実装になる可能性があります。

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

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

9
user204677

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

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

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

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

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

3
Philipp

ほとんどすべての言語に共通/標準ライブラリがあります。そのため、これは優れたアイデアとして広く認識されています。ホイールを再発明するのではなく、さまざまなタスクにサードパーティのライブラリを使用することも、一般的には良いアイデアと見なされますが、コスト/メリットとライブラリの品質をそれぞれの場合に明らかに評価する必要があります。

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

1
JacquesB

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

例外は、以下のmostを満たすライブラリです。

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

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

0
tkruse