定型文の防御?


14

私にとって、定型的なコードは明らかに悪いです。しかし、ボイラープレートを減らすために抵抗を示す開発者に会いました。私は、私が長年にわたってそれに対して開発した嫌悪感を超えて、すぐに形成された、よく考えられた議論を持っていなかったことに気付きました。

定型文を少なくするという説得力のある議論を形成できるように、いくつかの反論は何ですか?言い換えれば、ボイラープレートを支持する議論(もしあれば)は何ですか?

(私は一般的に定型語が意味すると思うものを意味しますが、良い例はJavaのゲッターとセッターです。)


7
重複コードに対する引数(ボイラープレートがコピー/貼り付けされていると仮定):stackoverflow.com/a/2490897/1583
Oded

1
@Oded:そうです。しかし、あなたは質問を誤解しています。:)彼は定型コードについて何か言いたいことがあるかどうか調べようとしています。私の推測では、彼は不利な点について非常によく知っています。
スティーブンジュリス

3
@StevenJeuris-私は質問を完璧に読みました。それが私が答えを投稿しなかった理由です。私は議論の反対側に追加するだけです。ちょうどそのように、OPは「次回に向けて開発した嫌悪感を乗り越えて、すぐに形成されたよく考えられた議論」を;)
Oded

2
定型文は審美的に喜ぶことができます:en.wikipedia.org/wiki/This_Is_the_House_That_Jack_Built
SK-logic

互いに補完するいくつかの良い答えとコメント...受け入れるものを選ぶのは難しいです。
抽象化

回答:


15

覚えておくべき重要なことの1つは、不必要なコンテキストを削除することにより、コードが一般的に小さくなることです。 コンパイラーが何かを理解できる場合、引数は行く、それを明示的に記述する必要はありません。

コンパイラーだけがそれを読むことを意図していた場合、それは素晴らしいことです。しかし、「プログラムは人々が読むために、そして偶然にマシンが実行するためだけに書かれるべきである」ことを忘れないでください。(皮肉なことに、この引用はその過度の簡潔さの大部分が原因で、普通の人間が読むのが最も難しい言語の1つに特化した教科書からています。)

あなたがそれを書いているときに退屈で反復的な定型句のように見えるかもしれないものは、1年後(または5年)来てあなたのコードを維持しなければならない誰かにとって貴重なコンテキストになります。

それは短いの両方何かに置き換えることができるので、WRTは、Javaの例具体的には、私は、悪い定型の良い例だということを同意するだろうし、プロパティ:読みやすく、また、より柔軟な。しかし、それは、すべての言語のすべての定型的な構文要素が、JavaおよびC ++のゲッターおよびセッターと同じくらい無駄であることを意味しません。


7
もちろん、この議論は両方の方法で機能します。かなりの量のボイラープレートコードがコンパイラをなだめるためにあり、人間が理解するのを助けませ。 、プロパティごとに単一の短い行を読むのではなく、単にそれがプロパティであり、どのタイプを持っているかを示します。

6
ボイラープレートは、人間の読者にとっても有害だと思います。繰り返しのある無意味なテキストを強制的に書くことで、他の人からコードの関連部分を隠しています。何かが役立つ場合、定義上、定型ではありません。
アンドレスF.

1
@Giorgio:それどころか、それは私の意見以上のものです。それを研究しようとした人の大多数の意見です。そして、そもそも「読みにくい」が本質的に意見の問題である場合、その意見が非常に広く共有されているという事実は事実になります。
メイソンウィーラー14

1
@Mason Wheeler:プログラミング言語に対する人々の認識は、多くの場合、過去の経験に影響されます。Schemeでプログラムすることを学んだ人は、CまたはPascalが不器用で読みにくいと感じます。一方、大多数の人々は主流の言語でプログラムすることを学びました。
ジョルジオ14

2
私はより多くのコンテキストが人間が持っている唯一の手段が起こってすべてのものの大きな精神的なマップを維持するという決まり文句を除去することにより、プログラマから隠されている意見だ舞台裏で目に見えない そしてそれは、それがに来るとき大きな不利益でありますオーサリング時に少し視覚的なスペースを節約するよりもデバッグします。
パトリックヒューズ

7

定型コードを支持する1つの論点は、1か所でコードを変更しても、コードの1つのフローにしか影響しないということです。これは、多くの場合よりも、実際に変更を使用するコードのすべての部分に影響を与える必要があるという事実とのバランスを取る必要があります。しかし、私は議論をサポートするまれな例を見てきました。

あなたが言うコードの部分があるとしましょう

public ForTheBar(Foo foo)
{
    Bar bar = foo.bar();
    return bar.BeFooed();
}

これは、コードの約2箇所で使用されます。

ある日、誰かがやって来て、「OK、この道だけで、Fooingする前にバーをGrommitしてほしい」と言います。

そして、あなたは「まあこれは簡単だ」と思う。

public ForTheBar(Foo foo, bool shouldIGrommit)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    return bar.BeFooed();
}

その後、ユーザーはいくつかの新しい機能を追加し、FooTheBarにうまく適合すると考えています。そして、あなたはそれをFooする前にそのバーをグロミットするべきかどうかを彼らに忠実に尋ねると、彼らは「今回は違う」と言います。

したがって、上記のメソッドを呼び出すだけです。

しかし、ユーザーは「OK、待ってください。3番目のケースでは、BeFooedを呼び出す前にバーを落書きしてほしい」と言います。

問題ありません、私はそれができると思います。

public ForTheBar(Foo foo, bool shouldIGrommit, bool shouldIDoodle)
{
    Bar bar = foo.bar();

    if (shouldIGrommit)
    {
        bar.BeGrommitted();
    }

    if (shouldIDoodle)
    {
        bar.BeDoodled();
    }

    return bar.BeFooed();
}

突然、コードが定型化されなくなります。おそらく、繰り返される2行のコードを受け入れる必要があります。今では、2〜3行のコードが3つあり、これ以上繰り返されることはありません。

これはすべて、「これは一般的なケースではありませんが、発生した場合はリファクタリングできます」と反論します。

最近聞いたもう1つの議論は、定型コードがコードのナビゲートに役立つことがあるということです。私たちが議論していた例は、大量のボイラープレートマッピングコードを削除し、AutoMapperに置き換えた場所でした。さて、すべてが規約に基づいているため、IDEに「このプロパティはどこにあるのか」と言うことはできず、それを知っていると期待することはできません。

IoCコンテナについても同様のことを議論する人がいます。

私は彼らに同意するとは言いませんが、それでも公正な議論です。


2
私はあなたの答えの2番目の部分を好みました。; p +1
スティーブンジュリス

私の例があなたのものに非常に似ていることを理解してください...それが常識ではないにしても、かなり起こるように思われます:)
kritzikratzi

6

効率の進化

あなたはこれから始めます:

<p>
    <label for="field">My field</label>
    <input type="text" id="field">
</p>

面倒なボイラープレートをすべて取り除き、関数に追加します。

  1. createFieldHtml( id, label )

    これはいいです、私は非常に多くの行を節約しています!

  2. createFieldHtml( id, label, defaultValue )

    はい、デフォルト値も必要です。簡単に追加できました。

  3. createFieldHtml( id, label, defaultValue, type )

    かっこいい、今はチェックボックスにも使える

  4. createFieldHtml( id, label, defaultValue, type, labelFirst )

    UXデザイナーは、ラベルはチェックボックスの後に配置する必要があると言いました。

  5. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate )

    必要に応じて日付ピッカーをレンダリングするようになりました。うーん、パラメータが少し手に負えなくなってきています

  6. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses )

    CSSクラスを追加する必要があるこの1つのケースがありました

  7. createFieldHtml( id, label, defaultValue, type, labelFirst, isDate, containerCssClasses, fieldCssClasses, disabled, clearAfter, helpText, uploadPath )

    aaaaaaaaaaaaaaaaaaaaa

定型文を守るために

これを言葉で表現するのは大変です。最近気づいたことなので、リストを作成します。

  1. 重複した線が少し伸びるのではないかという不安があるように思えます。数行だけであれば、まったく問題ないかもしれません。いくつかのことは本質的に「ほとんど繰り返し」です(上の例のように)。長期的には最適化の機会はほとんどありません。
  2. 人々は機能をどこかにカプセル化するのが大好きです。客観的に見て、それが単なる「混乱を隠している」ように思えるなら、疑ってください!それはいくつかの古き良き定型句の時間かもしれません
  3. ますます強力になる機能がある場合。それは入力に応じて多くの異なる実行パスを取り、最終的にはほとんど何もしません-それは定型的な時間かもしれません!
  4. 抽象化の別のレイヤーの上に抽象化のレイヤーを追加するが、コードを短くするだけの場合(基礎となるレイヤーは変更するためのものではありません)-定型時間!
  5. 非常に多くのパラメーターを受け取る関数がある場合、名前付きパラメーターが本当に必要です-多分定型的な時間でしょう。

最近私がいつも自問していることの1つは、
何も変更せずに別のプロジェクトにコピー&ペーストできるかということです。はいの場合、ライブラリにカプセル化または配置しても構いません。いいえの場合、定型的な時間です。

これは、ボイラープレートがコードのコピー&ペーストであるという一般的な認識に大きく反対しています。私にとって定型文はコピー&ペーストについてですが、常に微調整する必要があります。


更新:実際の名前の上に私の例を挙げている記事に出会ったばかりです: "too DRY anti-pattern"。

この関数はより多くのパラメーターを取得し、さまざまなケースでその動作を制御する内部ロジックがますます複雑になっています。あまりにも乾燥した機能を見つけるのは簡単です。多種多様な使用法に対処しようとする複雑なif-thenロジックがたくさんあります。[...]また、コードが小さく、離散関数を実行する場合、コードを繰り返すことは必ずしも悪いことではありません。

短く興味深い記事です。次の記事を参照してください:Too Dry Anti-Pattern


1
「抽象化の別のレイヤーの上に抽象化のレイヤーを追加するが、コードを短くするためだけに」 Trueの場合、再利用の可能性がある場合にのみ抽象化のレイヤーを追加する必要があります。
スティーブンジュリス

4
+1。自分自身を繰り返さないでください。しかし、自分自身をほとんど繰り返さないようにするために、厄介な長さにしないでください。
ジュリアヘイワード14

4

定型コードを deしていますが、定型コードを削除できるからといって、それが最善の方法であるとは限りません。

WPFフレームワークには、非常識な量の定型コードを含む依存関係プロパティがあります。暇なときに、書く必要のあるコードの量を大幅に減らすソリューションを調査しました。1年以上後、私はまだこのソリューションを改善しており、その機能を拡張するか、バグを修正する必要があります。

何が問題ですか?これは、新しいことを学び、代替ソリューションを検討するのに最適ですが、おそらく最良の商業的決定ではありません。

WPFフレームワークは十分に文書化されています。それは適切にあなたの定型的なコードを書く方法を説明します。この定型コードを削除しようとするのは良い練習であり、間違いなく探索する価値がありますが、msdnが提供するのと同じレベルの「ポリッシュ」を達成するには長い時間がかかります。


ただし、現時点での結果にはまだ満足しており、空き時間のプロジェクトで喜んで使用しています。:)
スティーブンジュリス

3
WPFとそれらの依存関係プロパティに触れるたびに、C#がC ++のマクロと同じくらい単純なものを持っていることを常に望んでいます。確かにマクロは間違った手で悪用されますが、ここでの繰り返しを大幅に排除できます。次回それらのマクロを希望するようになったときに、AOPフレームワークを確認する必要があります:)
DXM

@DXMを実行し、それがひどくクラッシュした場合、私を責めてエラーを投稿することを忘れないでください。; p
スティーブンジュリス

コードスニペットは、依存関係プロパティに対して非常にうまく機能しました。
コーディズム

@Codism:まあ、彼らがあるソリューション、私は軽蔑あまりにもそれらを。:)
スティーブンジュリス

1

ボイラープレートの問題は、DRYに違反することです。基本的に、ボイラープレートを記述するとき、同じコード(または非常に類似したコード)をいくつかのクラスにわたって繰り返します。そのコードを変更する必要がある場合、開発者がコードが繰り返されたすべての場所を覚えているかどうかはまったくわかりません。これは、古いAPIまたは古いメソッドが使用されるバグにつながります。

ボイラープレートを共通ライブラリーまたは親クラスにリファクタリングする場合、APIが変更されたときにコードを1か所で変更するだけで済みます。さらに重要なことは、予期しない変更が発生すると、コードが1か所で破損し、すべてを再び機能させるために修正する必要があるものを正確に知ることができることです。これは、1つの変更で数十、または数百のクラスで障害が発生するシナリオよりもはるかに望ましい方法です。


2
これはボイラープレートを支持する議論ですか?
クリスウェセリング

0

私は別のタクトを取ります。開発の一貫性は、ソフトウェア設計の最も重要な機能の1つです。アプリケーションの拡張性と保守性を高めるための重要なツールですが、複数のサイト、言語、タイムゾーンにまたがってチームを管理する場合は達成が困難です。

達成された場合、一貫性により、「一度見たら、すべて見た」コードにアクセスしやすくなり、保守やリファクタリングがはるかに安くなりますが、何よりも拡張がはるかに容易になります。定型文を必要とするライブラリを作成するとき、ライブラリのパワーとともに、開発者にも提供します。

  • 開始点は、機能の前文(定型文)を理解し、ほとんどの主要なクラスとアクセスポイントは通常、定型文の一部として機能します。これにより、開発者はドキュメントの出発点になります
  • 期待はセットアッププリアンブルの一部としてトレースオブジェクトは、その後、開発者は、例外や情報をログに記録する場所を知っている場合は、開発者のあなたの配置は、例えば、明らかになるだろう
  • 開発者にクラスをインスタンス化するプロセスを強制する際の暗黙的な理解により、ライブラリの残りの部分にアクセスするために必要な技術を推測し、ライブラリ全体で使用した規則を紹介する機会を得ることができます
  • 定型コードが必要な場合の簡単な検証通常、例外とガード句を使用して自分自身を非常に簡単に検証できるため、すでに障害のあるプロセスにコミットしているときに消費者が行の途中で立ち往生するのを防ぐことができます
  • ボイラープレートコードを必要とするライブラリの構成は、単一の実行パスの機能をカスタマイズするための明らかな実装ポイントが既にあるため、簡単です。これは、必要な定型コードがFactoryまたはCommandパターンで拡張されている場合に特に便利です

ライブラリの消費者がインスタンス化を把握している場合、プライベート/拡張メソッド、親クラス、またはテンプレートさえも簡単に作成して、定型コードを実装できます。


-3

定型コードの唯一の本当の問題は、バグを見つけた場合、再利用した場所ではなく、使用したすべての場所を修正する必要があることです。

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