당신이 겪은 최악의 반 패턴


9

프로그래머로서 경력에서 겪은 최악의 반 패턴은 무엇입니까?

언어와 무관하지만 대부분 자바에 관여합니다.

나는 그것의 최악이 내가 주요 안티 패턴 이라고 생각합니다 . 그것은 모든 논리를 포함하는 매우 큰 단일 클래스 (때로는 작은 클래스 쌍과 함께 제공됨)로 구성된 프로그램을 의미합니다. 일반적으로 모든 비즈니스 로직이 포함되어 있고 때로는 수만 줄의 코드가 포함 된 큰 루프가 있습니다.

답변:


38

코드를 주석 처리했습니다. 그것의 블록, 아마도 수백 줄. 이론은, 그것은 논평되고, 아무런 해를 끼치 지 않으며 아마도 우리는 미래에 그것을 필요로 할 것입니다.


7
적어도 안전하게 삭제할 수 있습니다. 내가 함께 일한 사람과 달리 절차의 이름을 자주 바꾸고 죽은 코드에 액세스 할 수 있습니다. 블리치.
Jay

@Cyrena, Eric도 함께 일 했나요?!?
CaffGeek

#ifdef COMMENT를 사용하여 내용을 잠그는 코드가 한 번있었습니다. 누군가가 COMMENT를 정의 할 때까지 훌륭하게 작동했습니다.
Michael Kohne

9
버전 관리를 사용하는 것이 또 다른 경우입니다. 몇 번의 키 입력으로 다시 검색 할 수 있으므로 나중에 필요할지 여부를 묻지 않고 코드를 삭제할 수 있습니다.
Jason B

5
나는 주석이 달린 코드가 그 이유를 설명하는 주석을 접두어로 배치하면 장소가 있다고 생각합니다. 때때로 나는 내가 생각하고있는 잠재적 인 길을 나타내는 주석이 달린 블록을 남겨두고 내가하지 않은 이유에 대한 주석을 남길 것입니다. @Jason, 나는 이것이 버전 제어의 역할에 대해 분명히 들었지만 버전 제어에서 삭제 된 코드는 매우 발견 할 수 없습니다.
nlawalker

19

"복사 파스타"로 또 다른 분명한 것을 맞을 것입니다. 원하는 것과 거의 동일한 코드를 복사 한 다음 메소드로 추출하는 대신 몇 가지 사항을 변경하십시오.

이것은 90 년대 후반의 일부 기능 및 API 테스트 코드에서 특히 널리 퍼져 있습니다. 문자 그대로 수백 개 (또는 수천 개)의 거의 동일한 테스트 사례가 3 개 또는 4 개의 매개 변수를 취하는 몇 가지 함수로 나뉘어 질 수 있습니다. 데이터 중심의 무언가. 대학 밖에서의 첫 직업은 말 그대로 8 개월 동안 수천 줄의 카피 파스타를 다시 쓰고 리팩토링하는 것입니다. 테스트가 완료 될 때까지 테스트 파일은 원래 크기의 10 분의 1보다 작았으며 유지 관리가 쉽고 읽기 쉬웠습니다.


16

적은 노력으로 해결할 수있는 Pattern Mania 및 솔루션 에 대해 많이 쓸 수 있다고 생각 하지만 간단한 솔루션을 과도하게 복잡하게 만드는 방법에 대한 환상적인 예를 들어 최근에 읽은 훌륭한 기사를 가리키고 싶습니다. .

Java로 팩토리얼을 작성하는 방법 (아님)으로 알고리즘에 팩토리를 넣는 방법


3
대박! 이제 FactorialWebService는 어디에 있습니까? : P
FrustratedWithFormsDesigner

1
나는 그것을 패턴 열 (Pattern Fever)이라고 부른다. 우리 중 더 나은 것은 그 이상으로 성장합니다. 나는 언제 패턴에 대해 생각해야하는지 물어 보는 인터뷰를했다. 나는 그들이 시스템으로 진화하게했다고 그에게 말했다. "아니요, 처음부터 패턴을 사용해야합니다."
Michael Brown

FactoryFactories는 가능한 한 실제 선택을 지연시키고 자하는 증상 일 뿐이지 만 여전히 하드 코딩하거나 외부 문자열 값을 코드 조각에 매핑합니다. 의존성 주입이 더 나은 솔루션입니다.

패턴은 훌륭한 디자인의 인공물입니다. 따라서 그렇게 취급해야합니다. 나는 그것들을 해결책 이라기보다는 정의로 묘사하고 싶다. 통신 할 때 유용하지만 반드시 디자인 할 필요는 없습니다.
Michael K

고마워요
Syg


14

지역

C #에서는 IDE에서 축소 될 수있는 코드 영역을 정의 할 수 있으므로 해당 코드를 처리하지 않으려면 숨길 수 있습니다. 나는 지역이 수백 줄에 걸쳐있는 프로젝트에 있었고 (현재 내가 과장하고있다) 수천 개의 라인 기능으로 여러 지역이있었습니다 (내가 농담하고 싶습니다).

거꾸로, 지역을 만든 개발자는 지역 내에서 특정 기능을 식별하는 데 매우 효과적이었습니다. 그래서 그 지역에서 추출법을 사용하여 계속 진행할 수있었습니다.

지역은 개발자가 자신의 쓰레기를 눈에 잘 띄지 않도록 권장합니다.


15
리전의 경우 +1은 개발자가 자신의 쓰레기를 눈에 잘 띄지 않도록 권장합니다. 그러나 올바르게 사용하면 영역이 논리적으로 코드를 그룹화하고 나중에 쉽게 찾을 수 있습니다.
대런 영

이것은 편집기를 접는 데 오랫동안 문제가되어 왔습니다. OCCAM에서 마지막으로 프로그래밍 할 때 같은 종류의 작업을 수행했습니다.
Michael Kohne

2
나는 지역을 좋아하지만 조직을 위해서만 ... 디지털 코드를 숨기지 않습니다.
IAbstract 2019

3
+1. 그렇기 때문에 영역을 사용하면 StyleCop 규칙 SA1124를 위반하는 것 DoNotUseRegions입니다.
Arseni Mourzenko

1
SQL의 수많은 필드에서 작동하는 프로젝트가 있으며이를 업데이트 / 생성하는 코드는 여러 줄입니다. 영역 #region SQL Update은 축소 가능하므로 스크롤이 덜 필요합니다.
JYelton


9

과부하가 걸리지 않는 방법 :

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

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

프로그래머가 과부하를 이해하지 못했음을 분명히 보여줍니다.



5

소프트 코딩 , 즉 프로그래머가 하드 코딩을 피하고 스케일의 다른 쪽 ( "하드 코딩 된"종속성)에서 벗어나는 경우.


4

클라이언트의 상태를 유지하십시오.

모든 상태가 브라우저에 유지되는 웹 애플리케이션으로 작업 한 후 문제없는 확장 성을 보장하기 위해 모든 예외는 무시되었습니다.


좀 더 자세히 설명해 주시겠습니까? Imho, 웹 응용 프로그램의 경우 유일한 상태가 브라우저 (예 : 쿠키)에 있고 서버가 '공유 없음'이면 좋습니다. 아니면 '응용 프로그램 데이터베이스'에서와 같이 '상태'를 의미합니까?
keppla

상태 : 작동 할 실제 데이터와 동일합니다.

OO 내 깊은 동정심이 있습니다.
keppla

4

대규모 체크인

개발자가 일주일 이상 체크인하지 않은 것을 싫어합니다. 그것은 그가 붙어서 도움을 구하지 않았거나 많은 기능을 하나의 큰 체크인으로 모으는 것을 의미합니다. (나는 최악의 시나리오를 배제했지만 그는 아무것도하지 않고있다. 해결하기 쉽습니다 ... 두 단어가 고용 된 것처럼 들립니다.)

큰 체크인을하는 경우 변경 집합을 특정 기능에 연결할 수있는 것처럼 SCM의 많은 이점을 잃게됩니다. 또한 많은 병합 작업을 수행 할 가능성이 높으며 반드시 올바르게 달성하기가 쉽지는 않습니다.


1
아무것도하지 않는 것이 항상 최악의 시나리오는 아닙니다. 때로는 코드를 다시 작성하는 것보다 처음부터 새로 작성하는 것이 좋습니다.
Malachi

4

현재 레거시 코드로 작업하고 있으며 이전 코더가 목록의 첫 번째 요소를 얻는 방식을 좋아합니다.

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

그러나이 코드에서 본 최악의 상황은 클래스 인라인 JSP 페이지를 정의하고 scriptlet 및 out.println을 사용하여 모든 HTML, CSS 및 Javascript를 작성하는 것입니다.


4

내가 본 최악의 행동 방지 패턴 중 하나는 코드를 프로덕션에 넣은 후에 만 ​​버전 제어에 체크인하도록 허용하는 상점이었습니다. 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 사용


이것들은 반드시 안티 패턴이 아니며 나쁜 코딩 일뿐입니다.
Gary Willoughby

@Gary 또는 열악한 개발 패턴이 반복되는 것을 봅니다. 아마도 안티 패턴의 엄격한 정의 내에 있지 않을 것입니다.
Peter Lawrey

1
@Peter : "일부 메모리를 확보하기 위해 System.gc ()를 호출합니다."GC가 명시 적으로 호출되지 않으면 .NET이 OutOfMemory 예외로 폭발하는 경우를 보았습니다. 물론 그것은 규칙이 아니라 더 많은 예외였습니다.
Coder

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종종 일을 끝내는 유일한 방법입니다. 나는 줄에 대해 생각하고있다; 스위치를 사용할 수 없습니다. 조건이 유용해야합니다.
Michael K

각 if / else를 간단한 매핑 또는 방문자 패턴으로 바꿀 수 있습니다. 문자열의 경우 즉, 다음과 같은 속성 파일이있을 수 있습니다. someString1 = some.package.ObjectToHandleSomeString1
Marcin Michalski

2
싱글 톤 공장 입니다. 그 코드에는 아무런 문제가 없습니다. 틀릴 수있는 유일한 것은 외부 코드가 모든 호출 getInstance이 동일한 인스턴스 를 반환 한다고 가정한다는 것 입니다. 이러한 가정은 캡슐화를 깨뜨릴 것이며 실제로 가장 일반적인 반 패턴 중 하나입니다.
back2dos

예를 들어, 메소드가 create ()이거나 모든 것이 완벽하게 괜찮을 때마다 동일한 인스턴스를 반환하는 경우에는 혼동 스럽습니다.
Marcin Michalski

2

그것은 코딩 패턴이 아니라 행동 패턴입니다.하지만 코드에서 무언가를 수정하고 (요구 사항이 바뀌 었다고 가정) 코드가 그것을 통과 할 때까지 모든 단위 테스트를 조정하십시오. 테스트 메소드에서 모든 테스트 코드를 조정하거나 제거하지만 메소드는 그대로 둡니다.

이것은보다 일반적인 패턴 인 That 'll Do 패턴 과 연결되어 있으며 , 대표적인 코드 라인은 다음과 같습니다.

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

결국 작동합니다.


2

나는 추상화 반전을 절대적으로 무시 하거나 높은 수준의 기본 요소 위에 낮은 수준의 기본 요소를 다시 발명합니다. 그러나 때때로 이것은 나쁜 프로그래머가 아닌 나쁜 언어 디자이너에 의해 발생합니다. 예 :

  1. 함수 포인터 대신 멤버 변수와 해당 인터페이스 (함수 포인터 테이블로 구현)가없는 단일 메서드 클래스를 사용합니다. Java와 같은 언어에서는 선택의 여지가 없습니다.

  2. MATLAB과 R에서 모든 것이 기본 요소가 아닌 벡터 / 행렬이라는 주장.

  3. 우리는 MATLAB을 강타하고 있지만 정수가 없다는 사실은 어떻습니까? 따라서 정수가 필요할 때는 double을 사용해야합니다.

  4. 루프를 작성하기 위해 함수 호출을 사용해야하는 순수 기능 언어.


1

그것은 분명히 복사 / 붙여 넣기 일 것입니다. 나는 그 때문에 많은 나쁜 코드, 카우보이 코딩 및 그로부터 파생 된 모든 코드를 보았습니다. (신 클래스, 초대형 메소드, 나쁜 생각 알고리즘 등)

그리고 디자인 패턴이 허용된다면, 나는 디자인이나 도메인 분석을 수행하지 않고 계획에서 일련의 행동으로 프로젝트를 수행합니다.


1

다중 사용 Java Bean-

몇 가지 다른 종류의 작업에 사용되는 변수가 많은 Java Bean입니다. 각 조작은 Bean 변수의 임의의 서브 세트를 사용하고 다른 변수는 무시합니다. GUI 상태에 대한 몇 가지 변수, 구성 요소 사이를 통과하기 위해 던져지는 몇 가지 변수, 더 이상 사용되지 않는 변수 모범 사례에는 문서가 없으므로 패턴의 감상을 방해합니다.

또한 사랑하는 사람을 잊을 수 없다

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

IMHO, 예외가 악취. 그것들을 제대로 얻기가 너무 어려우며 잘못된 보안 감각을 추가합니다.
Coder

예외의 악취에 대한 당신의 의견이 무엇이든, 조용히 삼키는 것은 더 악취가납니다.
Steve B.

1

전직 동료는 단순히 새 객체를 만드는 대신 속성을 덮어 써서 객체를 재사용하는 습관을 가졌습니다. 새로운 기능을 구현할 때 이런 문제가 발생했다고 상상할 수 없었습니다.


1

나를 슬프게 만든 것은 "하늘의 큰지도"패턴입니다. 적절한 개체를 사용하는 대신지도를 던지십시오. 디버깅하지 않고 "변수"가 무엇인지 알 수 없으며 코드를 거꾸로 추적하지 않고 무엇이 포함될 수 있는지 모릅니다. 일반적으로 문자열을 객체에 매핑하거나 문자열을 문자열에 매핑하면 기본적으로 구문 분석해야합니다.


종류 슬프게도 종종 필요한 페이지 사이의 데이터의 수병을 전달하는 ASP.NET의 세션과의 ViewState에 의존하는 등의 사운드 ...
웨인 몰리나

1

내가 가장 좋아하는 개발 방지 패턴 중 하나는 프로그래밍 방식 으로 하나 이상의 테이블에 추가 열 을 계속 추가 해야하는 데이터베이스 "디자인"을 사용 하는 것 입니다. 이것은 엔터티의 각 인스턴스에 대해 새 테이블을 만드는 "디자인"의 사촌입니다. 둘 다 필연적으로 데이터베이스 서버의 한계에 부딪 쳤지 만 시스템이 꽤 오랫동안 생산 될 때까지는 아닙니다.


0

필자가 본 최악의 안티 패턴 중 하나는 컴퓨터 메모리 대신 데이터베이스 테이블을 임시 저장소로 사용하는 것입니다.

문제 영역은 독점적이므로 문제를 설명 할 수는 없지만 기본 문제를 이해할 필요는 없습니다. 이것은 백엔드 데이터베이스로 Java로 작성된 GUI 응용 프로그램입니다. 특정 입력 데이터를 가져 와서 조작 한 다음 처리 된 데이터를 데이터베이스에 커밋했습니다.

우리 프로젝트에는 나중에 처리하기 위해 중간 값을 저장하는 상당히 복잡한 알고리즘이 있습니다. 임시 객체를 객체로 캡슐화하는 대신 "t_object"와 같은 데이터베이스 테이블이 생성되었습니다. 값이 계산 될 때마다이 테이블에 추가되었습니다. 알고리즘이 작업을 마치면 모든 중간 값을 선택하여 하나의 큰 Map 객체에서 처리합니다. 모든 처리가 완료된 후에 저장되도록 표시된 나머지 값이 실제 데이터베이스 스키마에 추가되고 "t_object"테이블의 임시 항목이 삭제됩니다.

테이블은 또한 고유 목록처럼 사용되었으며 데이터는 한 번만 존재할 수있었습니다. 이것은 테이블에 제약 조건을 구현했을 때 디자인의 적절한 기능 일 수 있었지만 데이터가 존재하는지 여부를 확인하기 위해 전체 테이블을 반복했습니다. (아니오 우리는 CONTAINS와 함께 where 절을 사용한 쿼리조차 사용하지 않았습니다)

이 디자인으로 인해 발생한 문제 중 일부는 구체적으로 디버깅이었습니다. 이 응용 프로그램은 파이프 라인 데이터를 위해 작성되었으므로이 알고리즘에 도달하기 전에 데이터를 사전 처리하는 여러 GUI가 있습니다. 디버깅 프로세스는 테스트 케이스를 처리 한 다음 위 섹션을 완료 한 직후 일시 중지하는 것이 었습니다. 그런 다음이 테이블에 어떤 데이터가 포함되어 있는지 데이터베이스를 쿼리합니다.

우리가 발견 한 또 다른 문제는이 임시 테이블에서 데이터가 올바르게 삭제되지 않아 향후 실행을 방해한다는 것입니다. 예외가 올바르게 처리되지 않아서 애플리케이션이 올바르게 종료되지 않아서 제어중인 테이블의 데이터가 삭제되지 않았기 때문인 것으로 나타났습니다.

기본 객체 지향 설계를 사용하고 모든 것을 메모리에 보관했다면 위의 문제는 발생하지 않았을 것입니다. 첫째, 응용 프로그램에서 중단 점을 쉽게 설정 한 다음 스택 및 힙의 메모리를 검사 할 수 있으므로 디버깅이 간단했을 것입니다. 둘째, 응용 프로그램이 비정상적으로 종료되면 데이터베이스에서 삭제하는 것에 대해 걱정할 필요없이 Java 메모리가 자연스럽게 정리되었습니다.

참고 : 나는이 패턴이 본질적으로 나쁘다는 것을 말하지는 않지만이 예제에서는 기본 OO 원칙이 충분했을 때 불필요하다는 것을 알았습니다.

나는이 반 패턴의 이름을 확신하지 못한다. 이 패턴에 대해 좋은 이름을 생각할 수 있습니까?


나는 이것을 담요 문제라고 부르지 않을 것이다. 저장되는 임시 데이터의 양과 수행 할 작업에 따라 다릅니다.
GrandmasterB

게시물에 더 추가해야하지만 주요 문제는 객체를 수정하고 메모리에서 데이터에 액세스하는 대신 해킹 SQL 코드로 데이터를 조작한다는 것입니다. 이로 인해 복잡성이 증가하고 성능 문제가 심각해졌습니다.
jluzwick

2
문제 영역을 언급하지는 않지만 항상 나쁜 것은 아닙니다. 이와 같은 상태를 유지하면 프로세스를 확장하고 장기적으로 검사하여 디버깅에 도움을 줄 수 있습니다. DB 액세스로 인해 성능 문제가 발생 했습니까?
Jé Queue

이 기사를 프로젝트에서 어떻게 사용했는지 더 잘 반영하도록 기사를 편집했지만 디버깅 할 때 특히 임시 변수를 확인하기 위해 데이터베이스를 쿼리해야했기 때문에 많은 문제가있었습니다. 또한 데이터베이스는 지속적으로 데이터를 쿼리하고 새 데이터가 이미 있는지 확인하여 성능 관련 문제가 컸습니다.
jluzwick

0

카트-전-전-일명 YouMightNeedIt

예를 들면 다음과 같습니다.

  • 추상적 개념, 상호 참조를 통해 RDMB 스키마 생성-본질적으로 지나치게 일반화 된 데이터 큐브 ... 그리고 모든 모델을 중심으로 기능을 작성합니다.

야 그니의 사악한 쌍둥이 형제일까요?
웨인 몰리나

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.