Asterisco¿Qué es lo importante al momento de encarar un desarrollo ágil de software? Keith Swenson nos deja una compilación de 26 consejos que recolectó durante los años, sobre diversos temas. 

 26 consejos para el desarrollo de software

  1. Hacer que el Caso 1 funcione completamente antes de empezar el Caso 2. Otra forma de decir lo mismo usando una metáfora con la cocina: "Serví el almuerzo antes de preparar la cena". Uno de los mayores problemas del desarrollo de software es comenzar un montón de cosas en paralelo: inevitablmente el trabajo incluirá cosas que serán descartadas más tarde, con el consiguiente esfuerzo desperdiciado. Trabajá en un caso por vez; hacé que funcione completamente; hacé que todos sus pruebas pasen con éxito; escribí la documentación; verificá que sea una pieza de trabajo terminada antes de empezar con la siguiente.
  2. Nunca romper la construcción. Bastante obvio, pero tiene que estar incluido en cualquier lista de consejos para el desarrollo de software. Un programador que toma todas las precauciones de probar antes de subir los fuentes al repositorio nunca podrá romper una construcción. Si la construcción se rompe, siempre es porque tomamos algún atajo.
  3. Nunca implementar una rutina antes que sea requerida por algún caso de uso. Cuando se está implementando una clase en particular, debemos tener en mente un caso de uso específico, y sólo debemos implementar los métodos que necesita dicho caso. Podemos pensar en el potencial de otras características en la clase, y podemos documentarlo como un comentario, pero la implementación debería esperar hasta que sea realmente necesaria en algún caso de uso.
  4. Nunca agregar un dato antes de que sea requerido por algún caso de uso. Similar al concepto anterior, refiriéndonos a datos de una clase. Podría parecer obvio que el registro de "cliente" va a necesitar una "dirección de envio", pero esa dirección no debería implementarse hasta que algún caso de uso lo indique específicamente.
  5. No tener miedo a tomar decisiones; no tener miedo a cambiar una decisión temprana. El desarrollo Ágil trata sobre responder al cambio y a la incertidumbre de manera rápida. Cuando empezamos el desarrollo no tenemos información completa. Debemos demorar las decisiones lo más posible, pero llega el momento en el que es necesario tomar una decisión para seguir avanzando. No podemos demorar la decisión esperando que aparezca la información. En cambio, tomamos la mejor decisión con la información disponible. Más tarde, cuando aparezca nueva información, no debemos tener miedo de cambiar la decisión (algunos dinosaurios lo llaman "ser una veleta", yo lo llamo reaccionar a un entorno cambiante).
  6. Aprender continuamente sobre cómo mejorar la calidad. Esta es una actividad que no termina nunca, así que debemos esperar estar continuamente buscando cosas a mejorar, y recolectando ejemplos de formas en las que se identificaron y resolvieron problemas de calidad.
  7. Medir, medir, medir. El desarrollo Ágil ayuda a resolver el problema de la incertidumbre del futuro, pero no debería haber incertidumbre sobre el pasado. Las pruebas deberían funcionar continuamente. El rendimiento de cada ejecución debería medirse y registrarse.
  8. Diseñar pensando en las personas, no en los sistemas. A menudo los desarrolladores crean diseños pensando en las oportunidades técnicas. Nunca debemos perder el foco sobre el propósito del software, que es ayudar a las personas a hacer su trabajo.
  9. Las pruebas son parte del producto. Muchos desarrolladores y gerentes piensan que el producto es lo que se le entrega al cliente, y todo el resto es menos importante. Las pruebas deben considerarse como parte del producto, y recibir atención completa al momento de diseño, e incluso en muchos casos, deben entregarse junto al producto al cliente.
  10. Escribir las pruebas antes del código. Las pruebas pueden usarse para clarificar el diseño sobre lo que se necesita exactamente. Muchas veces hay fallas en el diseño que se descubren cuando se trabaja sobre los casos de prueba. Piensen en cuánto se ahorraría al trabajar en estos casos antes de construir. Pero: escriban la prueba para el Caso 1 y codifiquen el Caso 1 antes de empezar con el Caso 2.
  11. Eliminar el desperdicio. Este es otro consejo clásico que no puede faltar en una lista sobre el desarrollo de software. Y es muy importante. Siempre debemos estar buscando desperdicios y eliminándolos; es una tarea que no tiene fin. Debemos eliminar todo lo que no le agregue valor al cliente. Si en alguna actividad no podemos identificar el valor que le entrega al cliente, es probable que no la necesitemos.
  12. Construir una cultura de respuesta inmediata ante una construcción fallida. Debemos comprender que cuando una construcción falla, afecta a todos en el proyecto, y por lo tanto no hay nada más importante que asegurarse que el código central se construya y pruebe apropiadamente. Conozco equipos que dejan pruebas fallidas durante meses porque "era el trabajo de otro". Todos lo padecen, pero nadie actua. En cambio, se necesita un reconocimiento completo que ese pequeño trabajo será una inversión que recuperaremos con creces en el tiempo.
  13. Cada miembro del equipo necesita comprender las necesidades del cliente. Los proyectos grandes y complejos tienen que dividirse en equipos separados y dividirse más para asginarlo a desarrolladores, pero nunca debe hacerse al punto de que las personas pierdan de vista las motivaciones y objetivos de los usuarios con el producto final.
  14. Mantener juntas las definiciones relacionadas. Hay que estructurar al código de manera que las cosas muy relacionadas se ubiquen juntas, posiblemente dentro de la misma clase. Este es un principio básico del diseño orientado a objetos, llamado encapsulamiento. Idealmente, todo el código fuera de la clase no necesitará saber los detalles de funcionamiento interno. A algunos desarrolladores les encanta distribuir los detalles en múltiples archivos para organizarlos de otra manera: como ser, mantener todos los tipos de datos juntos, u organizados alfabéticamente. Por ejemplo, una forma bastante común de agregar complejidad innecesaria al programa es ubicar toda las constantes en una clase de un paquete diferente en donde se usan . La regla general debería ser la de agrupar las cosas relacionadas con el objetivo de ocultar complejidad.
  15. Siempre ejecutar las pruebas antes de subir los fuentes al repositorio. Esta regla ayuda a satisfacer el consejo de "nunca romper una construcción".
  16. La optimización prematura es la causa de todos los males. Es una frase de Don Knuth que todavía es cierta hoy en día. El código debe escribirse bien para evitar desperdicios innecesarios al micro nivel, pero la optimización más allá del método individual debería esperar hasta que se pruebe el programa completo con pruebas de estrés en un caso de uso real. La intuición sobre "lo qué es importante para el rendimiento general" es casi siempre equivocada cuando sólo nos basamos en nuestro análisis del código estático. En cambio, debemos medir el comportamiento del sistema completo, para identificar ese 1% del código que realmente hace una diferencia en el rendimiento, y enfocarnos ahí.
  17. Minimizar el backlog de tareas de codificación incompletas. Cuando un desarrollador comienza a trabajar en un caso de uso, existe un costo asociado con todo el código que está siendo modificado, pero todavía no está terminado ni probado. Se agrega un riesgo importante de desperdicio por retrabajo cuando se mantienen cambios incompletos durante días o semanas. Consideremos tres tareas estimadas en 1 día cada una. Si empezamos las tres tareas a la vez, y trabajamos en paralelo por tres días, estaremos acumulado 9 "unidades" de costo. Pero si hacemos cada tarea de forma secuencial, completando cada tarea antes de empezar la siguiente, sólo estaremos involucrando 3 "unidades" de costo. Esto no es intuitivo. Nuestra intuición nos dice que ya que estamos ahí, bien podemos hacer las tres cosas a la vez, antes de cerrar el trabajo. Pero el software no es como la construcción de productos físicos. Las tareas cortas, rápidas y completas causan una menor carga cognitiva, y también reducen la probabilidad de que el trabajo incompleto afecte el trabajo incompleto de otra persona.
  18. Nunca sobre-generalizar la funcionalidad. A esto también se lo conoce como "No lo vas a necesitar" (YAGNI - You aren't going to need it). Al codificar una clase en particular, a los programadores les gusta imaginar que con un pequeño cambio la clase podría usarse con otro propósito. Esto está bien si se necesita ese otro propósito en un caso de uso actual, pero usualmente el programador piensa en casos de uso que todavía no fueron inventados, y que de hecho podrían no existir nunca.
  19. Nunca usar 3 líneas cuando alcanza con 2. El código breve siempre ayuda cuando alguien lo tiene que leer. Pero no achiquen el código hastsa el punto que sea dificil de leer. El código pequeño y bien escrito puede ser más facil de mantener y más facil para encontrarle errores. Siempre debemos simplificar lo máximo posible,  y no más.
  20. Nunca jamás medir al código contando las líneas. La cantidad de líneas que se necesitan para una tarea en particular varía mucho entre programadores, y entre distintos estilos. La cantidad de líneas de código no dice nada sobre la completitud o calidad de ese código. La calidad del código puede variar por un factor de 200, y esto sobrepasa cualquier utilidad que pudiera tener la cantidad de líneas. En cambio debemos contar casos de uso que funcionan.
  21. Rediseñar y refactorizar continuamente. Debemos aplicar esto con cuidado porque algunas parte del código puede ser difíciles de cambiar, pero en general no deberíamos tener miedo a cambiar el código para que satisfaga al caso de uso real. Un atributo de una clase puede haber sido un entero en el pasado, pero cuando algún caso de uso necesita que sea un float no debemos estar asustados de cambiarlo.
  22. Borrar el código muerto. Existe una tendencia por dejar "tranquilo al perro dormido" cuando se trata de grandes bloques de código que no se entienden bien. Un ejemplo de esto consiste en agregar un nuevo método a la clase para reemplazar otro: a menudo el desarrollador deja el método viejo "por si las dudas". Se debe aplicar esfuerzo para verificar si se necesita ese método viejo, y borrarlo si no hay evidencia de su utilidad. Otra ofensa peor es comentar bloques de código, y dejar esos bloques comentados en el tiempo. El código comentado debe ser eliminado ni bien las pruebas se ejecutan exitosamente, y siempre antes de subirlo al repositorio de código. Es facil agregar código en cualquier momento, es dificil borrar código. Por lo tanto, cuando nos parezca que algo no se necesita, apliquemos algo de esfuerzo extra para verificar y eliminar el código. Tendremos una base de código más mantenible.
  23. No inventar nuevos lenguajes. A los programadores les encanta crear archivos de texto que hacen que la ejecución sea configurable en tiempo de ejecución. No hay límite para los archivos de configuración que nos permiten cambiar comportamiento sin necesidad de recompilar. La llegada del XML parece haber creado una suerte de "lenguajes de scripting" que le permiten al usuario final "programar funcionalidad" sin necesidad de compilar. El problema con este razonamiento es que la definición precisa del comportamiento de una operación casi nunca se define bien por fuera de la implementación particular, y este tipo de lenguajes de scripting sólo resultan útiles para quienes tienen un conocimiento profundo del cuerpo principal del código. Por lo tanto, los usuarios finales sin conocimiento interno detallado no pueden saber ni anticipar los efectos de una combinación compleja de comandos. Los lenguajes de scripting son útiles y no pueden ser eliminados, pero el diseñador tiene que considerar muy bien cuándo usarlos, y evitar la creación de nuevos lenguajes.
  24. No crear un diseño hasta estar listos para implementar y probar la implementación. Deberiamos tener cierta idea general de lo que estamos haciendo, y una visión de alto nivel de la arquitectura del sistema, pero debemos dejar el diseño detallado y la descripción detallada de las implementaciones hasta que comience la iteración de desarrollo para implementar las pruebas y el código de esa funcionalidad. El diseño detallado debería cubrir sólo lo necesario para tratar el caso de uso actual. Una de las mayores causas de desperdicio en el desarrollo de software es gastar tiempo diseñando cosas que no se necesitan o que luego necesitan rediseñarse.
  25. El software es plástico. A diferencia de la construcción de materiales físicos, el sofware puede cambiarse completamente de forma muy simple. De hecho hay mucha evidencia que muestra que el software es más facil de cambiar que las especificaciones de diseño que lo describen. Más aún, el software comunica el diseño de forma más efectiva que la especificación. Por lo tnato, debemos usar el tiempo para implementar directamente el diseño, de manera que los clientes puedan ver los detalles del diseño. Si nos equivocamos y debemos cambiar el diseño, es más facil cambiar el software que cambiar la especificación. Pero lo más importante, la información sobre lo que quiere el cliente resulta mucho más útil después de que vieron algo funcionando.
  26. Tomarse el tiempo para codificar una descripción completa del problema cuando en el código se detecta e informa situaciones excepcionales. Los programadores suelen ser bastante vagos y tiran excepciones con descripciones superficiales sobre lo que salió mal. Piensan que ellos son los únicos que veran el problema, y que recordarán el significado del problema al leer esa descripción vaga del tema. Pero de hecho, el mayor tiempo de soporte al cliente se gasta debido a reportes de error inexactos o incompletos. Debemos escribir mensajes de error como si estuvieramos explicando la situación a alguien que acaba de entrar al proyecto y no tiene experiencia con el código. De hecho, el cliente y el equipo de soporte al cliente no tienen experiencia con el código.
Traducido de 26 hints for Agile software development, por Keith Swenson.

Inspiración.

"Si tú tienes una manzana y yo tengo una manzana e intercambiamos las manzanas, entonces tanto tú como yo seguiremos teniendo una manzana cada uno. Pero si tú tienes una idea y yo tengo una idea, e intercambiamos las ideas, entonces ambos tendremos dos ideas"

Bernard Shaw