¿Cuál puede ser la causa de que aparezcan nuevos errores en otra parte cuando se resuelve un error conocido?

13

Durante una discusión, uno de mis colegas dijo que tiene algunas dificultades con su proyecto actual al intentar resolver errores. "Cuando soluciono un error, otra cosa deja de funcionar en otro lugar", dijo.

Comencé a pensar en cómo podría suceder esto, pero no puedo resolverlo.

  • A veces tengo problemas similares cuando estoy demasiado cansado / cansado para hacer el trabajo correctamente y para tener una visión general de la parte del código en el que estaba trabajando. Aquí, el problema parece ser por unos días o semanas, y no está relacionado con el enfoque de mi colega.
  • También puedo imaginar que este problema surja en un proyecto muy grande, muy mal administrado , donde los compañeros de equipo no tienen idea de quién hace qué, y qué efecto en el trabajo de otros puede tener un cambio. Ellos están haciendo. Este no es el caso aquí tampoco: es un proyecto bastante pequeño con un solo desarrollador.
  • También puede ser un problema con base de código antigua, mal mantenida y nunca documentada , donde los únicos desarrolladores que realmente pueden imaginar las consecuencias de un cambio habían dejado la compañía hace años. Aquí, el proyecto acaba de comenzar y el desarrollador no usa el código base de nadie.

Entonces, ¿cuál puede ser la causa de tal problema en una base de código nueva y de pequeño tamaño escrita por un solo desarrollador que se mantiene enfocado en su trabajo ?

¿Qué puede ayudar?

  • Pruebas unitarias (no hay ninguna)?
  • Arquitectura adecuada (estoy bastante seguro de que el código base no tiene ninguna arquitectura y fue escrito sin un pensamiento preliminar), ¿se requiere la refactorización completa?
  • ¿Programación de pares?
  • ¿Algo más?
pregunta Arseni Mourzenko 09.12.2011 - 18:39

10 respuestas

37

No tiene mucho que ver con el enfoque, el tamaño del proyecto, la documentación u otros problemas del proceso. Problemas como ese son generalmente el resultado de un excesivo acoplamiento en el diseño, lo que hace que sea muy difícil aislar los cambios .

    
respondido por el Karl Bielefeldt 09.12.2011 - 18:49
13

Una de las causas puede ser el acoplamiento estrecho entre los componentes de su software: si no hay interfaces simples y bien definidas entre los componentes, incluso un pequeño cambio en una parte del código puede introduzca efectos secundarios inesperados en otras partes del código.

Como ejemplo, últimamente estaba trabajando en una clase que implementa un componente GUI en mi aplicación. Durante semanas se informaron nuevos errores, los reparé y aparecieron nuevos errores en otra parte. Me di cuenta de que esa clase había crecido demasiado, estaba haciendo demasiadas cosas y muchos métodos dependían de que otros métodos fueran llamados en la secuencia correcta para funcionar correctamente.

En lugar de corregir los últimos tres errores, hice una fuerte refactorización: dividí el componente en una clase principal más clases MVC (tres clases adicionales). De esta manera, tuve que dividir el código en partes más pequeñas y simples y definir interfaces más claras. Después de la refactorización, todos los errores se resolvieron y no se informaron nuevos errores.

    
respondido por el Giorgio 09.12.2011 - 18:54
7

Es fácil para un error enmascarar a otro. Supongamos que el error "A" hace que se llame a la función incorrecta para manejar la entrada. Cuando se corrige el error "A", de repente se llama a la función correcta, que nunca se ha probado.

    
respondido por el ddyer 09.12.2011 - 18:52
5

Bueno, la causa inmediata son dos errores que hacen un bien, o al menos que hacen un no-obviamente-mal. Una parte del código está compensando el comportamiento incorrecto de la otra parte. O si la primera parte no está "mal" como tal, hay un acuerdo no escrito entre las dos partes que se está violando cuando se cambia el código.

Por ejemplo, supongamos que las funciones A y B usan una convención basada en cero para alguna cantidad, de modo que funcionen juntas correctamente, pero C usa una, podría "arreglar" A para trabajar con C y luego descubrir un problema con B.

El problema más profundo es la falta de verificación independiente de la corrección de las partes individuales. Las pruebas unitarias están diseñadas para abordar esto. También actúan como una especificación de las entradas adecuadas. P.ej. un buen conjunto de pruebas dejaría en claro que las funciones A y B esperaban una entrada basada en 0 y una basada en C 1.

Hacer las especificaciones correctas también se puede hacer de otras maneras, desde documentos oficiales hasta buenos comentarios en el código, según las necesidades del proyecto. La clave es comprender qué espera cada componente y qué promete, para que pueda encontrar inconsistencias.

La buena arquitectura ayuda con el problema de entender el código, facilitando esto. La programación de pares es útil para evitar errores en primer lugar, o para encontrarlos más rápidamente.

Espero que esto ayude.

    
respondido por el Mike B 09.12.2011 - 18:56
5

El acoplamiento apretado, la falta de pruebas, estos son probablemente los culpables más comunes. Básicamente, el problema común es simplemente normas y procedimientos de mala calidad. Otro es el código incorrecto que logra tener suerte durante un tiempo con el comportamiento correcto. Considere memcpy bug de Linus Torvalds donde cambiar su implementación expuso (no causó) errores en clientes que usaron memcpy en lugares donde deberían haber usado memmove con una fuente y destino superpuestos.

    
respondido por el user204677 15.01.2016 - 15:47
4

Parece que estos "nuevos" errores no son realmente "nuevos" errores. Simplemente no fueron un problema, hasta que el otro código que se rompió, en realidad fue arreglado. En otras palabras, su colega no se da cuenta de que en realidad tuvo dos errores todo el tiempo. Si el código que no está demostrando que está roto no se rompió, no habría fallado, una vez que la otra parte del código haya sido reparada.

En ambos casos, un mejor régimen de prueba automatizado podría ser útil. Parece que su colega necesita realizar una prueba unitaria del código base actual. En el futuro, las pruebas de regresión verificarán que el código existente continúa funcionando.

    
respondido por el Ramhound 09.12.2011 - 21:26
0

Mejore la amplitud de su régimen de prueba automatizado. SIEMPRE ejecute el conjunto completo de pruebas antes de confirmar los cambios de código. De esa manera, detectará el efecto pernicioso de sus cambios.

    
respondido por el Stephen Gross 09.12.2011 - 18:51
0

Acabo de encontrar esto cuando una prueba fue incorrecta. La prueba verificó un estado de permiso dado que era correcto. Actualicé el código y ejecuté la prueba de permisos. Funcionó. Entonces me hice todas las pruebas. Todas las otras pruebas que utilizaron el recurso verificado fallaron. Corrigí la prueba y la verificación de permisos, pero al principio hubo un poco de pánico.

Las especificaciones inconsistentes también ocurren. Entonces es casi seguro que corregir un error creará otro (emocionante cuando esa parte particular de la especificación no se ejerce hasta más adelante en el proyecto).

    
respondido por el ccoakley 09.12.2011 - 19:30
0

Imagina que tienes un producto completo. Luego agrega algo nuevo, todo parece estar bien, pero rompió algo más, que depende de algún código que cambie para que la nueva característica funcione. Incluso si no cambia ningún código, solo agrega funcionalidad a la existente, podría romper algo más.

Básicamente, casi te contestas a ti mismo:

  • acoplamiento suelto
  • falta de pruebas

Simplemente aprenda a adaptar el principio TDD (al menos para las nuevas funciones) e intente probar cada estado posible que pueda suceder.

La programación de pares es excelente, pero no siempre está "disponible" (tiempo, dinero, ambos ..). Pero las revisiones de códigos (por sus colegas, por ejemplo) una vez al día / semana / conjunto de confirmaciones también serán de gran ayuda, especialmente cuando la revisión incluye el conjunto de pruebas. (Me resulta difícil no escribir errores en las suites de prueba ... a veces debo probar la prueba internamente (comprobación de validez) :)).

    
respondido por el Dalibor Filus 09.12.2011 - 22:18
0

Digamos que el desarrollador A escribió un código con un error. El código no hace exactamente lo que se supone que debe hacer, sino algo ligeramente diferente. El Desarrollador B escribió un código que se basó en que el código de A hace exactamente lo que se espera que haga, y el código de B no funciona. B investiga, encuentra el comportamiento incorrecto en el código de A y lo arregla.

Mientras tanto, el código del desarrollador C solo funcionó correctamente porque se basó en el comportamiento incorrecto del código de A. El código de A es ahora correcto. Y el código de C deja de funcionar. Lo que significa que cuando arregla el código, debe comprobar con mucho cuidado quién usa este código y cómo cambiará su comportamiento con el código fijo.

He tenido otra situación: algunos códigos se comportaron mal y dejaron de funcionar correctamente una característica en alguna situación X. Así que cambié la mala conducta e hice que la característica funcionara. El desafortunado efecto secundario fue que toda la característica tenía problemas significativos en la situación X y fallaba por todas partes, esto era completamente desconocido para cualquiera porque la situación nunca había ocurrido antes. Bueno, eso es duro.

    
respondido por el gnasher729 04.02.2018 - 00:10

Lea otras preguntas en las etiquetas