コードをクラスや関数にラップする代わりに、長くて簡単なコードをコピーして貼り付けることは受け入れられますか?


29

インターネットに接続し、そのような接続結果を表示するコードのセグメントがあるとします:

HttpRequest* httpRequest=new HttpRequest();
httpRequest->setUrl("(some domain .com)");
httpRequest->setRequestType(HttpRequest::Type::POST);
httpRequest->setRequestData("(something like name=?&age=30&...)");
httpRequest->setResponseCallback([=](HttpClient* client, HttpResponse* response){
    string responseString=response->getResponseDataString();
        if(response->getErrorCode()!=200){
            if(response->getErrorCode()==404){
                Alert* alert=new Alert();
                alert->setFontSize(30);
                alert->setFontColor(255,255,255);
                alert->setPosition(Screen.MIDDLE);
                alert->show("Connection Error","Not Found");
            }else if((some other different cases)){
                (some other alert)
            }else
                Alert* alert=new Alert();
                alert->setFontSize(30);
                alert->setPosition(Screen.MIDDLE);
                alert->setFontColor(255,255,255);
                alert->show("Connection Error","unknown error");
            }
        }else{
            (other handle methods depend on different URL)
        }
}

コードは長く、一般的に使用されますが、上記のコードはカスタム関数やカスタムクラスなどの特別なものを必要としません(HttpRequestとAlertはどちらもデフォルトでフレームワークによって提供されます)。コードセグメントは長いですが、簡単で複雑ではありません(URL、フォントサイズなどの設定のバンドルがあるため長くなります)、コードセグメントはクラス間でほとんど違いがありません(例:URL、リクエストデータ、エラーコードハンドルケース、通常のハンドルケース...)

私の質問は、コードの依存関係を減らすために関数でラップするのではなく、長くて簡単なコードをコピーして貼り付けることは受け入れられますか?


89
割り当てたオブジェクトを解放しないなど、そのコードにバグがあると想像してください。(フレームワークはAlertオブジェクトを解放しますか?)バグを修正するために、このコードのコピーされたすべてのインスタンスを見つける必要があると想像してください。さて、それをしなければならないのはあなたではなく、そもそもこれらすべてのコピーを作成したのはあなただと知っている狂ったcrazy殺人者だと想像してください。
セバスチャンレッド

8
ところで、ネットワーキングとエラー表示を1か所に混在させることは、すでに大きな問題ではありません。
-sleske

11
いいえ。まったく受け入れられません。私のプロジェクトに参加していた場合、あなたは私のプロジェクトに参加できなくなり、トレーニングプログラムまたはPIPに参加することになります。
nhgrif

10
さらに、スーパーバイザーが「スクリーンの真ん中にあるこの警告ボックスは絶対的な恐怖です。猫のジフを見ています。ポップアップが表示されるたびにポップアップがブロックされています。右上に移動してください。 」3週間後、「あなたは一体何をしましたか?!ポップアップが右上のXを覆っているので、猫のジフを閉じることができなくなりました。修正してください。」
MonkeyZeus

11
ここの誰もがこれは悪い考えだと思うようです。しかし、質問を好転させるために、なぜこのコードを別のクラスまたは関数に入れないのでしょうか?
カールジェルツェン

回答:


87

変更のコストを考慮する必要があります。接続方法を変更したい場合はどうしますか?どれほど簡単でしょうか?多数のコードが重複している場合、変更が必要なすべての場所を見つけるのは非常に時間がかかり、エラーが発生しやすくなります。

また、明確さを考慮する必要があります。おそらく、30行のコードを見なくても、「connectToInternet」関数を1回呼び出すだけで理解するのは簡単ではありません。新しい機能を追加する必要がある場合、コードを理解しようとしてどれくらいの時間が失われますか?

複製が問題にならない特定のまれなケースがあります。たとえば、実験を行っていて、コードが1日の終わりに破棄される場合。しかし、一般に、複製のコストは、コードを別の関数に引き出す必要がないというわずかな時間の節約よりも重要です。

https://softwareengineering.stackexchange.com/a/103235/63172も参照してください。


19
...そして、これらの30行が以前に見た他の行と本当に同じであるか、誰かが何らかの理由で自分のコピーで別のポートまたはIPアドレスに切り替えたかどうかを知っています。「〜で始まる30行程度の行HttpRequestはすべて同じである」という暗黙の仮定は、簡単に誤解されます。
nullの

@nullすばらしい点。私はかつて、データベース接続フックアップがすべてコピーされて貼り付けられていたコードに取り組んでいましたが、一部はセットアップに微妙な違いがありました。これらが重要なのか、意図的な変更なのか、それとも単なるランダムな違いなのか、私には
分かりませんでした

54

いや

実際、「単純な」コードでさえ、小さな部分に分割する必要があります。少なくとも2つ。

1つは接続を確立し、通常の200応答を処理します。たとえば、場合によってはPOSTからPUTに変更するとどうなりますか?これらの接続を無数に作成していて、マルチスレッドまたは接続プールが必要な場合はどうなりますか?メソッドの引数を指定して、コードを1か所に配置すると、これがはるかに簡単になります

同様に、別のエラーを処理します。たとえば、アラートの色またはフォントサイズを変更した場合。または、断続的な接続に問題があり、エラーをログに記録したい場合。



また、SRPを引用できます唯一の目的を持っているコードブロックを持つことは、それはそんなに簡単に理解し、維持することができます...
ローランドTEPP

これは、DRYとSRPが実際に整合する1つのケースです。時々そうではありません。
user949300

18

コピーして貼り付けてもかまいません...

いや

私にとって、決定的な議論はこれです:

...一般的に使用されています...

あなたがコードの一部を使用した場合より、次によりも一つの場所、とき、それは変わる、あなたがする必要が変更複数の場所でそれをか、矛盾を得るために開始- 「奇妙なもの」は(つまり、あなたがバグを導入)に発生し始めます。

それは簡単で複雑ではありません...

それで、関数にリファクタリングするのがもっと簡単になるはずです。

... URL、フォントサイズなどの設定のバンドルがあります...

そして、何のユーザが行う愛する変更するには?フォント、フォントサイズ、色など。

今; 同じ色/フォント/サイズに戻すために、同じコードを何箇所変更する必要がありますか?(推奨される回答:1つのみ)。

...コードセグメントにはクラス間でほとんど違いがありません(例:URL、リクエストデータ、エラーコードハンドルケース、通常のハンドルケース...)

バリエーション=>関数パラメーター。


「そして、ユーザーは何を変更したいのですか?フォント、フォントサイズ、色など」これは非常に対処されています。本当に何十もの場所でそれを変えたいですか?
ダン

8

これは実際にはコピーアンドペーストとは関係ありません。あなたが他の場所からコードを取る場合は、第二に、あなたは、コードを取ることですあなたのコードとあなたの責任なので、それは完全に自分でコピーしたり、書かれているかどうかの違いがありません。

アラートでは、いくつかの設計上の決定を行います。ほとんどの場合、同様の設計上の決定をすべてのアラートに対して行う必要があります。そのため、 "ShowAlertInAStyleSuitableForMyApplication"のどこか、または少し短いメソッドを用意する必要があり、それを呼び出す必要があります。

同様のエラー処理を備えた多くのhttp要求があります。エラー処理を何度も何度も繰り返してはいけませんが、一般的なエラー処理を抽出してください。特に、エラー処理がもう少し複雑になった場合(タイムアウトエラー、401など)。


6

状況によっては複製は問題ありません。しかし、これではありません。その方法は複雑すぎます。メソッドの「ファクタリング」より複製が簡単な場合、下限があります。

例えば:

def add(a, b)
    return a + b
end

愚かです、ただa + bをしてください。

しかし、ほんの少し、ほんの少し複雑になると、通常はその先を行くことになります。

foo.a + foo.b

になるはずです

foo.total
def foo
    ...
    def total
        return self.a + self.b
    end
end

あなたの場合、4つの「メソッド」があります。おそらく異なるクラスで。1つは要求を作成し、1つは応答を取得し、1つはエラーを表示し、応答を処理するために応答が戻った後に呼び出される何らかのコールバックを行います。個人的には、コールを簡単にするために、その上に一種の「ラッパー」を追加する可能性があります。

最後に、Webリクエストを行うには、次のような呼び出しが必要です。

Web.Post(URI, Params, ResponseHandler);

その行は、私がコード全体で持っているものです。それから、「ものの入手方法」に変更を加える必要があるとき、はるかに少ない労力ですぐに変更できました。

これは、コードをDRYに保ち、SRPにも役立ちます。


0

任意のサイズ/複雑さのプロジェクトで、次の目的で必要なときにコードを見つけられるようにしたいと思います。

  1. 壊れたときに修正する
  2. 機能を変更する
  3. 再利用してください。

進行中のプロジェクトに参加するか、数年間プロジェクトに取り組み続け、「インターネットに接続して接続結果を表示する」という新しいリクエストがあったために場所を見つけるのが簡単だったのは素晴らしいことではありませんかhttprequestのコード全体を検索するのではなく、優れた設計ですか?とにかく、Googleで見つける方が簡単でしょう。

心配しないでください、私は新しい人です。このコードブロックをリファクタリングします。この無知なチームにひどいコードベースを参加させることに動揺しているからです。コピーして貼り付けてください。少なくとも、ボスは私の背中から離れます。次に、プロジェクトが本当に災害であると特定されたら、私たちが誰も理解していない最新かつ最高のフレームワークにバージョンをコピーして貼り付けることで、プロジェクトを書き換えることをお勧めします。


0

少なくとも私の意見では、クラスや関数の方が優れています。一度、ファイルを小さくします。これは、Webアプリケーションや、ストレージの少ないデバイス(IoT、古い携帯電話など)のアプリケーションを扱う場合、非常に大きな利益になります。

そして明らかに、最良のポイントは、新しいプロトコルなどのために変更するものがある場合、関数の内容を変更するだけであり、この関数を別のファイルにある場所に配置すると、検索して変更します。

PHPでMySQLからMySQLiに切り替えることができるように、SQLインタープリター全体を作成しました。インタープリターを変更するだけで、すべてが正常に機能するためです。


-1

2回呼び出される関数にコードを複製するか移動するかを決定するには、どちらがより可能性が高いかを判断してください。

  1. 同じ方法で両方のコードの使用を変更する必要があります。

  2. それらが異なるように、コードの少なくとも1つの使用を変更する必要があります。

前者の場合、1つの関数で両方の使用法を処理する方が適切です。後者の場合、2つの使用法に対して別々のコードを使用する方が良いでしょう。

一度使用するコードをインラインで記述するか、別の関数に引き出すかを決定する際に、関数に必要な動作を完全に記述する方法を見つけます。関数の必要な動作の完全かつ正確な説明がコード自体と同じかそれより長い場合、コードを別の関数に移動すると、物事が理解しにくくなり、理解しにくくなります。2番目の呼び出し元が同じ関数を使用する可能性が高く、関数への今後の変更が両方の呼び出し元に影響する必要がある可能性が高い場合でも、実行する価値があるかもしれませんが、そのような考慮がない場合、読みやすさは分割を優先しますコードとその必要な動作の説明がほぼ同じ長さになるレベルまで。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.