あなたが遭遇した最悪のアンチパターン[クローズド]


9

プログラマーとしてのキャリアで出会った最悪のアンチパターンは何ですか?

私はJavaにほとんど関わっていますが、おそらく言語に依存していません。

最悪なのは、メインのアンチパターンと呼んでいるものだと思います。これは、すべてのロジックを含む単一の非常に大きなクラス(場合によっては、一対の小さなクラスを伴う)で構成されるプログラムを意味します。通常、すべてのビジネスロジックが含まれる大きなループがあり、時には数万行のコードが含まれます。

回答:


38

コードをコメント化。そのブロック、おそらく数百行。理論的には、コメント化されていますが、害はありません。将来必要になるかもしれません。


7
少なくとも、安全に削除できます。私が一緒に働いた誰かとは異なり、それは頻繁にプロシージャの名前を変更し、死んだコードにアクセス可能なままにします。ブレッヒ。
ジェイ

@シレナ、あなたもエリックと一緒に働いた?!?
CaffGeek、2011

#ifdef COMMENTを使用してロックアウトしたコードがたくさんありました。誰かがコメントを定義するまではうまくいきました。
マイケルコーン

9
これは、バージョン管理を使用することで成果が得られるもう1つのケースです。数回のキーストロークで再度取得できるため、コードが将来必要になるかどうかを尋ねることなくコードを削除できます。
Jason B

5
コメントアウトされたコードには、その理由を説明するコメントをプレフィックスとして付ければ、場所があると思います。時々、私が考えていた可能性のある道路を表すコメント付きブロックを残し、なぜそうしなかったかについてのコメントを残します。@ジェイソン、私は間違いなくこれがバージョン管理の役割だと聞いていますが、バージョン管理で削除されたコードはあまり発見できません。
nlawalker、2011

19

「コピーパスタ」でもう一つの当たり前のものを叩きます。必要なものとほぼ同じコードをコピーしてから、いくつかの点を変更します(メソッドに抽出するのではなく)。

これは特に、90年代後半の一部の機能テストコードとAPIテストコードでよく見られます。文字通り数百(または数千)のほぼ同一のテストケースであり、3つまたは4つのパラメーターを取るいくつかの関数に分解できた可能性があります。 、データ駆動型の何か。私が大学を卒業した最初の仕事は、文字通り8か月間、廃止された方法を使用していた何千行ものコピーパスタを書き直し、リファクタリングすることでした。テストが完了するまでに、テストファイルは元のサイズの10分の1未満であり、はるかに保守しやすい(そして読みやすい!)ものでした。


16

私はパターンマニアともっと少ない労力で解決できる解決策についてたくさん書くことができると思いますが、私は最近読んだ素晴らしい記事を指摘したいと思います。単純な解決策が複雑すぎる可能性があるという素晴らしい例を挙げたいと思います。 。

JavaでFactorialを記述する方法(そうでない場合)を使用して、アルゴリズムにファクトリを配置します


3
驚くばかり!FactorialWebServiceはどこにありますか?:P
FrustratedWithFormsDesigner

1
私はそれをパターンフィーバーと呼んでいます... 私たちの間でより良いものはそれを超えて成長します。私はインタビューをして、パターンについていつ考えるべきか男が尋ねました。私はそれらをシステムに進化させたと彼に話しました。「いいえ、最初からパターンを使用する必要があります。」
Michael Brown、

FactoryFactoriesは、実際の選択を可能な限り延期したい症状にすぎませんが、それでも、ハードコーディングするか、外部ストリング値をコードの一部にマッピングすることになります。Dependency Injectionはより良いソリューションです。

パターンは優れたデザインのアーティファクトです-それらはそのように扱う必要があります。私はそれらをソリューションではなく定義として説明するのが好きです。コミュニケーションの際に役立ちますが、必ずしも設計には役立ちません。
マイケルK

そのため、ありがとうございます。
Syg


14

地域

C#では、IDEで折りたたむことができるコードの領域を定義して、そのコードを処理する必要がない限り非表示にすることができます。私は(現在は)数百行にまたがるプロジェクト(私は誇張していると思います)に参加しており、千行関数に複数の領域がありました(ここでも冗談ですが)。

利点として、リージョンを作成した開発者は、リージョン内の特定の機能を識別するのに非常に良い仕事をしました。地域で抽出メソッドを実行して次に進むことができたほどです。

リージョンは、開発者ががらくたを一目で「隠す」ことを奨励します。


15
リージョンの+1により、開発者はがらくたを目に見えないように「隠す」ことができます。ただし、適切に使用すると、リージョンはコードを論理的にグループ化し、後で簡単に見つけるのに役立ちます。
ダレンヤング

これは長い間、折りたたみエディタの問題でした。OCCAMで最後にプログラムしたときも、同じようなことをしていました。
マイケルコーン

2
私は地域が大好きです...しかし、組織のためだけです...コードのデジタル領域を隠さないでください。
IAbstract

3
+1。これは、リージョンの使用がStyleCopルールSA1124に違反する理由でもありDoNotUseRegionsます。
Arseni Mourzenko

1
SQLの膨大な数のフィールドを処理するプロジェクトがあり、それを更新/作成するコードは多くの行です。リージョン#region SQL Updateはそれを折りたたみ可能にするので、必要なスクロールは少なくなります。
JYelton、2011


9

メソッドをオーバーロードしない:

// Do something
public int doSomething(Data d);

// Do same thing, but with some other data
public int doSomething2(SomeOtherData d);

プログラマーがオーバーロードを理解していなかったことを明らかに示しています。



5

ソフトコーディング、つまりプログラマーがハードコーディングを回避するために邪魔をして、最終的にはスケールの反対側、つまり「ハードコーディングされた」依存関係になる場合。


4

クライアントで状態を保持します。

以前は、すべての状態がブラウザーに保持されていたWebアプリケーションで作業しました。(トラブルのないスケーラビリティを確保するために、すべての例外が無視されました)。


詳しく説明してもらえますか?Imho、Webアプリケーションの場合、唯一の状態がブラウザー(つまりCookie)にあり、サーバーが「何も共有されていない」場合は問題ありません。それとも「アプリケーションデータベース」のように「状態」を意味しますか?
ケプラ2011

状態:操作対象の実際のデータと同様。

OOあなたは私の深い同情を持っています。
ケプラ2011

4

大規模なチェックイン

開発者が1週間以上チェックインを行っていないのを見ると嫌いです。それは、彼が行き詰まって助けを求めていないか、または一連の機能を1つの大きなチェックインにまとめていることを意味します。(私は最悪のケースのシナリオを省略しました、彼は何もしていないだけです。それは簡単に解決されます... 2つの単語はあなたが雇われているように聞こえます。)

大きなチェックインを行っている場合、変更セットを特定の機能にリンクできるなど、SCMの多くの利点が失われます。また、多くのマージが必要になる可能性があり、それを正しく行うのは必ずしも容易ではありません。


1
何もしないことが必ずしも最悪のシナリオではありません。コードを書き直すよりも、ゼロから記述した方がよい場合があります...
マラキ

4

現在、私はレガシーコードの一部を扱っており、以前のコーダーがリストの最初の要素を取得する方法が気に入っています。

String result;
for(int i = 0; i < someList.size(); i++) {
    result = someList.get(i);
    break;
}

しかし、このコードで私が見た中で最悪なのは、クラスをインラインJSPページを定義し、スクリプトレットとout.printlnを使用してすべてのHTML、CSS、JavaScriptを記述することです:-(


4

私が目にした中で最悪の行動アンチパターンの1つは、本番稼働後のバージョン管理にのみコードをチェックインできるショップでした。これは、VSSでの排他的なチェックアウトと相まって、次のリリースの前にプロダクションの欠陥を修正する必要がある場合はチェックアウトを取り消す複雑なプロセスにつながりました。

これが部門のポリシーであったという事実は、このように振る舞う単一の開発者の場合よりもさらに悪化しました。


3

文字列リテラルのロック

synchronized("one") { /* block one A*/ }

synchronized("one") { /* block one B*/ }

非常に長いクラス名。(JRE内)

com.sun.java.swing.plaf.nimbus.
InternalFrameInternalFrameTitlePaneInternalFrameTitlePaneMaximizeButtonWindowNotFocusedState

貧弱な継承構造

com.sun.corba.se.internal.Interceptors.PIORB extends
com.sun.corba.se.internal.POA.POAORB extends
com.sun.corba.se.internal.iiop.ORB extends
com.sun.corba.se.impl.orb.ORBImpl extends
com.sun.corba.se.spi.orb.ORB extends
com.sun.corba.se.org.omg.CORBA.ORB extends 
org.omg.CORBA_2_3.ORB extends
org.omg.CORBA.ORB

ない例外。

public interface FlavorException { }

無意味で不可解なエラー処理

if (properties.size() > 10000)
   System.exit(0);

オブジェクトの不要な作成

Class clazz = new Integer(0).getClass();
int num = new Integer(text).intValue();

他の目的で例外をスローする

try {
    Integer i = null;
    Integer j = i.intValue();
} catch (NullPointerException e) {
    System.out.println("Entering "+e.getStackTrace()[0]);
}

静的メソッドのインスタンスオブジェクトの使用。

Thread.currentThread().sleep(100);

非最終フィールドでの同期

synchronized(list) {
   list = new ArrayList();
}

定数文字列の無意味なコピー

String s = new String("Hello world");

String.toString()への無意味な呼び出し

String s = "Hello";
String t = s.toString() + " World";

System.gc()を呼び出してメモリを解放する

ローカル変数をnullに設定してメモリを解放する

    // list is out of scope anyway.
    list = null;
}

パフォーマンス上の理由(またはその他のマイクロマイクロ最適化)のためにi ++の代わりに++ iを使用する


これらは必ずしもアンチパターンではなく、単に悪いコーディングです。
ゲイリーウィロビー

@ゲイリー、または私が繰り返し見る開発の貧弱なパターン。おそらく、アンチパターンの厳密な定義の範囲外です。
Peter Lawrey、2011

1
@Peter:「System.gc()を呼び出してメモリを解放する」と、GCが明示的に呼び出されない限り、.NETがOutOfMemory例外で爆発することがありました。もちろん、それは規則というよりむしろ例外でした。
Coder、2011

3

コードが散りばめられた:

// TODO: 

または

// TODO: implement feature 

追加情報なし。


2

ダミーのイテレータ:

Iterator iCollection = collection.iterator();
for(int i = 0 ; i < collection.size() ; i++ ){
    if(collection.get(i) == something){
       iCollection.remove();
    }
 }

シングルトノファクトリー:

public class SomeObject{
   private SomeObject() {}
   public static SomeObject getInstance(){
       return new SomeObject();
   }
}

if-else駆動の開発(オープンクローズの原則とも呼ばれます-理解のために変更のためにオープン):

if (sth1){
...  
}else if(sth2){
..
}
...
..
else if(sth1000000000000){
...
}

StringPattern(StringObjectとも呼ばれます):

a) sendercode
if(sth1)
   str+="#a";
if(sth2)
   str+="#b";
...
if(sth1000)
   str+="#n";

b) receiver
   regexp testing if str contains #a, #b, ... #n

しかし、それelse ifは多くの場合、物事を成し遂げる唯一の方法です。文字列について考えています。スイッチは使用できません。それが有用であるためには、条件は同じである必要があります。
マイケルK

IMHOそれぞれのif / elseは、単純なマッピングまたはビジターパターンに置き換えることができます。文字列の場合、たとえば次のようなプロパティファイルがあるとします。someString1 = some.package.ObjectToHandleSomeString1
Marcin Michalski

2
シングルトン工場です。そのコードには何も問題はありません。間違っている可能性がある唯一のことは、外部コードがすべての呼び出しgetInstanceが同じインスタンスを返すことを前提としていることです。そのような仮定はカプセル化を壊し、実際には最も一般的なアンチパターンの1つです。
back2dos 2011

exaclyそれは、メソッドが(作成と呼ばれていた場合、それはそう:)混乱さ)、または、それがたびに、すべてが完璧に大丈夫だと思う非常に同じインスタンスを返す理由です
マルチンMichalski

2

これはコーディングパターンではなく、動作パターンです。ただし、コードで何かを変更し(要件が変更されたとしましょう)、コードがそれを通過するまですべての単体テストを微調整します。テストメソッドからすべてのテストコードを微調整または単に削除し、メソッドはそのままにします。

ただし、これはより一般的なものであるザット・ドゥ・ パターンにリンクされています。これがその代表的なコード行です。

int num = new Integer( stringParam ).parseInt( stringParam );

結局、それは機能します。


2

抽象化の逆転、または高レベルのプリミティブの上に低レベルのプリミティブを再発明することは絶対に嫌いです。しかし、時々、これは悪いプログラマーではなく、悪い言語デザイナーによって引き起こされます。例:

  1. 関数ポインターの代わりに、メンバー変数のない単一のメソッドクラスと対応するインターフェイス(関数ポインターのテーブルに関して実装)を使用します。Javaのような言語では、選択の余地がないことに注意してください。

  2. MATLABおよびRでは、すべてがプリミティブではなくベクトル/マトリックスであるという主張。

  3. MATLABをbashしている間、整数がないというのはどうでしょうか。したがって、整数が必要な場合はdoubleを使用する必要があります。

  4. ループを記述するために関数呼び出しを使用する必要がある純粋な関数型言語。


1

それは間違いなくコピー/貼り付けでしょう、それのために多くの悪いコードが行われるのを見てきました、それとカウボーイコーディングとそれに由来するすべてのもの。(神のクラス、特大のメソッド、悪い考えのアルゴリズムなど)

そして、設計パターンが許可されている場合、それらは次のようになります。設計やドメイン分析を行わずに、計画からのアクションのセットとしてプロジェクトを実行します。


1

多目的Java Bean-

いくつかの異なる種類の操作で使用される、多くの変数を持つJava Bean。各操作は、Bean変数の任意のサブセットを使用し、その他は無視します。GUI状態のいくつかの変数、コンポーネント間で受け渡すためにスローされるいくつかの変数、おそらくもう使用されていないいくつかの変数。最良の例には、パターンの評価を妨げるドキュメントがありません。

また、最愛の人を忘れることはできません

try{ 
   ... //many lines of likely dangerous operations
}
catch(Exception e){}

私見、例外臭い。それらは正しいものにするのが難しすぎ、誤った安心感を与えます。
Coder

例外の悪臭についてのあなたの意見が何であれ、静かに飲み込むことはもっと悪臭を放つ必要があります。
Steve B.

1

以前の同僚は、単に新しいオブジェクトを作成するのではなく、オブジェクトのプロパティを上書きしてオブジェクトを再利用する習慣がありました。新しい機能を実装するときにこれが引き起こす問題の量を想像することはできませんでした。


1

私に多くの悲しみを引き起こしたのは、「空の大きな地図」パターンです。適切なオブジェクトを使用する代わりにマップを投げる。デバッグを行わないと、どのような「変数」が含まれているかがわかりません。また、コードを逆にトレースしないと、何が含まれているかもわかりません。通常、文字列をオブジェクトに、または文字列を文字列にマッピングします。これらは、プリミティブに解析される可能性があります。


ASP.NETのSessionとViewStateに依存してページ間でデータのまとまりを渡すようなもののように聞こえますが、これは悲しいことにしばしば要求されます...
Wayne Molina

1

私のお気に入りの開発アンチパターンの1つは、プログラムで 1つ以上のテーブルに追加の列を継続的に追加する必要があるデータベースの「設計」の使用です。これは、エンティティのインスタンスごとに新しいテーブルを作成する「デザイン」のいとこです。どちらも必然的にデータベースサーバーの制限に影響を与えますが、通常、システムがかなり長い間本稼働状態になるまではそうではありません。


0

私が見た中で最悪のアンチパターンの1つは、コンピューターのメモリを使用する代わりに、データベーステーブルを一時ストレージとして使用することです。

問題ドメインは独自のものであり、説明することはできませんが、基本的な問題を理解する必要はありません。これは、バックエンドデータベースを備えたJavaで記述されたGUIアプリケーションでした。特定の入力データを取得して操作し、処理されたデータをデータベースにコミットすることでした。

私たちのプロジェクトには、後で処理するために中間値を保存するかなり複雑なアルゴリズムがあります。一時オブジェクトを...オブジェクトにカプセル化する代わりに、データベーステーブルを「t_object」のように作成しました。値が計算されるたびに、このテーブルに追加されました。アルゴリズムが機能を終えると、すべての中間値が選択され、1つの大きなMapオブジェクトですべて処理されます。すべての処理が完了すると、保存するようにマークされた残りの値が実際のデータベーススキーマに追加され、「t_object」テーブルの一時エントリが破棄されます。

テーブルは一意のリストのようにも使用され、データは一度しか存在できませんでした。テーブルに制約を実装した場合、これは設計の適切な機能だったかもしれませんが、データが存在するかどうかを確認するためにテーブル全体を繰り返し処理することになりました。(いいえ、CONTAINSでwhere句を使用するクエリを使用していませんでした)

この設計が原因で発生した問題のいくつかは、具体的にはデバッグに関するものでした。アプリケーションはデータをパイプライン処理するように構築されているため、このアルゴリズムに到達する前にデータを前処理する複数のGUIがあります。デバッグプロセスは、テストケースを処理し、上記のセクションを完了した直後に一時停止することでした。次に、データベースにクエリを実行して、このテーブルに含まれているデータを確認します。

私たちが発見した別の問題は、データがこの一時テーブルから適切に削除されておらず、将来の実行に干渉することでした。これは、例外が適切に処理されていないため、アプリケーションが適切に終了せず、制御対象のテーブルのデータを削除していないことが原因であることがわかりました。

基本的なオブジェクト指向設計を使用し、すべてをメモリに保持していた場合、上記の問題は発生しませんでした。まず、アプリケーションにブレークポイントを簡単に設定し、スタックとヒープのメモリを検査できるため、デバッグは簡単でした。次に、アプリケーションからの異常終了時に、Javaメモリがデータベースから削除されることを心配することなく、自然にクリーンアップされます。

注:このパターンが本質的に悪いと言っているのではありませんが、この例では、基本的なOOの原則で十分である場合は不要であることがわかりました。

このアンチパターンの名前がわからないのは、このようなことをしたのが初めてだからです。皆さんがこのパターンについて考えることができる良い名前はありますか?


私はこれを全面的な問題とは呼びません。保存される一時データの量と、それを使用して何が行われるかによって異なります。
GrandmasterB、2011

私は投稿にさらに追加する必要がありますが、主な問題は、オブジェクトを変更してメモリからデータにアクセスする代わりに、データがハックSQLコードで操作されることでした。これにより、複雑さが増し、パフォーマンスの問題が深刻化しました。
jluzwick

2
問題のドメインについては言及しませんが、必ずしも悪いことではありません。このように他の場所で状態を維持すると、プロセスをスケーリングし、長時間の実行中にイントロスペクトでき、デバッグにも役立ちます。DBアクセスにより、パフォーマンスの問題や懸念が生じましたか?
–JéQueue、2011

これがプロジェクトでどのように使用されているかをよりよく反映するように記事を編集しましたが、特に一時変数を確認するためにデータベースにクエリを実行する必要があったため、デバッグ時に多くの問題が発生しました。また、データベースは常にデータを照会され、新しいデータがすでに存在するかどうかを確認するため、パフォーマンス関連の大きな問題がありました。
jluzwick、2011

0

カートビフォアザホース-別名YouMightNeedIt

例えば:

  • 抽象概念と相互参照を使用したRDMBスキーマの作成-本質的には一般化されたデータキューブ... そして、何でもできるモデルに関する機能を記述します。

それはYAGNIの邪悪な双子の兄弟ですよね?
ウェインモリーナ

0

IMOで私が見た中で最悪のアンチパターンは、「臭いパターンが必要ない」アンチパターンです。デザインパターンは時間の無駄であり、一緒にスロープしてコピー/コピーするだけでコードをより速く書くことができるという考え必要に応じて貼り付けます。

名誉ある言及は、以下の古いVB6スタイルを使用してデータベースからオブジェクトをロードするコードを持つことです。

Foobar oFoo = new Foobar();
oFoo.FooID = 42;
if (oFoo.Load()) { 
    // do something with oFoo
}

それ自体は実際にはアンチパターンではありませんが、適切なアーキテクチャと懸念事項の分離を活用できないことを示しています。

また、次のようなもの:

// this name is misleading, we may not always want to stand in fire,
// we may want to stand in slime or voidzones or ice patches...
public Foobar StandInFire() { }

// why is this here???
public string BeatWithNerfBat(string whom) { }

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