En el libro El programador pragmático , los escritores mencionan la programación por concepto de coincidencia . Explica qué es, por qué se causa, cuáles son los peligros que puede encontrar y se compara con un campo de minas terrestres en una guerra.
¿Alguna vez has visto viejas películas de guerra en blanco y negro? El soldado cansado avanza con cautela fuera de la maleza. Hay un claro por delante: ¿hay minas terrestres o es seguro cruzar? No hay indicios de que sea un campo minado, sin signos, alambre de púas o cráteres. El soldado empuja el suelo delante de él con su bayoneta y sus muecas, esperando una explosión. No hay uno Así que avanza minuciosamente por el campo por un tiempo, empujando y hurgando mientras avanza. Finalmente, convencido de que el campo está a salvo, se endereza y marcha con orgullo hacia adelante, solo para volar en pedazos.
Las sondas iniciales del soldado para las minas no revelaron nada, pero esto fue simplemente afortunado. Fue llevado a una falsa conclusión, con resultados desastrosos.
Como desarrolladores, también trabajamos en campos minados. Hay cientos de trampas esperando para atraparnos cada día. Recordando la historia del soldado, debemos tener cuidado de sacar conclusiones falsas. Deberíamos evitar la programación por coincidencia, confiando en la suerte y los éxitos accidentales, a favor de la programación deliberada ...
Pero no estoy realmente satisfecho con la forma en que describen el problema de "cómo superarlo". Sí, tienes que pensar antes de escribir el código, pero ¿cómo practicar eso? Lo único que puedo pensar es al agregar características a los proyectos de código abierto existentes, donde debe tener conocimiento tanto de "lo que estoy haciendo ahora" como de "cómo funcionan los otros códigos", y no es tan aplicable cuando escribes tus propios proyectos.
EDITAR:
un resumen de tus publicaciones:
- No adivines tu próximo movimiento, prueba que es correcto
- Prueba unitaria y refactorización tanto como sea posible, cuando sea necesario
- Agregue funciones, compile y pruebe a menudo
- Si no puede explicar el código a un novato, probablemente esté programando por coincidencia.
Por cierto, es difícil aceptar una respuesta, es realmente difícil. Todas las respuestas son realmente geniales :)
fuente
Respuestas:
No tiene que pensar con anticipación, simplemente sea muy claro en lo que se hizo y sea muy claro en lo que está haciendo en este momento.
Las subrutinas deben decir lo que hacen, hacer lo que dicen y no tener dependencias ocultas. Entonces, alguien que los llame puede razonar más fácilmente sobre lo que harán.
Evitar el estado global. (Variables, singletons, etc.) Cuanto más tenga que tener en mente para comprender qué hacen las cosas, más difícil será comprender qué se supone que sucederá y encontrar los casos extremos.
Escribir pruebas unitarias. Las pruebas unitarias son excelentes para capturar el comportamiento real del código que acaba de escribir, en lugar del comportamiento ideal que espera encontrar.
Acorte su ciclo de edición / compilación / prueba. Cuando agrega una gran porción de código y prueba mal, entonces las probabilidades son de que se comportará de manera diferente de lo que piensa. Luego lo "arreglas" con algún cambio aleatorio y obtienes la respuesta correcta por el momento, pero no tienes idea de cómo sucedió realmente. Ahora estás programando por coincidencia. Pero cuando agrega 5 líneas y luego prueba, las probabilidades de que obtenga la respuesta correcta porque funciona como cree que funciona son mucho mejores. Puedo decir por experiencia que 5 trozos de 10 líneas cada uno, probados individualmente, son una bestia muy diferente a las 50 líneas de código probadas a la vez.
Refactorizar sin piedad. Muchas veces he visto un refactorizador que hará que mi código sea algo más simple, pero requerirá mucho trabajo que no quería hacer. Después de que comencé a abordar deliberadamente esos refactores como una prioridad, descubrí que generalmente se amortiza en un mes. Pero tenga en cuenta la clave, los refactores en los que me concentro son los que simplifican la vida cotidiana, y no los que cumplen con una estética arbitraria de mejor o más general. Esos refactores con los que he aprendido a ser mucho más cauteloso.
Ninguna de estas cosas requiere una planificación previa. Pero todos hacen que sea más fácil entender su código existente y, por lo tanto, facilitan la implementación de su próximo fragmento de una manera deliberada.
fuente
UNION
que necesitabaUNION ALL
.) Y así sucesivamente.Se reduce a no adivinar . La mayoría de los programadores nuevos lo hacen, pero también he visto veteranos, porque creen que ahorra tiempo de investigación. Algo no funciona, por lo que agrega a
+1
o a-1
, cambia atrue
afalse
o viceversa, reordena algunas declaraciones, agrega o cambia demoras, cambia las prioridades de hilo y otras pequeñas transformaciones, básicamente probando permutaciones aleatorias hasta que funcione.Eso se aplica principalmente a cambiar el código existente, pero también es un factor en el código nuevo, porque nadie realmente comienza desde cero. Siempre está construyendo sobre bibliotecas estándar, sistemas operativos o al menos arquitecturas de procesador.
En otras palabras, no habrá terminado hasta que sepa por qué funciona su solución. El camino que tomas para llegar allí no importa tanto. Incluso las permutaciones aleatorias a veces pueden ser útiles para reducir un error que es difícil de diagnosticar, siempre y cuando se tome el tiempo para preguntarse: "Bien, cambiar de verdadero a falso lo solucionó, pero ¿por qué?"
fuente
El comentario más aterrador que encontré en un programa fue
y da miedo solo porque reconoce que el fragmento de código fue el resultado de la programación por coincidencia .
Para evitar la programación por coincidencia, debe poder explicar (a un compañero de trabajo, usted mismo o un pato de goma ) exactamente qué hace el código y por qué funciona. Las viñetas para programar deliberadamente son en su mayoría ayuda para avanzar hacia ese objetivo de poder explicar el código.
1 Para el contexto, este comentario apareció en el código que maneja los cambios de contexto en un sistema operativo primitivo. El código ya había estado en producción durante varios años cuando lo encontré.
fuente
Para los nuevos programadores, la parte más importante de superar esto es comprender realmente lo que están haciendo.
En muchas áreas, cuando no sabes cómo hacer algo, simplemente vas por prueba y error. Intenta algo; si funciona, genial, si no, prueba con otra cosa.
En la programación, especialmente cuando se usa un lenguaje que tiene el concepto de comportamiento indefinido (como C o C ++), este enfoque simplemente no funciona, porque el éxito ya no es una decisión booleana. Puede tener cosas que "funcionan", que a veces funcionan, que funcionan para algunas entradas pero no para otras.
En ocasiones he enseñado a nuevos programadores, y la tendencia a intentar escribir cosas aleatorias para ver si funciona es común. Escribirían una línea y luego se volverían hacia mí y me preguntarían: "¿Funcionaría de esta manera?" aunque estaba claro que no tenían absolutamente ninguna idea de si podría hacerlo.
La conclusión es que, como nuevo programador, realmente tienes que poder explicar qué hace tu código. Tienes que aprender a leer el código, no solo escribirlo.
(Por supuesto, eso se aplica también a los programadores experimentados, pero mi experiencia aquí ha sido principalmente con nuevos principiantes completos).
fuente
Es demasiado fácil codificar, probar y corregir "en la línea de carreras". Tiene alguna funcionalidad que, dado X e Y, produce Z. ¿Pero qué pasa si X está dañado e Y no está disponible? ¿Qué pasa si no puede generar Z? Tenga constantemente presente lo que puede salir mal y anótelo para el ciclo de prueba.
Mantenga sus rutinas cortas y descriptivas: el mejor código requiere pocos comentarios (si los hay).
Los nombres significativos de métodos, clases y variables contribuyen en gran medida a la legibilidad.
Si encuentra un olor a código, entonces DETÉNGASE. Es poco probable que ese olor desaparezca y un pequeño esfuerzo ahora podría ahorrarle una gran cantidad de dolor más adelante.
Incluya pruebas dentro de su proceso de desarrollo. Yo recomendaría el uso de BDD en lugar de TDD, ya que te obliga a describir lo que pretendes lograr en lugar de depender ciegamente de una serie de pruebas que podrían darte una falsa sensación de seguridad.
Resista el impulso de agregar características geniales adicionales (a menos que sea su propio proyecto favorito). Cualquier código adicional debe ser diseñado, escrito, probado y mantenido. Si no es requerido por el cliente / negocio, corre el riesgo de que esto se convierta en una gran pérdida de recursos.
fuente