Los peores antipatrones que has encontrado [cerrado]

9

¿Cuáles son los peores antipatrones que has encontrado en tu carrera como programador?

Estoy principalmente involucrado en Java, aunque probablemente sea independiente del idioma.

Creo que lo peor es lo que llamo el antipatrón principal . Significa un programa que consiste en una sola clase extremadamente grande (a veces acompañada con un par de clases pequeñas) que contiene toda la lógica. Por lo general, con un gran bucle en el que está contenida toda la lógica empresarial, a veces con decenas de miles de líneas de código.

стривігор
fuente

Respuestas:

38

Comentó el código. Bloques de la misma, tal vez cientos de líneas. La teoría es, oye, está comentado, no hace ningún daño y tal vez lo necesitemos en el futuro.

Navi
fuente
77
Bueno, al menos puedes eliminarlo de forma segura. A diferencia de alguien con quien he trabajado, con frecuencia cambiaría el nombre de los procedimientos y dejaría accesible el código muerto. Blech
Jay
@Cyrena, ¿también trabajaste con Eric?
CaffGeek
Una vez tuve un montón de código que usaba #ifdef COMMENT para bloquear las cosas. Funcionó muy bien hasta que alguien definió COMENTARIO.
Michael Kohne
99
Este es otro caso donde vale la pena usar el control de versiones. Puede eliminar el código sin tener que preguntar si es posible que lo necesite en el futuro porque puede recuperarse nuevamente con unas pocas teclas.
Jason B
55
Creo que el código comentado tiene un lugar, si lo prefieres con un comentario que explique por qué está ahí. A veces dejaré un bloque comentado que representa un camino potencial que estaba pensando en tomar, y lo dejaré con un comentario sobre por qué no lo hice. @ Jason, definitivamente te escucho acerca de que este es el rol del control de versiones, pero el código eliminado en el control de versiones no es muy reconocible.
nlawalker
19

Golpearé otro obvio con "copy-pasta". Copiando código que es casi idéntico a lo que desea, luego cambiando algunas cosas (en lugar de extraerlo en un método).

Esto es especialmente frecuente en algunos códigos de prueba funcionales y API de finales de los 90: literalmente cientos (o incluso miles) de casos de prueba casi idénticos que podrían haberse dividido en algunas funciones que toman 3 o 4 parámetros, o incluso mejor , algo basado en datos. Mi primer trabajo fuera de la universidad fue, literalmente, 8 meses de reescritura y refactorización de miles de líneas de pasta de copia que usaban métodos obsoletos. Cuando terminé, los archivos de prueba tenían menos de una décima parte de su tamaño original y mucho más fáciles de mantener (¡y legibles!).

Ethel Evans
fuente
16

Creo que puedo escribir mucho sobre Pattern Mania y las soluciones que podrían resolverse con mucho menos esfuerzo, pero prefiero señalar un excelente artículo que he leído recientemente con un fantástico ejemplo de cómo una solución simple puede complicarse demasiado .

Cómo (no) escribir Factorial en Java o eso ponemos una fábrica en su algoritmo

Andrey Taptunov
fuente
3
¡Increíble! ¿Dónde está el FactorialWebService? : P
FrustratedWithFormsDesigner
1
Yo lo llamo Pattern Fever ... todos lo tienen en algún momento de su carrera. Los mejores entre nosotros crecen más allá. Tuve una entrevista en la que el chico me preguntó cuándo debería pensar en los patrones. Le dije que los dejé evolucionar en el sistema. Él dijo: "No, debes usar patrones desde el principio".
Michael Brown
FactoryFactories es solo un síntoma de querer diferir la elección real tanto como sea posible, pero aún así termina codificándola o asignando un valor de cadena externa a un fragmento de código. La inyección de dependencia es una mejor solución.
Los patrones son artefactos de un buen diseño; deben tratarse como tales. Me gusta describirlos como definiciones en lugar de soluciones. Son útiles cuando se comunican, pero no necesariamente en el diseño.
Michael K
Gracias por eso, buena lectura.
Syg
14

Regiones

En C # puede definir una región de código que se puede contraer en el IDE, ocultándola a menos que desee lidiar con ese código. He estado en (actualmente estoy en) un proyecto en el que las regiones abarcaban cientos de líneas (ojalá estuviera exagerando) y había varias regiones en una función de mil líneas (nuevamente deseo estar bromeando).

Por el lado positivo, el desarrollador que hizo la región hizo un muy buen trabajo al identificar funciones específicas dentro de una región. Tanto es así que pude hacer un método de extracción en la región y seguir adelante.

Las regiones alientan a los desarrolladores a "ocultar" su basura a simple vista.

Michael Brown
fuente
15
+1 para Regions anima a los desarrolladores a "ocultar" su basura a simple vista. Sin embargo, cuando se usa correctamente, encuentro que las regiones ayudan a agrupar lógicamente el código y encontrarlo fácilmente en un momento posterior.
Darren Young
Esto ha sido durante mucho tiempo un problema con los editores plegables. Solía ​​hacer lo mismo la última vez que programé en OCCAM.
Michael Kohne
2
Me encantan las regiones ... pero solo para la organización ... no para ocultar resmas digitales de código.
Resumen de
3
+1. Es por eso que usar regiones viola la regla SA1124 de StyleCop DoNotUseRegions.
Arseni Mourzenko
1
Tengo proyectos que funcionan con una gran cantidad de campos en SQL, y el código que lo actualiza / crea son muchas líneas. Una región lo #region SQL Updatehace plegable, por lo que se requiere menos desplazamiento.
JYelton
12

Para mí, el peor patrón es Copiar / Pegar .

LennyProgrammers
fuente
28
Para mí, el peor patrón es Copiar / Pegar.
Andrew Arnold
9

No sobrecargar los métodos:

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

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

Muestra claramente que el programador no entendió la sobrecarga.

Michael K
fuente
5

Secuencias de cambio de bucle

http://en.wikipedia.org/wiki/Loop-switch_sequence

Me molestan hasta el infinito y realmente muestran cuán inexperto era el desarrollador

CaffGeek
fuente
Ah, una máquina de estado de terminación :)
¿Por qué tienes que traer estos recuerdos enterrados? Estaba teniendo un buen día.
Malaquías
5

Codificación suave , es decir, cuando los programadores hacen todo lo posible para evitar la codificación dura y terminan en el otro lado de la escala: dependencias "codificadas".

AareP
fuente
4

Mantener el estado en el cliente.

Una vez trabajado con una aplicación web donde todo el estado se mantuvo en el navegador. (Para garantizar una escalabilidad sin problemas, se ignoraron todas las excepciones).

usuario1249
fuente
¿Podrías por favor elaborar? En mi opinión, para una aplicación web, está bien cuando el único estado está en el navegador (es decir, las cookies), y el servidor no 'comparte nada'. ¿O quiere decir 'estado' como en 'la base de datos de aplicaciones'?
keppla
Estado: como en los datos reales para operar.
OO, tienes mis más profundas condolencias.
keppla
4

Registros masivos

Odio cuando veo que un desarrollador no ha hecho un check-in en más de una semana. Significa que está atascado y no ha buscado ayuda, o está agrupando un montón de características en un gran check-in. (Dejé el peor de los casos, él simplemente no está haciendo nada. Eso es fácil de resolver ... dos palabras suenan como si estuvieras contratado).

Si realiza un gran check-in, pierde muchos beneficios de SCM, como poder vincular un conjunto de cambios a una característica específica. Además, es probable que tenga que fusionarse mucho y eso no es necesariamente fácil de hacer.

Michael Brown
fuente
1
No hacer nada no siempre es el peor de los casos. A veces es mejor tener que escribirlo desde cero que tener un código para reescribir ...
Malachi
4

Actualmente, estoy trabajando con un código heredado y me encanta la forma en que el codificador anterior obtiene el primer elemento de una lista:

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

Pero lo peor que he visto en este código es definir páginas JSP en línea de clases, escribir todo el HTML, CSS y Javascript usando scriptlet y out.println :-(

SourceRebels
fuente
4

Uno de los peores patrones contra el comportamiento que he visto fue una tienda que solo permitía que el código se registrara en el control de versiones después de que estaba en producción. Junto con los pagos exclusivos en VSS, esto condujo a un proceso complicado de deshacer los pagos si un defecto de producción necesita ser corregido antes de la próxima versión, y mucho menos que una persona necesite cambiar un archivo dado para la próxima versión.

El hecho de que se tratara de una política departamental lo hizo aún peor que el caso de un solo desarrollador que se comportara de esta manera.

Malaquías
fuente
3

Bloqueo en un literal de cadena

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

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

Nombres de clase muy largos. (en el JRE)

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

Mala estructura de herencia

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

Una excepción que no lo es.

public interface FlavorException { }

Manejo de errores sin sentido y críptico

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

Creación innecesaria de objetos.

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

Lanzar una excepción para otros fines

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

Uso de objetos de instancia para métodos estáticos.

Thread.currentThread().sleep(100);

Sincronización en un campo no final

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

Copia sin sentido de una cadena constante

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

Llamada inútil a String.toString ()

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

Llamadas a System.gc () para liberar algo de memoria

Establecer la variable local en nulo para liberar algo de memoria

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

Usar ++ i en lugar de i ++ por razones de rendimiento (o cualquier otra micro-micro-optimización)

Peter Lawrey
fuente
Estos no son necesariamente antipatrones, solo codificación incorrecta.
Gary Willoughby
@Gary, o pobres patrones de desarrollo que veo repetidos. Quizás no dentro de la definición estricta de un antipatrón.
Peter Lawrey
1
@ Peter: "Llamadas a System.gc () para liberar algo de memoria", he visto una ocasión en la que .NET explotaría con la excepción OutOfMemory a menos que se llamara a GC explícitamente. Por supuesto, fue más una excepción que una regla.
Codificador
3

Código rociado con:

// TODO: 

o

// TODO: implement feature 

sin información adicional

Malaquías
fuente
2

Iterador para tontos:

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

Singletono-Factory:

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

desarrollo impulsado por if-else (también llamado principio de cierre cerrado - abierto para modificación cierre para comprensión)

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

StringPattern (también llamado 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
Marcin Michalski
fuente
Sin else ifembargo, esa es a menudo la única forma de hacer las cosas. Estoy pensando en cuerdas; No puedo usar un interruptor. Las condiciones deben ser iguales para que sea útil.
Michael K
En mi humilde opinión cada uno / otro puede ser reemplazado con un mapeo simple o patrón de visitante. En el caso de cadenas, es decir, puede tener un archivo de propiedades como: someString1 = some.package.ObjectToHandleSomeString1
Marcin Michalski
2
El singleton es una fábrica . No hay nada malo con ese código. Lo único que podría estar mal es que el código externo asume que cada llamada a getInstancedevuelve la misma instancia. Tal suposición rompería la encapsulación y, de hecho, es uno de los antipatrones más comunes.
back2dos
exactamente por eso es tan confuso :) si el método se llamara create () o devolvería la misma instancia cada vez que todo estaría perfectamente bien
Marcin Michalski
2

No es tanto un patrón de codificación sino un patrón de comportamiento, aunque es bastante malo: modificar algo en el código (digamos que los requisitos cambiaron), luego ajustar todas las pruebas unitarias hasta que el código lo apruebe. Ajustar o simplemente eliminar todo el código de prueba del método de prueba, pero dejar el método allí.

Sin embargo, esto está vinculado a uno más genérico, el patrón That'll Do , aquí hay una línea de código representativa para ello:

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

Funciona, después de todo.

revs biziclop
fuente
2

Desprecio absolutamente la inversión de abstracción o la reinvención de primitivas de bajo nivel además de las primitivas de alto nivel. A veces, sin embargo, esto es causado por diseñadores de lenguaje malos, no por malos programadores. Ejemplos:

  1. Usar una sola clase de método sin variables miembro y una interfaz correspondiente (implementada en términos de tablas de punteros de función), en lugar de un puntero de función. Tenga en cuenta que en lenguajes como Java, es posible que no tenga otra opción.

  2. En MATLAB y R, la insistencia en que todo es un vector / matriz en lugar de un primitivo.

  3. Mientras atacamos MATLAB, ¿qué tal el hecho de que no tiene enteros, por lo que cuando necesita un entero tiene que usar un doble?

  4. Lenguajes puramente funcionales donde tienes que usar llamadas de función para escribir un bucle.

dsimcha
fuente
1

Definitivamente sería copiar / pegar, he visto una gran cantidad de código incorrecto debido a eso, eso y la codificación de vaquero y todo lo que se deriva de eso. (Clases de Dios, métodos extra grandes, algoritmos mal pensados, etc.)

Y si se permiten patrones de diseño, yo diría: Hacer un proyecto como un conjunto de acciones de un plan, sin hacer ningún diseño o análisis de dominio.

Coyote21
fuente
1

Frijol Java multiuso -

Un bean Java con muchas variables, utilizado en algunos tipos diferentes de operaciones. Cada operación utiliza un subconjunto arbitrario de las variables de bean e ignora las demás. Algunas variables para el estado de la interfaz gráfica de usuario, algunas variables para pasar entre los componentes, algunas que probablemente ya ni siquiera se usan. Los mejores ejemplos no tienen documentación, lo que dificultaría la apreciación del patrón.

Además, no puedo olvidar a la amada

try{ 
   ... //many lines of likely dangerous operations
}
catch(Exception e){}
Steve B.
fuente
En mi humilde opinión, las excepciones apestan. Son demasiado difíciles de corregir y agregan una falsa sensación de seguridad.
Codificador
Cualquiera que sea su opinión sobre el mal olor de las excepciones, tragar en silencio uno tiene que apestar más.
Steve B.
1

Un antiguo compañero de trabajo tenía la costumbre de reutilizar objetos sobrescribiendo sus propiedades, en lugar de simplemente crear otras nuevas. Nunca podría haber imaginado la cantidad de problemas que esto ha causado al implementar nuevas funciones.

deltreme
fuente
1

Algo que me ha causado mucho dolor es el patrón "Gran mapa en el cielo". Lanzar un mapa en lugar de usar los objetos adecuados. No tiene idea de qué "variables" contiene sin depurar, y no sabe qué podría contener sin rastrear el código hacia atrás. Por lo general, asigna cadenas a objetos o cadenas a cadenas, que se supone que debe analizar en primitivas.

Buhb
fuente
Suena algo así como confiar en Session y ViewState en ASP.NET para pasar grandes cantidades de datos entre páginas, lo que lamentablemente a menudo se requiere ...
Wayne Molina
1

Uno de mis anti patrones de desarrollo favoritos es el uso de un "diseño" de base de datos que requiere la adición continua de columnas adicionales a una o más tablas mediante programación . Este es un primo del "diseño" que crea una nueva tabla para cada instancia de una entidad. Ambos inevitablemente golpean las limitaciones del servidor de la base de datos, pero generalmente no hasta que el sistema ha estado en producción durante bastante tiempo.

Malaquías
fuente
0

Creo que uno de los peores antipatrones que he visto implica el uso de una tabla de base de datos como almacenamiento temporal en lugar de usar la memoria de la computadora.

El dominio del problema es propietario, lo que me impide explicarlo, pero no es necesario comprender el problema básico. Esta fue una aplicación GUI escrita en Java con una base de datos de back-end. Era tomar ciertos datos de entrada, manipularlos y luego confirmar los datos procesados ​​en la base de datos.

Nuestro proyecto tiene un algoritmo bastante complicado que guarda valores intermedios para su procesamiento posterior. En lugar de encapsular los objetos temporales en ... objetos, se creó una tabla de base de datos como "t_object". Cada vez que se calculaba un valor, se agregaba a esta tabla. Una vez que el algoritmo haya terminado su trabajo, seleccionaría todos los valores intermedios y los procesaría todos en un objeto Map grande. Una vez finalizado todo el procesamiento, los valores restantes que se marcaron como guardados se agregarán al esquema de la base de datos real y las entradas temporales en la tabla "t_object" se descartarán.

La tabla también se usó como una lista única, los datos solo podían existir una vez. Esta podría haber sido una característica decente del diseño si hubiéramos implementado Restricciones en la tabla, pero terminamos iterando en toda la tabla para ver si los datos existían o no. (No, ni siquiera usamos consultas que usaban cláusulas where con CONTAINS)

Algunos de los problemas que encontramos debido a este diseño fueron específicamente la depuración. La aplicación se creó para canalizar datos, por lo que habría múltiples interfaces gráficas de usuario que procesarían los datos antes de llegar a este algoritmo. El proceso de depuración consistió en procesar un caso de prueba y luego hacer una pausa justo después de terminar la sección anterior. Luego consultaríamos la base de datos para ver qué datos estaban contenidos en esta tabla.

Otro problema que descubrimos fue que los datos no se eliminaban correctamente de esta tabla temporal, lo que interferiría con la ejecución en el futuro. Descubrimos que esto se debía a que las Excepciones no se manejaban correctamente y, por lo tanto, la aplicación no salía correctamente y no borraba los datos de la tabla que controlaba.

Si hubiéramos utilizado el diseño orientado a objetos básicos y guardado todo en la memoria, estos problemas anteriores nunca hubieran ocurrido. Primero, la depuración habría sido simple, ya que podríamos configurar fácilmente puntos de interrupción en la aplicación y luego inspeccionar la memoria en la pila y el montón. En segundo lugar, al salir anormalmente de la aplicación, la memoria de Java se habría limpiado naturalmente sin tener que preocuparse por eliminarla de la base de datos.

NOTA: No digo que este patrón sea intrínsecamente malo, pero en este ejemplo me pareció innecesario cuando los principios básicos de OO hubieran sido suficientes.

No estoy seguro de un nombre para este antipatrón, ya que es la primera vez que veo algo así. ¿Algún buen nombre que ustedes puedan pensar para este patrón?

revs jluzwick
fuente
No llamaría a esto un problema general. Dependerá de cuántos datos temporales se almacenen y qué se haga con ellos.
GrandmasterB
Debería agregar más a la publicación, pero el problema principal era que, en lugar de modificar objetos y acceder a los datos desde la memoria, los datos se manipularon con código SQL pirateado. Esto condujo a una mayor complejidad y graves problemas de rendimiento.
jluzwick
2
No menciona su dominio problemático, pero no siempre es algo malo, mantener el estado en otro lugar como este podría permitir que los procesos se escalen y sean introspectivos durante tiempos de ejecución largos, también para ayudar en la depuración. ¿El acceso a la base de datos estaba causando problemas o problemas de rendimiento?
Jé Queue
Edité el artículo para reflejar mejor cómo se usó esto en nuestro proyecto, pero tuvimos numerosos problemas al depurar, específicamente porque tuvimos que consultar la base de datos para ver las variables temporales. También tuvimos grandes problemas relacionados con el rendimiento debido a que constantemente se consultaba la base de datos para obtener datos y verificar si ya existían nuevos datos.
jluzwick
0

Cart-Before-The-Horse - también conocido como YouMightNeedIt

Por ejemplo:

  • Crear un esquema de RDMB con conceptos abstractos, referencias cruzadas, en esencia un cubo de datos demasiado generalizado ... Y LUEGO escribir características alrededor de un modelo de hacer todo.
Sheldon Warkentin
fuente
Ese sería el malvado hermano gemelo de YAGNI, ¿verdad?
Wayne Molina
0

En mi opinión, el peor antipatrón que he visto es el antipatrón "No necesitamos ningún patrón apestoso": la idea de que los patrones de diseño son una pérdida de tiempo y que puedes escribir código más rápido simplemente mezclándolo y copiando / pegar según sea necesario.

Mención de honor va a tener código que carga un objeto de la base de datos usando el viejo estilo VB6 de:

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

no es realmente un antipatrón, per se, pero muestra una falta de aprovechamiento de la arquitectura adecuada y la separación de preocupaciones.

Además, cosas como esta:

// 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) { }
Wayne M
fuente