19

私は最近、自分のプロジェクトのコードベースで発生している問題にますます不満を感じています。

私は、1M 行以上のコードを持つ大規模な Java プロジェクトに取り組んでいます。インターフェイスとクラス構造は非常にうまく設計されており、コードを書いているエンジニアは非常に熟練しています。問題は、コードをよりきれいにしようとして、一部の機能を再利用する必要があるときはいつでも人々がユーティリティ クラスを作成することです。その結果、時間が経つにつれて、またプロジェクトが成長するにつれて、ますます多くのユーティリティ メソッドが作成されます。ただし、次のエンジニアが同じ機能の必要性に出くわしたとき、誰かが既にコードのどこかにユーティリティ クラス (またはメソッド) を実装していて、別のクラスに機能の別のコピーを実装していることを知る方法はありません。その結果、多くのコードが重複し、機能が重複するユーティリティ クラスが多すぎます。

ユーティリティ クラスの重複や低可視性を防ぐために、チームとして実装できるツールや設計原則はありますか?

例:エンジニア A には、XML を文字列に変換する必要がある 3 つの場所があるため、XMLUtilというユーティリティ クラスを作成し、その中に静的toString(Document)メソッドを配置します。エンジニア B には、ドキュメントを String を含むさまざまな形式にシリアル化する場所がいくつかあるため、SerializationUtilserialize(Document)というユーティリティ クラスを作成し、String を返す静的メソッドを呼び出します。

上記の例の 2 つの実装が異なる可能性が非常に高いため (一方はトランスフォーマー API を使用し、もう一方は Xerces2-J を使用するとします)、これは単なるコードの重複ではありません。 「問題も…

更新:私たちが開発している現在の環境をよりよく説明していると思います。CI には Hudson、コード カバレッジには Clover、静的コード分析には Checkstyle を使用しています。日々のトークや(不十分かもしれませんが)コードレビューを含むアジャイル開発を行っています。すべてのユーティリティ クラスを .util で定義します。このサイズにより、ルート (.util) クラスの下に 13 のサブパッケージと約 60 のクラスが含まれるようになりました。また、ほとんどの apache commons jar や Guava を構成する一部の jar などのサードパーティ ライブラリも使用しています。

パッケージ全体のリファクタリングを誰かに任せれば、ユーティリティの量を半分に減らすことができると確信しています。問題の再発を可能な限り遅らせることができます。

4

9 に答える 9

9

この問題の良い解決策は、オブジェクト指向をさらに追加することです。あなたの例を使用するには:

例: エンジニア A には、XML を文字列に変換する必要がある 3 つの場所があるため、XMLUtil というユーティリティ クラスを作成し、その中に静的な toString(Document) メソッドを配置します。

解決策は、プリミティブ型または JVM によって提供される型 (String、Integer、java.util.Date、java.w3c.Document) の使用を停止し、それらを独自のプロジェクト固有のクラスにラップすることです。次に、XmlDocument クラスで便利な toString メソッドやその他のユーティリティ メソッドを提供できます。独自の ProjectFooDate には、そうでなければさまざまな DateUtils クラスなどになる解析および書式設定メソッドを含めることができます。

このように、IDE は、オブジェクトで何かをしようとするたびに、ユーティリティ メソッドでプロンプトを表示します。

于 2013-04-14T06:54:19.703 に答える
6

あなたの問題は非常に一般的なものです。良い解決策がないため、実際の問題もあります。

私たちはここでも同じ状況にあります。さらに悪いことに、1,300 万行のコード、売上高、800 人を超える開発者がコードに取り組んでいます。私たちは、あなたが説明したのとまったく同じ問題についてよく話し合います。

最初のアイデア (開発者が既に使用している) は、いくつかのユーティリティ クラスで共通コードをリファクタリングすることです。ペアプログラミング、メンタリング、ディスカッションを行ったとしても、そのソリューションの問題は、これが効果的であるには人数が多すぎるということです. 実際、私たちはサブチームで成長し、人々はサブチームで知識を共有していますが、知識はサブチーム間を移動しません。間違っているかもしれませんが、この場合はペアプログラミングやトークでも役に立たないと思います。

建築チームもあります。このチームは、設計とアーキテクチャの問題に対処し、必要になる可能性のある共通ユーティリティを作成する責任があります。このチームは実際、企業のフレームワークと呼べるものを生み出しています。はい、これはフレームワークであり、うまく機能する場合もあります。このチームは、ベスト プラクティスを推進し、何をすべきか、何をすべきか、何が利用可能で何が不可能かについての認識を高める責任もあります。

優れたコア Java API 設計は、Java の成功の理由の 1 つです。優れたサードパーティのオープン ソース ライブラリも重要です。巧妙に作成された小さな API でさえ、非常に有用な抽象化を提供し、コード サイズを大幅に削減することができます。しかし、フレームワークとパブリック API を作成することは、ユーティリティ クラスを 2 時間でコーディングすることとはまったく同じではありません。それは本当に高いコストを持っています。ユーティリティ クラスの費用は、最初のコーディングに 2 時間、デバッグと単体テストに 2 日ほどかかります。大規模なプロジェクトやチームで共通のコードを共有し始めると、実際に API が作成されます。その場合、完全なドキュメント、つまり本当に読みやすく保守可能なコードを確保する必要があります。このコードの新しいバージョンをリリースするときは、下位互換性を維持する必要があります。会社全体(または少なくともチーム全体)で宣伝する必要があります。小規模なユーティリティ クラスの場合は 2 日から 10 日になり、

そして、あなたの API 設計はそれほど素晴らしいものではないかもしれません。エンジニアが賢くないというわけではありません。しかし、UI の一貫した方法で数値を解析するだけの小さなユーティリティ クラスで 50 日間作業させてもよろしいですか? まったく異なるニーズを持つモバイル UI を使い始めるとき、彼らに全体を再設計してもらいますか? また、世界で最も優秀なエンジニアが、決して普及しないか、ゆっくりと衰退する API をどのように作成しているのかに気付きましたか? ご覧のとおり、私たちが作成した最初の Web プロジェクトでは、内部フレームワークのみを使用するか、フレームワークをまったく使用しませんでした。次に、PHP/JSP/ASP を追加しました。次に、Java に Struts を追加しました。現在は JSF が標準です。そして、Spring Web Flow、Vaadin、Lift を使用することを考えています...

私が言いたいのは、良い解決策がないということだけです。オーバーヘッドは、コードのサイズとチームのサイズに応じて指数関数的に増加します。大きなコードベースを共有すると、俊敏性と応答性が制限されます。あらゆる変更は慎重に行う必要があり、潜在的な統合の問題をすべて考慮し、全員が新しい特異性と機能についてトレーニングを受ける必要があります。

しかし、ソフトウェア会社の主な生産性ポイントは、XML を解析するときに 10 行または 50 行のコードを取得しないことです。これを行うための一般的なコードは、何千行ものコードになり、ユーティリティ クラスによって階層化される複雑な API を再作成します。男が XML を解析するためのユーティリティ クラスを作成する場合、それは優れた抽象化です。彼は、10 行または 100 行の特殊なコードに名前を付けます。このコードは特殊化されているため便利です。共通 API を使用すると、ストリーム、URL、文字列などを処理できます。ファクトリがあるため、パーサーの実装を選択できます。ユーティリティ クラスは、このパーサーと文字列でのみ機能するため、優れています。そして、それを呼び出すには 1 行のコードが必要だからです。しかしもちろん、このユーティリティ コードの用途は限られています。これは、このモバイル アプリケーションや XML 構成の読み込みに適しています。そしてそれは'

結論として、コードベース全体のコードを統合しようとする代わりに、チームの成長に合わせてコードの責任を分割することを検討します。

  • 1 つの大きなプロジェクトに取り組む大きなチームを、複数のサブプロジェクトに取り組む小さなチームに変えます。
  • 統合の問題を最小限に抑えるためにインターフェイスが適切であることを確認しますが、チームには独自のコードを持たせます。
  • これらのチームと対応するコードベース内で、ベスト プラクティスがあることを確認してください。重複コードなし、優れた抽象化。コミュニティからの既存の実績のある API を使用します。ペア プログラミング、強力な API ドキュメント、Wiki を使用してください。ただし、チーム間でコードが重複したり、設計上の決定が異なる場合でも、実際にはさまざまなチームに選択を任せ、独自のコードを作成する必要があります。設計上の決定が異なる場合は、ニーズが異なることが原因である可能性があります。

あなたが本当に管理しているのは複雑さです。最終的に、非常に一般的で高度なモノリシックなコードベースを作成すると、新規参入者が立ち上がる時間が長くなり、開発者が共通のコードをまったく使用しないリスクが高まり、すべての変更が原因で全員の速度が低下します。既存の機能を壊す可能性がはるかに高くなります。

于 2011-04-18T09:36:12.747 に答える
4

これに対処するために使用できるいくつかのアジャイル/XP プラクティスがあります。

  • お互いに話す (例: 毎日のスタンドアップ ミーティング中)
  • ペアプログラミング・コードレビュー

次に、参照可能な 1 つまたは複数のユーティリティ ライブラリ プロジェクトを作成、文書化、およびテストします。Maven を使用して依存関係/バージョンを管理することをお勧めします。

于 2011-04-11T18:06:58.413 に答える
3

すべてのユーティリティ クラスを のようなよく整理されたパッケージ構造に配置することを提案することを検討してくださいcom.yourcompany.util.。人々がサブパッケージとクラスに適切な名前を付けることを厭わない場合、少なくともユーティリティを見つける必要がある場合、どこを見ればよいかがわかります。ただし、ここに特効薬の答えはないと思います。コミュニケーションは重要です。おそらく、開発者が新しいユーティリティを作成するときに、残りの開発スタッフに簡単な電子メールを送信するだけで、人々の注意を引くことができるでしょう。または、人々がそれらをリスト/文書化できる共有 wiki ページ。

于 2011-04-11T18:18:49.633 に答える
1
  1. チームのコミュニケーション (「ドキュメント toString を持っている人はいますか?」と叫びます)
  2. ユーティリティ クラスを最小限に抑え、単一の名前空間に制限する
  3. オブジェクトでこれを行うにはどうすればよいか、常に考えてください。あなたの例では、 Document クラスを拡張し、それらtoStringserializeメソッドをそれに追加します。
于 2011-04-11T18:28:49.173 に答える
0

「同じ機能」を認識するツールを構築するのはかなり難しいです。(理論的にはこれは実際には不可能であり、実際にそれを行うことができる場合は、定理証明者が必要になる可能性があります)。

しかし、よくあることは、人々が望むものに近いクローンを作成し、それをカスタマイズすることです。 クローン検出器を使用して見つけることができるその種のコード。

CloneDRは、パラメーター化された構文ツリーの使用に基づいて、正確でニアミスのクローンコードを検出するためのツールです。解析されたバージョンのコードと一致するため、レイアウト、コメントの変更、変数名の改訂、または多くの場合、ステートメントの挿入または削除によって混乱することはありません。多くの言語(C ++、COBOL、C#、Java、JavaScript、PHPなど)のバージョンがあり、提供されたリンクでクローン検出の実行例を確認できます。通常、10〜20%の重複コードが検出され、そのコードを宗教ベースのライブラリメソッドに抽象化すると、コードベースが実際に縮小する可能性があります(これは、CloneDRを使用する1つの組織で発生しました)。

于 2011-04-12T03:10:22.363 に答える
0

あなたはこの避けられない問題を管理するのを助けることができる解決策を探しています、そして私はツールを提案することができます:

読むべきより多くのもの:

于 2011-04-13T20:57:17.410 に答える
0
  1. 標準のアプリケーションユーティリティプロジェクト。機能に基づいて拡張性の範囲とパッケージが制限されたjarを構築します。
  2. apache-commonsやgoogleコレクションなどの一般的なユーティリティを使用して抽象化を提供する
  3. 知識ベースとドキュメント、およびバグと拡張機能のJIRA追跡を維持する
  4. 進化的リファクタリング
  5. コードの重複やバグを見つけるためのfindbugsとpmd
  6. ユーティリティツールのパフォーマンスのレビューとテスト
  7. util karma!チームメンバーに、既存のジャングルコードでコードベースを見つけた場合、または新しいコードベースが必要な場合はいつでも、コードベースに貢献するように依頼します。
于 2011-04-14T04:27:38.813 に答える
0

この問題は、IDE の「コード補完」機能を型拡張をサポートする言語 (C# や F# など) と組み合わせると解決します。Java にそのような機能があると想像すると、プログラマーは次のように IDE 内でクラスのすべての拡張メソッドを簡単に調べることができます。

Document doc = ...
doc.to //list pops up with toXmlString, toJsonString, all the "to" series extension methods

もちろん、Java には型拡張はありません。ただし、grep を使用してプロジェクトを検索し、「SomeClass を最初の引数として取るすべての static public メソッド」を検索して、特定のクラスに対してどのユーティリティ メソッドが既に記述されているかについて同様の洞察を得ることができます。

于 2011-04-11T18:43:39.883 に答える