web-dev-qa-db-ja.com

クラスまたは関数にラップするのではなく、長くて単純なコードをコピーして貼り付けることはできますか?

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

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、要求データ、エラーコードハンドルケース、通常のハンドル)ケース...)

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

29
ggrr

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

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

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

参照 https://softwareengineering.stackexchange.com/a/103235/63172

87
Vaughn Cato

番号。

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

1つは接続を作成し、通常の200応答を処理します。たとえば、POSTからPUTに変更する場合がありますか?これらの接続を何十億も作成していて、マルチスレッドまたは接続プーリングが必要な場合はどうでしょうか?コードをメソッドの引数を持つ1つの場所がこれをはるかに簡単にします

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

54
user949300

コピーして貼り付けてもいいですか...

番号。

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

...それは一般的に使用されます...

moreで1か所以上のコードを使用する場合、when変更された場合、change複数の場所で変更する必要があるか、不整合が生じ始めます-「奇妙なこと」が発生し始めます(つまり、導入します)バグ)。

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

そして、そうすることで、関数にリファクタリングしやすくなります。

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

そして、ユーザーは何を変更しますか?フォント、フォントサイズ、色など.

今;それらをすべて同じ色/フォント/サイズにするために、同じコードをいくつ変更する必要がありますか? (推奨される回答:ただone)。

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

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

18
Phill W.

これは実際にはコピーアンドペーストとは関係ありません。他の場所からコードを取得する場合、2番目にコードを取得するのはyourコードとyourの責任であるため、自分でコピーしたか完全に記述したかは違いを生じさせません。 。

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

同様のエラー処理を伴う多数のhttpリクエストがあります。エラー処理を何度も複製するのではなく、一般的なエラー処理を抽出する必要があります。特に、エラー処理がもう少し複雑になった場合(タイムアウトエラー、401などはどうでしょうか)。

8
gnasher729

複製は、状況によっては問題ありません。しかし、これではありません。その方法は複雑すぎます。複製がメソッドを「除外する」よりも簡単な場合には、下限があります。

例えば:

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 [〜#〜] に役立ちます。

6
coteyr

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

そして明らかに最良の点は、新しいプロトコルなどのために何か変更する必要がある場合は、関数の内容を変更するだけであり、この関数を別のファイルにある可能性がある場所に何度も置くと、さらに困難になります見つけて変える。

私はSQLインタプリタ全体を作成したので、MySQLからPHPで MySQLi に切り替えることができます。これは、インタプリタを変更する必要があるため、すべてが機能しているためです。ただし、これは極端な例です。

0
My1

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

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

進行中のプロジェクトに参加するか、数年間プロジェクトに取り組み続けること、そして「インターネットに接続して接続結果を表示する」という新しいリクエストが、 httprequestのコード全体で検索を行うのではなく、優れた設計ですか?とにかく、Googleを使用するほうが簡単です。

心配する必要はありません。私はこのコードブロックをリファクタリングします。私はこの無知なチームにひどいコードベースを追加することに非常に動揺しているか、または残りの人と同じように多くのプレッシャーを受けています。コピーして貼り付けるだけです。少なくともそれは上司を私の背中から遠ざけるでしょう。次に、プロジェクトが本当に災害であると識別されたとき、私は誰もが理解できない最新かつ最高のフレームワークでバージョンをコピーして貼り付けることで、プロジェクトを書き直すことをお勧めします。

0
JeffO