質問

コードの行を見たときに、ロジックにおけるその役割を忠実に説明するテーマの抽象化をコードに当てはめることができないという、コードの重複のケースに遭遇したことはありますか?そしてそれに対処するために何をしましたか?

これはコードの重複であるため、理想的には、独自の関数を作成するなど、何らかのリフラクタリングを行う必要があります。しかし、コードにはそれを説明するための適切な抽象化が含まれていないため、結果として、適切な名前も思いつかず、ロジック内での役割が一見しただけでは明らかではない奇妙な関数が作成されます。私にとって、これはコードの明瞭さを損なうものです。明確さを維持してそのままにすることもできますが、保守性が損なわれてしまいます。

このような問題に対処する最善の方法は何だと思いますか?

役に立ちましたか?

解決

コードの重複は「ダジャレ」の結果である場合があります。同じように見える 2 つのものは、同じではありません。

過度に抽象化すると、システムの真のモジュール性が損なわれる可能性があります。モジュール性の体制の下では、「何が変わる可能性があるのか​​」を決定する必要があります。 「安定したものは何ですか?」。安定したものはすべてインターフェイスに配置され、不安定なものはすべてモジュールの実装にカプセル化されます。そうすれば、状況が変化したときに、必要な変更はそのモジュールに分離されます。

リファクタリングは、安定していると思われた場合に必要になります (例:この API 呼び出しは常に 2 つの引数を取ります) を変更する必要があります。

そこで、これら 2 つの重複したコード部分について、次のように質問します。 一方に変更が必要な場合は、必ずもう一方も変更する必要があるのでしょうか?

この質問にどう答えると、優れた抽象化がどのようなものであるかについて、より深い洞察が得られるかもしれません。

デザインパターンも便利なツールです。おそらく、複製されたコードが何らかの形で走査を行っているため、反復子パターンを適用する必要があります。

複製したコードに複数の戻り値がある場合 (そのため、単純な抽出メソッドを実行できない場合)、おそらく、戻り値を保持するクラスを作成する必要があります。このクラスは、2 つのコード フラグメント間で異なるポイントごとに抽象メソッドを呼び出すことができます。次に、クラスの 2 つの具体的な実装を作成します。各フラグメントに 1 つずつ。[これは事実上、テンプレート メソッドの設計パターンであり、C++ のテンプレートの概念と混同しないでください。あるいは、あなたが検討している問題は、Strategy パターンを使用してより適切に解決できる可能性があります。]

これを考えるもう 1 つの自然で便利な方法は、高階関数を使用することです。たとえば、ラムダを作成したり、コードを抽象化に渡すための匿名の内部クラスを使用したりします。一般に、重複を削除することはできますが、それらの間に実際の関係がない限り(一方が変更されると、もう一方も変更される必要があります)、モジュール性を助けるどころか、害を及ぼすことになる可能性があります。

他のヒント

このような状況に遭遇すると、「非伝統的な」抽象化について考えるのが最善です。機能内に多くの重複があり、単純な古い関数を考えると、あまりにも多くの変数を渡す必要があるため、あまりうまく適合しません。ここでは、D/Pythonスタイルのネストされた機能(外側のスコープへのアクセスを備えた)がうまく機能します。 (はい、その状態をすべて保持するためにクラスを作成できますが、2つの機能でのみ使用している場合、これはネストされた機能を持たないための醜く冗長な回避策です。) Mixinはうまく機能します。たぶんあなたが本当に必要なのはマクロです。たぶん、いくつかのテンプレートメタプログラムまたは反射/内省、あるいは生成プログラミングを考慮する必要があります。

もちろん、実用的な観点からは、言語がそれらをサポートせず、言語内できれいに実装するのに十分なメタプログラム機能がない場合、これらはすべて不可能ではないにしても困難です。この場合、「より良い言語を取得する」以外に何を言うべきかわかりません。また、多くの抽象化機能(Ruby、Python、Lisp、Dなど)を備えた高レベルの言語を学習することで、いくつかのテクニックがまだ使用可能であるかもしれませんが、それほど明白ではない低レベルの言語でより良くプログラムするのに役立つ場合があります。

個人的に私はそれを無視して先に進みます。それが奇妙なケースであるなら、それを複製する方が良い場合、あなたは年齢のリファクタリングを費やすことができ、次の開発者は一見してあなたの変更を元に戻すことができます!

コードサンプルがなければ、コードに容易に識別可能な抽象化がない理由を言うのは困難です。その警告があり、ここにいくつかのアイデアがあります:

  • 共通のコードを保持する1つの新しい関数を作成する代わりに、機能をいくつかの異なる部分に分割します。
  • 一般的なデータ型または抽象的な動作に基づいて、小さな部分をグループ化します。
  • 新しいピースを考慮して、重複コードを書き直します。
  • 新しいコードが引き続き明確な抽象化を拒否した場合は、それを小さく分けてプロセスを繰り返します。

この演習の最大の難しさは、あなたの機能が特定の抽象化レベルであまりにも多くの無関係な動作を組み込んでいる可能性が高いことであり、それらのいくつかをより低いレベルで処理する必要があることです。明確さはコードを維持するための鍵であると正しく推測しますが、コードの動作を明確にすること(現在の条件)は、コードの意図を明確にすることとは大きく異なります。

関数の署名に何を識別させることにより、小さなコードピースの抽象的な方法を作成し、より大きなピースを分類しやすくする必要があります。

ライセンス: CC-BY-SA帰属
所属していません softwareengineering.stackexchange
scroll top