web-dev-qa-db-ja.com

プライベート関数/メソッドが多すぎるということはありますか?

十分に文書化されたコードの重要性を理解しています。しかし、自己文書化コードの重要性も理解しています。特定の機能を視覚的に読み取ることが容易であるほど、ソフトウェアのメンテナンスをすばやく行うことができます。

そうは言っても、big関数を他の小さな関数に分離するのが好きです。しかし、1つのパブリックメソッドを提供するためだけに、クラスが5つ以上のクラスを持つことができるようになるまで、私はそうします。 5つのプライベートメソッドを5つのパブリックメソッドで乗算すると、約25の非表示メソッドが取得されます。

確かに、これらのパブリックメソッドを読む方が簡単になりましたが、関数が多すぎることは悪い習慣だと思わざるを得ません。

[編集]

機能が多すぎるのはよくないことだと思う理由を聞かれます。

簡単な答え:それは直感です。

私の信念は、少しの間、ソフトウェアエンジニアリングの経験に裏付けられたものではありません。プログラマーにとっては、「作家のブロック」を与えたのは不確実性だけです。

過去には、個人的なプロジェクトのプログラミングしか行っていません。チームベースのプロジェクトに移ったのはつい最近のことです。今、私は他の人が私のコードを読んで理解できるようにしたいと思います。

何が読みやすさを向上させるかわかりませんでした。一方では、1つの大きな機能をわかりやすい名前で他の小さな機能に分離することを考えていました。しかし、それは冗長であるという私の別の側面がありました。

だから、私は正しい道を選ぶために自分自身を啓発するためにこれを求めています。

[編集]

以下に、私が問題をどのように解決できたかの2つのバージョンを含めました。最初のコードは、大きなコードの塊をしないことで解決します。 2つ目は、物事を分離します

最初のバージョン:

public static int Main()
{
    // Displays the menu.
    Console.WriteLine("Pick your option");
    Console.Writeline("[1] Input and display a polynomial");
    Console.WriteLine("[2] Add two polynomials");
    Console.WriteLine("[3] Subtract two polynomials");
    Console.WriteLine("[4] Differentiate two polynomials");
    Console.WriteLine("[0] Quit");
}

2番目のバージョン:

public static int Main()
{
    DisplayMenu();
}

private static void DisplayMenu()
{
    Console.WriteLine("Pick your option");
    Console.Writeline("[1] Input and display a polynomial");
    Console.WriteLine("[2] Add two polynomials");
    Console.WriteLine("[3] Subtract two polynomials");
    Console.WriteLine("[4] Differentiate two polynomials");
    Console.WriteLine("[0] Quit");
}

上記の例では、後者はプログラムのランタイム全体で一度だけ使用される関数を呼び出します。

注:上記のコードは一般化されていますが、私の問題と同じ性質のものです。

さて、これが私の質問です:どれですか?最初のものを選ぶのですか、それとも2番目のものを選ぶのですか?

63
Sal

5つのプライベートメソッドと5つのパブリックメソッドを乗算すると、約25の非表示メソッドが取得されます。これらのメソッドは、おそらくこれらのパブリックメソッドによって1回だけ呼び出されます。

これは カプセル化 として知られているもので、上位レベルに Control Abstraction を作成します。これは良いことです。

これは、コードのstartTheEngine()メソッドに到達したときに、コードを読んでいる誰もが、openIgnitionModule()turnDistributorMotor()などの下位レベルの詳細をすべて無視できることを意味します、sendSparksToSparkPlugs()injectFuelIntoCylinders()activateStarterSolenoid()、およびより大きくより抽象的な関数を実行するために実行する必要がある他のすべての複雑で小さな関数startTheEngine()の。

コードで処理している問題がこれらのコンポーネントの1つに直接対処しない限り、コードの保守担当者は、サンドボックス化されたカプセル化された機能を無視して、先に進むことができます。

これには、コードをテストしやすくするという追加の利点もあります。たとえば、turnAlternatorMotor(int revolutionRate)のテストケースを作成して、他のシステムから完全に独立して機能をテストできます。その関数に問題があり、出力が期待どおりでない場合は、問題が何であるかを知っています。

コンポーネントに分解されないコードは、テストがはるかに困難です。突然、メンテナは、測定可能なコンポーネントに掘り下げることができるのではなく、抽象化であると考えているところだけを見ています。

私のアドバイスは、コードがスケーリングされ、保守が容易になり、今後数年間使用および更新できるようになるため、現在行っていることを継続することです。

36
jmort253

はいといいえ。基本的な原則は次のとおりです。メソッドは1つの処理と1つの処理のみを実行する必要があります

メソッドをより小さなメソッドに「分割」するのは正しいことです。繰り返しになりますが、これらのメソッドはonlyがその「大きな」メソッドを提供せず、他の場所で再利用できないように十分に一般的である必要があります。ただし、InitializePlugins、InitializeInterfaceなどを呼び出すInitializeメソッドのように、メソッドが単純なツリー構造に従う場合もあります。

あなたが本当に大きなメソッド/クラスを持っているなら、それは通常それが多くをしているサインであり、そしてあなたは「ブロブ」を分割するためにリファクタリングをする必要がある。 Perphapsは抽象化の下で別のクラスの複雑さを隠し、依存性注入を使用します

22
Homde

一般的には、関数が少なすぎるのではなく、多すぎる方がいいと思います。実際に見たそのルールの2つの例外は、 [〜#〜] dry [〜#〜][〜#〜] yagni [〜#〜] です。 =原則。ほぼ同一の機能が多数ある場合は、それらを組み合わせてパラメーターを使用し、繰り返し使用しないようにする必要があります。 「念のため」に作成し、それらが使用されていない場合、関数が多すぎる可能性があります。可読性と保守性が追加されていれば、一度しか使用されない機能があることには何の問題もありません。

17
Karl Bielefeldt

jmort253の素晴らしい答えは、「はい、しかし」という答えでフォローアップするように私に刺激を与えました...

小さなプライベートメソッドをたくさん持つことは悪いことではありませんが、ここに質問を投稿することになる、くすんだ感じに注意してください:)。プライベートメソッドのみに焦点を当てたテストを作成しているポイントに到達した場合(直接呼び出すか、結果をテストできるように特定の方法で呼び出されるようにシナリオを設定する)一歩下がるべきだ。

あなたが持っているかもしれないのは、エスケープしようとしている独自のより集中したパブリックインターフェースを持つ新しいクラスです。その時点で、クラスを抽出して、現在プライベートメソッドに存在している既存のクラス機能のその部分をカプセル化することを検討することをお勧めします。これで、元のクラスが新しいクラスを依存関係として使用できるようになり、そのクラスに対してより集中したテストを直接作成できます。

10
Pete Hodgson

ほぼすべてのOO私がこれまでに参加したことのあるプロジェクトは、大きすぎるクラスと長すぎるメソッドにひどく苦しみました。

コードの次のセクションを説明するコメントの必要性を感じたら、そのセクションを別のメソッドに抽出します。長期的には、これによりコードが短くなります。これらの小さなメソッドは、最初に予想したよりも多く再利用されます。あなたはそれらの束を別のクラスに集める機会を見始めます。すぐに問題をより高いレベルで考えるようになり、全体の作業がはるかに速くなります。新しい機能は、これらの小さなメソッドから作成した小さなクラスに基づいて構築できるため、記述が簡単です。

8
kevin cline

5つのパブリックメソッドと25のプライベートメソッドを持つクラスは、私にはそれほど大きくありません。クラスに明確な責任があり、メソッドの数をあまり気にしないでください。

つまり、これらのプライベートメソッドは、タスク全体の特定の側面に焦点を当てる必要がありますが、「doSomethingPart1」、「doSomethingPart2」の方法ではありません。これらのプライベートメソッドが任意に分割された長いストーリーの一部であり、コンテキスト全体の外では意味がない場合、何も得られません。

7
user281377

R.マーティンのクリーンコード(p。176)からの抜粋:

重複の排除、コードの表現力、SRPなどの基本的な概念でさえ、あまりに遠くまで行き過ぎることがあります。クラスとメソッドを小さくするために、非常に多くの小さなクラスとメソッドを作成する可能性があります。したがって、このルール[クラスとメソッドの数を最小限に抑える]は、関数とクラスの数も少なくすることを示唆しています。クラスとメソッドの数が多いのは、無意味な独断の結果である場合があります。

4
user2418306

いくつかのオプション:

  1. それはいいです。プライベートメソッドに名前を付けるだけでなく、パブリックメソッドにも名前を付けます。そして、パブリックメソッドに適切な名前を付けます。

  2. これらのヘルパーメソッドのいくつかをヘルパークラスまたはヘルパーモジュールに抽象化します。そして、これらのヘルパークラス/モジュールが適切に命名され、それ自体がしっかりとした抽象であることを確認してください。

3
yfeldblum

「プライベートメソッドが多すぎる」という問題が、そのように感じられた場合、コードアーキテクチャが不十分であることの症状である可能性があるとは思いません。

これが私の考えです...アーキテクチャが適切に設計されている場合、Xを実行するコードがどこにあるべきかは一般的に明らかです。これにいくつかの例外がある場合は許容されますが、これらは本当に例外的である必要があり、そうでなければ標準としてこれらを処理するためにアーキテクチャをリファクタリングする必要があります。

問題は、クラスを開く際に、大きなチャンクを小さなコードチャンクに分割するプライベートメソッドでいっぱいである場合、おそらく、これはアーキテクチャーの欠落の症状です。クラスとアーキテクチャの代わりに、このコード領域は、1つのクラス内で手続き的に実装されています。

ここでバランスを見つけることは、プロジェクトとその要件によって異なります。これに対する反論は、ジュニアプログラマーが、50クラスのアーキテクトを必要とする50行のコードでソリューションをノックアップできるということです。

1
Michael Shaw

プライベート関数/メソッドが多すぎるということはありますか?

はい。

Python「プライベート」の概念(C++で使用されているように、JavaおよびC#)には実際には存在しません)。

「プライベートのような」命名規則がありますが、それだけです。

Privateはテストが難しいコードにつながる可能性があります。また、コードを単純にクローズすることにより、「オープン/クローズの原則」を破ることもできます。

その結果、Pythonを使用したことがある人にとって、プライベート関数は価値がありません。すべてを公開して、それで完了します。

0
S.Lott