2008-10-18 17 views
24

Periódicamente me llaman para hacer trabajos de mantenimiento en un sistema que fue construido por un verdadero cirujano espacial. Hay tanto problema con eso que es difícil saber por dónde empezar.¿Cuál es el programa más incorrecto que has tenido que mantener?

No, espera, comenzaré por el principio: en los primeros días del proyecto, al diseñador se le dijo que el sistema necesitaría escalar, y había leído que una fuente de problemas de escalabilidad era el tráfico entre la aplicación y los servidores de la base de datos, por lo que se aseguró de minimizar este tráfico. ¿Cómo? Al poner toda la lógica de la aplicación en los procedimientos almacenados de SQL Server.

En serio. La mayor parte de las funciones de la aplicación se realiza mediante la interfaz HTML que formula los mensajes XML. Cuando el nivel medio recibe un mensaje XML, utiliza el nombre de etiqueta del elemento del documento como el nombre del procedimiento almacenado al que debe llamar, y llama al SP, pasándole todo el mensaje XML como parámetro. Toma el mensaje XML que devuelve el SP y lo devuelve directamente al frente. No hay otra lógica en el nivel de aplicación.

(No fue algo de código en el nivel medio para validar los mensajes XML entrantes contra una biblioteca de esquemas. Pero me lo quitó, después de cerciorarse de que: 1) sólo un pequeño puñado de mensajes había correspondientes esquemas, 2) los mensajes en realidad no se ajustaban a estos esquemas, y 3) después de validar los mensajes, si se encontraban errores, el método los descartaba. "Esta caja de fusibles ahorra mucho tiempo, viene de fábrica con un centavo preinstalado")

He visto software que hace algo mal antes. Montones. He escrito bastante. Pero nunca he visto nada como la determinación acerada de hacer lo incorrecto, en en cada vuelta posible, que se materializa en el diseño y la programación de este sistema.

Bueno, al menos se fue con lo que sabía, ¿verdad? Um. Aparentemente, lo que sabía era Access. Y realmente no entendió Acceso. O bases de datos.

Aquí hay un patrón común en este código:

 
SELECT @TestCodeID FROM TestCode WHERE TestCode = @TestCode 

SELECT @CountryID FROM Country WHERE CountryAbbr = @CountryAbbr 

SELECT Invoice.*, TestCode.*, Country.* 
    FROM Invoice 
    JOIN TestCode ON Invoice.TestCodeID = TestCode.ID 
    JOIN Country ON Invoice.CountryID = Country.ID 
    WHERE Invoice.TestCodeID = @TestCodeID AND Invoice.CountryID = @CountryID 

Bueno, está bien. Tampoco confías en el optimizador de consultas. Pero ¿qué tal esto? (Originalmente, iba a publicar esto en What's the best comment in source code you have ever encountered? pero me di cuenta de que había mucho más por escribir que solo este comentario, y las cosas se salieron de control.) Al final de muchos de los procedimientos almacenados de utilidad, Veremos código que tiene el siguiente aspecto:

 
-- Fix NULLs 
SET @TargetValue = ISNULL(@TargetValue, -9999) 

Sí, que el código está haciendo exactamente lo que no puede permitirse que creen que está haciendo para que no sean llevado a la locura. Si la variable contiene un NULL, está alertando a la persona que llama al cambiar su valor a -9999. Así es como se usa comúnmente este número:

 
-- Get target value 
EXEC ap_GetTargetValue @Param1, @Param2, OUTPUT @TargetValue 
-- Check target value for NULL value 
IF @TargetValue = -9999 
    ... 

Realmente.

Para obtener más información sobre este sistema, consulte el artículo en thedailywtf.com titulado I Think I'll Call Them "Transactions". No estoy haciendo nada de esto. Lo juro.

A menudo recuerdo, cuando trabajo en este sistema, la famosa respuesta de Wolfgang Pauli a un alumno: "Eso no está bien. Ni siquiera está mal."

Este no puede ser realmente el peor programa de la historia. Es definitivamente el peor en el que he trabajado en toda mi carrera de 30 años. Pero no lo he visto todo. ¿Qué has visto? ?

+2

ERROR Así que .... Esto realmente no es una pregunta tanto como un respiradero! Supongo que estás preguntando retóricamente: ¿Puedes superar esto? ... Hmmm ... –

+0

Esto parece más adecuado para su blog o un sitio [dedicado a la discusión] (http://meta.stackexchange.com/questions/13198/). –

+0

Hice la pregunta porque pensé (y aún creo) que las respuestas podrían ser útiles. El análisis de fallas en el software generalmente solo se lleva a cabo después de que el software ha fallado por completo (si es así); Cuerpos terribles que solo se mantienen vivos a través del trabajo a menudo solo son realmente entendidos por una o dos personas. ¿Qué tan malo puede ser un software y aún ser útil? ¿Cómo surgieron tales cosas y qué esfuerzos se requieren para apoyarlas?Es difícil explorar sistemáticamente esas preguntas, pero vale la pena explorarlas. –

Respuesta

40

una vez intenté escribir un decodificador MP3. no funcionó.

+1

Asumiendo que el juego de palabras estaba destinado, obtienes mi visto bueno señor, bueno, y no es que esas preguntas subjetivas merecen una respuesta seria de todos modos. – Seldaek

+0

No veo el juego de palabras ... –

+13

"poco sólido", supongo. No es el mejor juego de palabras que he escuchado: P – Blorgbeard

6

El que acabo de empezar a trabajar en.

  1. sin control de origen.
  2. Todas las fuentes se edita en directo Para detener los errores, hay archivos de respaldo como db-access.php.070821 que ensucian el árbol de fuentes.
  3. El código es excepcionalmente frágil: hay muy poco en el camino de la comprobación de errores y absolutamente no hay retroceso si lo hace.
+2

Asegúrese de esperar unos días mientras intentan deshacer su error. Hace que las expresiones faciales resultantes sean mucho más interesantes. –

+1

Es un proyecto de Internet distribuido pero con efectivo real. He estado hablando mucho sobre svn y hasta ahora no ha pasado nada. –

+0

acaba de romper la construcción. Entonces déjalo que se rompa por una semana. Entonces tal vez vean el beneficio de usar control de versiones = D –

19

Mantuve ExtUtils::MakeMaker. MakeMaker ciertamente no es el peor código que he tenido que mantener; en realidad es una maravilla de la ingeniería. Sin embargo, es en esa clase única de horrores de codificación donde el código más crítico para la misión es también el más aterrador.

MakeMaker es el instalador de la mayoría de los módulos Perl. Cuando ejecuta "Makefile.PL" está invocando MakeMaker. Si MakeMaker se rompe, Perl se rompe. Perl funciona con todo, por lo que MakeMaker tiene que funcionar en todo. Cuando digo todo, me refiero a TODO. Cada extraña variante de Unix. Windows 95 en adelante. Y VMS. Sí, VMS.

¿Qué hace MakeMaker? Makefile.PL es un programa Perl que escribe un Makefile que contiene comandos de shell, que a menudo ejecutan Perl, para construir e instalar un módulo Perl. Permítanme repetir: escribe comandos de shell para ejecutar Perl. Perl, el lenguaje que reemplaza los scripts de shell.

Ah, también puede compilar y vincular el código C. Y también puede vincular estáticamente módulos de Perl en Perl. Ah, y puede administrar las cajas de RCS. Ah, y rodar tarballs de su distribución ... y archivos zip. Y haz todo esto relacionado vagamente con la instalación de módulos.

Y tiene que hacer todo esto de una manera portátil compatible con versiones anteriores. Tiene que hacer frente a variantes de insectos y en ...

  • maquillaje (make de GNU, BSD hacer, nmake, dmake, mms, MMK para nombrar unos pocos)
  • shell
  • Perl
  • el sistema de archivos (si usted no cree que eso es un gran problema, intente VMS)
  • compiladores de C & enlazadores

Es absoluta y positivamente no puede fallar y debe seguir siendo 100% backw ards compatibles.

Ah, y tiene muy poco en la forma de un API de extensión real, por lo que tiene que seguir siendo compatible con ad hoc Makefile hackery la gente tiene que hacer para extenderla.

¿Por qué hace todo esto? Hace 15 años, cuando sólo se corrió Perl en Unix esto parecía una gran idea. ¿Por qué escribir un sistema de construcción completo cuando puedes usar make? Perl es un lenguaje de procesamiento de texto; ¡lo usaremos para escribir un Makefile!

Afortunadamente hay un reemplazo, Module::Build, y anhelaba mi esperanza de que matara rápidamente a MakeMaker. Pero su aceptación ha sido lenta y la comunidad muy resistente al cambio, así que estoy atascado manteniendo MakeMaker.

1

Estoy manteniendo una aplicación web de programación que utilizamos en nuestra intranet. Cuando me preguntaron si podía eliminar un agente del programador, pensé, seguro por qué no. Cuando eché un vistazo al código fuente, descubrí que cada hora del día de este agente estaba codificada por separado. Así que todos los días de su semana. Y así fue cada semana de cada agente de esta región. Y así fue cada región de alrededor de 5 regiones. Html fies que contienen asp-code por todos lados.

Un día me tomé un tiempo para adivinar cuántas líneas de código hay en estos diversos archivos y estimé aproximadamente 300000. Trescientos mil líneas de código de una vez escritas a mano y luego copiadas y pegadas.

Pero este número convenció a mi gerente con bastante rapidez de que necesitaríamos una nueva aplicación de programación muy rápidamente.

12

¿Cuál es el programa más erróneo que has tenido que mantener?

¡Todo lo que alguna vez escribí!

En serio. Cuanto más leo blogs, escucho podcasts y sigo sitios como este, más aprendo todos los días. Y cada día, básicamente, me doy cuenta de que todo lo que escribí ayer está mal de alguna manera. Siento por los pobres que mantienen las cosas que escribí al principio de mi carrera.

+3

Oh, yo también. Pero hay una diferencia de categoría entre el código incorrecto y el código que es fundamentalmente horrible. Se necesita más que inexperiencia para escribir ese tipo de código; toma enormes cantidades de autoconfianza injustificada. –

2

Solía ​​ser un programador de COBOL (estremecimiento). Todo nuestro código cayó en la categoría "incorrecto". En COBOL, no tiene espacios de nombres, todas las variables son globales y hay una gran cantidad de duplicaciones obligatorias de nombres de archivos y otros recursos. Para invocar un procedimiento, establece variables globales, llama al procedimiento y luego inspecciona los contenidos de esas variables globales (u otras que puedan establecerse).

Lo peor, sin embargo, fue mantener un programa COBOL escrito antes de que naciera (nací en 1967) y su método exclusivo de control de flujo fue el GOTO. Fue un desastre absoluto e imposible de seguir. Los cambios menores en un tipo de variable pueden tardar días en resolverse. No hubo pruebas automáticas y los planes de prueba manuales nunca se guardaron, por lo que cada cambio requería que se escribiera un nuevo plan de prueba manual, seguido exhaustivamente y entregado con el código.

Irónicamente, esto es lo que hace que COBOL tenga tanto éxito. COBOL a menudo se ejecuta mediante Job Control Language (JCL). Como COBOL es tan débil, los programas no hacen mucho, por lo que JCL asignaría algo de espacio en el disco (a menudo hasta el nivel del cilindro), y ejecutaría un pequeño programa COBOL para leer datos y luego escribir solo los datos que necesita. Entonces JCL podría llamar a un programa de clasificación para ordenar el archivo resultante. Luego, se llamaría a otro programa COBOL para que lea el archivo ordenado, resuma los datos y tal vez vuelva a extraer los resultados necesarios. Y quizás JCL se usaría nuevamente para mover el archivo a otro lugar, y otro programa COBOL sería llamado para leer los resultados y almacenarlos en una base de datos, y así sucesivamente. Cada programa de COBOL tendía a hacer solo una cosa y se creaba una versión primitiva del modelo de oleoducto de Unix, todo porque COBOL es demasiado difícil de mantener o se puede complicar. Tuvimos un acoplamiento débil y una estrecha cohesión (entre programas, no en ellos) porque era casi imposible escribir COBOL de otra manera.

0

Mantenimiento de aplicaciones ASP para una empresa específica que contrata desarrolladores para mantener sus contrataciones anteriores ... Todas estas aplicaciones no están documentadas, ni hay ningún comentario.

Cada función se copia y pega en cada página ASP. Así que no hay funciones definidas o cualquier cosa ... Todos los días estoy paralizado por sus entornos, porque primero tengo que desconectarme a un servidor, para eludir el DMZ. Después de eso tengo que ir a un servidor de producción donde tengo que hacer los cambios.

5

Una vez tuve que mantener una aplicación C heredada que había sido escrita y mantenida previamente por algunos programadores que habían perdido la voluntad de programar (y posiblemente vivir). Tenía demasiados WTF para mencionar, pero recuerdo una función booleana que en varios casos especiales devolvería TRUE + 1, TRUE + 2, etc.

Luego leí Roedy Green's essay y me reí mucho, hasta que me di cuenta de que La razón por la que me pareció gracioso fue que reconocí la mayoría de los ejemplos del código que mantenía. (Ese ensayo se ha vuelto un poco hinchado durante años de adiciones, pero aún vale la pena mirarlo)

0

Una vez me llamaron para ayudarme a rastrear un bloqueo periódico en un lector EDIF. Casi de inmediato comencé a tener dolor de cabeza. El autor original parecía sentir que Yacc lo iba a penalizar por espacio en blanco, y su gramática Yacc era un desastre denso e ilegible. Pasé un par de horas formateándolo, agregando reglas para las terminales que faltaban a medida que aparecían, estructurando las declaraciones para evitar el crecimiento de la pila, y voila, el accidente se extinguió.

Recuerde, por cada vez que espera mientras Yacc procesa su gramática, habrá miles de ejecuciones con el analizador generado. ¡No seas barato con el espacio en blanco!

0

Todo lo que he escrito se supone originalmente que es un prototipo rápido y termina quedándose por un tiempo. Mi dominio de problema requiere una gran cantidad de prototipos desechables por su naturaleza. Para estos prototipos, a veces es razonable violar todas las mejores prácticas y las reglas del buen estilo, solo hazlo y limpia después si el prototipo termina siendo útil. Sin embargo, ocasionalmente estos prototipos terminan siendo muy difíciles de funcionar correctamente, pero luego terminan siendo guardianes. En estos casos, suelo posponer la refacturación/reescritura indefinida porque me temo que nunca volveré a ponerla en funcionamiento. Disminuyendo aún más mi motivación es que mi jefe es un experto en el dominio que no programa en absoluto.

1

Un sistema de gestión de contactos en línea PHP/MySQL, donde la tabla de contactos no tenía una clave natural. Hubo numerosas instancias de campos de base de datos que contenían datos compuestos en la forma de una cadena delimitada que posteriormente necesitaba ser analizada por el código de la aplicación.

El HTML y la lógica se entrelazaron, casi no se usaron funciones, sino que el código se cortó y se pegó en docenas de archivos de código fuente. Los datos no se desinfectaron y, por lo tanto, los campos con (por ejemplo) pestañas verticales incrustadas causaron un mal funcionamiento del XML devuelto por las llamadas Ajax y, para colmo, archivos con docenas o cientos de declaraciones vacías que consisten en cerrar llaves inmediatamente seguidas de punto y coma : "};"

0

El intérprete para un lenguaje de procesamiento de geometría CAD/CAM (P1 = 10,10; P2 = 20,20; L1 = P1, P2; - ese tipo de cosas), escrito en Microsoft BASIC Professional Development System (PDS) , con nombres de variables de longitud mínima (se agotó rápidamente, por lo que pasó a letras dobles PP, PQ, PR, ¿alguien?). Y, para ser justos, algunos comentarios. En italiano.

Curiosamente, lo que realmente trabajadas, y yo era capaz de añadir alguna funcionalidad a ella, pero era como la odontología aficionado - doloroso, y, ciertamente, no se recomienda ...

2

Nada más sacarlo de la escuela de posgrado en Lucent I recibió un compilador e intérprete para mantener, escrito en PL/I.El lenguaje que se compilaba describía un conjunto complejo de restricciones de integridad, y el intérprete las aplicaba a un gran conjunto de datos que luego se formaría en la base de datos inicial que controla el conmutador 4ESS. El 4ESS era, y sigue siendo, un interruptor de circuito para el tráfico de voz de larga distancia.

El código era un revoltijo. Había una etiqueta para ramificar llamada "NORTH40". Le pregunté al desarrollador original qué significaba.

"Ahí es donde se realizan los controles de rango, ya sabes, los controles para asegurarse de que cada campo tenga un valor correcto".

"¿Pero por qué 'NORTH40'?"

"Usted sabe, 'Hogar, hogar en el campo.'"

"¿Eh?"

Resultó 'NORTH40' significaba una granja de 40 acres en el norte, que en su mente criada en la ciudad tenía una conexión oscura con un rancho ganadero.

Otro módulo tenía dos matrices en paralelo llamadas TORY y DIREC, que se actualizaron en paralelo y, por lo tanto, fueron un intento obviamente erróneo de modelar una única matriz que contiene pares de datos. No pude descifrar los nombres y le pregunté al desarrollador. Resultó que estaban destinados a leerse juntos: "directivo". Estupendo.

Los pobres que tenían que escribir las restricciones de integridad no tenían un manual de usuario para guiarlos, solo una tradición oral más notas escritas a mano. Peor aún, el compilador no realizaba la comprobación de la sintaxis, y muy a menudo terminaban especificando una restricción que se asignaba silenciosamente a la lógica incorrecta, a menudo con muy malas consecuencias.

Peor estaba por venir. Mientras profundizaba en las entrañas del intérprete, descubrí que se había construido en torno a un proceso de clasificación gigante. Antes, el género era un proceso de entrada que generaba los datos de entrada de clasificación de los datos sin procesar y las restricciones de integridad. Por lo tanto, si tuviera una tabla con 5.000 definiciones de troncales y cada registro de troncal tuviera tres valores de campo únicos en todo el conjunto de datos de entrada, el proceso de entrada crearía 3 * 5.000 = 15.000 registros de entrada de clasificación, cada uno en bruto registro de datos prefijado por el número de restricción de integridad y una copia del valor de campo para ordenar. En lugar de hacer tres mil 5,000 géneros de registro, hizo una clasificación de 15,000 registros. En el momento en que incluyó cientos de restricciones de integridad intra e inter-tabla, y algunas tablas muy grandes, tuvo una pesadilla combinatoria.

Pude refactorizar un poco, documentar el idioma y agregar la verificación de sintaxis con mensajes de error comprensibles, pero unos meses más tarde salté a una transferencia a un nuevo grupo.

1

vez trabajé en una aplicación CAD escrito en BASIC, donde la política de la empresa es que cada programa debe comenzar con la declaración:

al reanudar

JMM

+0

¿de qué sirve? :PAG –

Cuestiones relacionadas