数日前、私はソフトウェア工学博士号の候補者と話をしていましたが、ある時点で彼女は私に言いました。
クラスとメソッドをできるだけ小さくしてください
そして、これは常に良い習慣であるのだろうか。
たとえば、クラスに属性が2つしかないことは価値があるのでしょうか?たとえば、いくつかのメソッドでは、整数のペアを使用する必要があります。「PairOfIntgers」クラスを作成する必要がありますか?
この考え方は、あまりにも多くの部分でコードを「壊す」ことができますか?
数日前、私はソフトウェア工学博士号の候補者と話をしていましたが、ある時点で彼女は私に言いました。
クラスとメソッドをできるだけ小さくしてください
そして、これは常に良い習慣であるのだろうか。
たとえば、クラスに属性が2つしかないことは価値があるのでしょうか?たとえば、いくつかのメソッドでは、整数のペアを使用する必要があります。「PairOfIntgers」クラスを作成する必要がありますか?
この考え方は、あまりにも多くの部分でコードを「壊す」ことができますか?
回答:
そのアドバイスには真実の粒がありますが、私見ではあまりよく表現されていないので、誤解や愚かな極端になりやすいです。とにかく、これは厳密な法律ではなく、経験則である必要があります。そして、そのようなルールでは、「合理的な範囲内」の節、または「しかし、あなたの常識を使うことを忘れないでください」という節を常に暗示すべきです:-)
真実の穀物は、ということです実際には、クラスやメソッドは常に縮小、自然ではない成長する傾向があります。ここでのバグ修正、そこへの小さな機能拡張、そこへの特別なケースの処理...そして出来上がり、かつてきちんとした小さなクラスが膨張し始めます。時間が経つにつれて、あなたのコードはほとんど必然的にスパゲッティの巨大な混乱になる傾向があります- リファクタリングによって積極的にこの傾向と戦わない限り。リファクタリングはほとんどの場合、いくつかの大きなクラス/メソッドから多くの小さなクラス/メソッドを生成します。しかし、もちろん、小型化には賢明な制限があります。リファクタリングのポイントは、クラスやメソッド自体を小さくすることではなく、コードをよりきれいに、理解しやすく、保守しやすくすることです。特定の時点で、メソッド/クラスを小さくすると、読みやすさを向上させるのではなく、読みやすさが低下し始めます。その最適を目指してください。これはぼやけて移動するターゲットエリアなので、その場でヒットする必要はありません。ただ、あなたはそれにいくつかの問題に気づいたときにコードを少し改善します。
ここで強調するより重要な問題は、適切な抽象化を作成することです。疎結合で結合性の高い小さなクラスは、優れた抽象化の産物です。
クラスに2つの整数をカプセル化することが完全に理にかなっている場合があります。特に、これらの属性を操作する方法をカプセル化し、それらを変更するプログラムの他の部分から確実に保護するために、このクラスにメソッドを「アタッチ」したい場合。
この場合、クラスを作成するもう1つのメリットは、MapやListのような低レベルのデータ構造よりも、クラスがはるかに優れたものに進化できることです。
第三に、優れた抽象化により、読みやすさが大幅に向上します。通常、SRPに準拠するクラスは、そうでないクラスよりも人間が理解しやすいものです。
そして最後のメモとして...あなたがどんなに優秀な学生であっても... OOPと優れた抽象化を理解し、それらをいつ使用するかは経験が必要です。悪いコードを書いて、それを維持するために苦労する必要があります。何が「良い」か、そして何が問題になるかについての知識を築くために、他の人が良いコードを書くことを見る必要があります。
God Objectのアンチパターンは、彼女がおそらくほのめかしていたものです。クラスの説明に「and」が含まれている場合、2つのクラスが必要だと思いがちです。メソッド/関数に10行を超えるコードがある場合は、分割する必要があります。海賊コードとして、それらはルールよりもガイドラインです。
オブジェクト指向プログラミングでは、単一の責任の原則では、すべてのオブジェクトに単一の責任があり、その責任はクラスによって完全にカプセル化される必要があると規定されています。通常、クラスが大きくなりすぎると、複数のことをします。あなたの場合、クラスは、まったく問題のないデータを保持する単なるデータクラスです。クラスにPairOfIntegerという名前を付けるべきではありません。整数は何を説明していますか?シナリオによっては、タプル(C#など)でも十分な場合があります。そして、あなたはクラスの代わりに支柱について考えたいかもしれません。
あなたのクラスを小さく保つようにしてください。そして、メソッドはさらに小さくなります。たぶん10行?!?現在、クラスを小さく抑えるのに役立つと思われるフローデザインとイベントベースのコンポーネントを使用しようとしています。最初は多くのクラスに行くのが心配でしたが、本当にうまくいきます!!! http://geekswithblogs.net/theArchitectsNapkin/archive/2011/03/19/flow-design-cheat-sheet-ndash-part-i-notation.aspx http://geekswithblogs.net/theArchitectsNapkin/archive/2011/03 /20/flow-design-cheat-sheet-ndash-part-ii-translation.aspx
物事をできる限りシンプルにしますが、シンプルではありません。それが私がやろうとしているルールです。時には、クラスがいくつかの共通のテーマに関連している場合、厳密に言えば複数のことを行うことが実際に理にかなっています。.NETを見てください。多数のインターフェイスを実装するクラスが多数あり、それぞれに必要なメンバーの独自のリストがあります。メソッドは、すべて相互接続されているため、リファクタリングにあまり適していない多くの中間ステップで複雑な処理を行う場合、やや長くなる必要があります。(メソッドを短く保つためのリファクタリングは、最終的には読みやすさと保守性に関するものでなければなりません。長いメソッドが短いメソッドよりも読みやすく、保守可能である場合、他のすべてが等しい場合、私はいつでも長いものを取ります)
私の意見では、「クラスとメソッドをできる限り小さくする」ことは間違っています。本当の課題は、@ c_makerが指摘しているように、優れた抽象化を提供することです。たとえば、複素数演算の実装に取り組んでいる場合や、Unixシステムでユーザー/グループコンテキストを参照する必要がある場合、2つの数値をグループ化する例は素晴らしいです。番号が、たとえば請求書IDとその請求書に追加される製品IDを表す場合、ほとんど意味がありません。
これは問題ありませんが、ある程度インテリジェントに実装する必要があります。絶対に盲目的にフォローしないでください。
コードを見ると、メソッドが大きすぎるかどうかがわかります。やりすぎで読みにくい場合は、リファクタリングの時間です。
良い例です:ループがあり、そのメソッドに60行のコードがあるかもしれません。その場合、おそらくリファクタリングする時が来ているでしょう。おそらく、そのメソッドでやりすぎだからです。
しかし、それは難しい規則ではありません。それはあなたがすることによって学ぶことができるものだけです。そして、あなたと一緒に働いている他の開発者は、必ずしも同意しているわけではなく、コードレビューなどであなたを呼ぶかもしれません。
ボブおじさんは、メソッドをリファクタリング/分割/抽出する必要があると言っています 小さくすることが不可能になるまで。これは通常、3行または4行の複数のメソッドを持つことになります。取得するメソッドが多すぎる場合、さらに多くのクラスを作成する必要があります。
メソッドごとに1レベルの抽象化とSRPを実行しようとすると、これらのルールが役立ちます。少なくとも彼らは私によく役立っています。「できるだけ小さく」を目指して、私は通常、目的を達成できないため、合理的な小さな方法を提供します。
そして、小さなクラスを理解する方が常に簡単です。先に進み、「クリーンコード」を読んでください
"As small as possible, but no smaller."