domingo, 11 de julio de 2004

Mejorar como desarrolladores

En el pasado he tocado varios temas: requerimientos, productividad, procesos, estándares, desarrollo agil. Todos estos temas son trascendentes cuando uno habla de desarrollo de software y piensa constantemente en mejorar. Pero, ¡el software es código! Ya es hora de pensar en el código que escribimos y elevar nuestros estandares en ese sentido.

¿Es realmente bueno el código que escribimos? Pensemos en la respuesta con criterio profesional y sin ligereza. ¿A qué me refiero?

Recorda la última vez que pediste una opinión sobre una película a un amigo o pariente. Posiblemente obtuviste una respuesta como: “No me gustó. Es un desastre.” o algo que suena mejor como “Mmm, es medio lenta pero con buena fotografía.” La mención de la fotografía pretende darle un toque sofisticado al comentario aunque no signifique para el neófito otra cosa que hay alguna toma de lindos paisajes en la película.

Usualmente no esperamos más que esto de un amigo o un pariente porque es suficiente para saber si voy a ver la película el sábado en el cine o un domingo a la tarde dentro de 3 años cuando la pasen por televisión abierta. Sin embargo este tipo de comentarios no es lo que esperamos de una crítica en una revista especializada. El crítico de cine observará otros detalles, comparara el trabajo de actores y directores con sus obras anteriores, analizará los personajes y los recursos utilizados para contar la historia, evaluará la reconstrucción del contexto histórico, rescatará la profundidad de los diálogos, etc.

De la misma manera, para criticar nuestro trabajo o el de otros no podemos decir “Este código es un desastre” o “Bah, anda mas o menos bien” con la liviandad de una charla de café en el bar de la esquina. Para mejorar nuestro código debemos conocer los conceptos que permitan evaluarlo críticamente. Debemos poder analizar el impacto de las dependencias, detectar el acoplamiento y la falta de cohesión, conocer maneras de mejorar su estructura, saber de patrones de diseño y saber encontrar el equilibrio entre la elegancia y la simplicidad de un diseño.

Es aquí cuando el camino hacia la mejora comienza a ganar nitidez y entendemos que aprender a programar con Struts o a usar Remoting en .NET no nos hace mejores desarrolladores. Conocer el entorno y las herramientas de trabajo siempre es útil y hacen una diferencia. Adquirirlo es parte del trabajo que debe hacer un desarrollador profesional. Pero personalmente no pienso que esto haga un aporte esencial para ser un mejor desarrollador.

¿Qué es lo que diferencia un desarrollador excelente de uno regular? ¿Qué podemos hacer para acortar la brecha? Debemos pensar en lo hacemos constantemente.
Dave Thomas y Andrew Hunt escriben en The Pragmatic Programmer: From Journeyman to Master:
“...te estamos desafiando a que pienses en lo que estas haciendo mientras lo haces. Esto no es una auditoria única de las prácticas actuales... es una evaluación crítica constante de cada decisión que tomas, cada día, y en cada desarrollo. Nunca corras en piloto automático. Piensa y critica constantemente tu trabajo en tiempo real.”

Coincidiendo con esta postura, Kent Beck ha dicho que él no es un gran programador sino un programador con grandes hábitos. Una manera de mejorar es suprimir los malos hábitos cuando desarrollamos y comenzar a adquirir los buenos, aquellos que aplican los grandes desarrolladores. Veamos algunos:

Aplicar Test Driven Development (TDD)


Personalmente pienso que la aplicación de TDD ha sido mi mejora como desarrollador más significativa en el último par de años. Si no sabes de qué se trata podes leer el artículo Test Infected como introducción.

Esencialmente al aplicar TDD escribimos las pruebas de unidad antes de implementar un módulo por lo que contamos con la prueba que demuestra que nuestro código funciona. Este es un salto enorme para el desarrollo de software. Voy a repetir el concepto porque es brillante. Estamos diciendo que, aplicando esta práctica, como desarrolladores estamos obligados a demostrar que el código que escribimos *funciona*. Esto es importante porque una parte significativa de nuestro trabajo como desarrolladores es, precisamente, escribir código que funcione. Hoy considero como un requerimiento básico la existencia de una prueba de unidad que verifique la funcionalidad de cualquier modulo que escribo en cualquier lenguaje.

Los beneficios de aplicar TDD no tienen que ver únicamente con el hecho de contar con pruebas unitarias automatizadas para todo el código que escribimos. Como las pruebas requieren de módulos sin acoplamiento y con responsabilidades bien definidas, el diseño de la aplicación se ve mejorado notablemente. También las pruebas juegan un rol importante como documentación porque su código es un ejemplo del uso de las clases.

Comenzar a desarrollar de esta manera es difícil al principio y en varias situaciones escribir las pruebas unitarias antes que el código es una tarea particularmente complicada. Pero los beneficios son tremendos. La diferencia entre dos desarrolladores es marcada cuando uno aplica TDD y otro no. Si no estas aplicando TDD, tenes una oportunidad excelente para mejorar notablemente como desarrollador. Además de toda la información disponible en la web referida al tema, ya existen varios libros al respecto. Kent Beck escribió Test Driven Development: By Example y es apropiado para introducirse al tema. En http://www.xprogramming.com/software.htm Ron Jeffries mantiene una lista de herramientas que permiten escribir y ejecutar pruebas de unidad para todo tipo de lenguaje y entorno de desarrollo.

Aplicar Refactoring

Cualquier persona que haya escrito código para alguna aplicación medianamente exitosa (en términos de vida útil al menos) se ha encontrado en la situación de tener que extender su código y pensar que hubiera sido mejor tomar decisiones de diseño distintas en el pasado para facilitar el tipo de cambios que se tiene entre manos. El problema es que uno no quiere modificar algo que está funcionando, entonces prefiere dejar las cosas como están y buscar la manera de implementar la extensión (aunque se parezca mucho a un “parche”). Es evidente que poco a poco esto degrada el diseño y será cada vez más difícil extender o modificar nuestra aplicación.

Cuando uno tiene un conjunto de pruebas unitarias extensivas que actúan como red de seguridad para hacer cambios, las mejoras en el diseño pueden ser realizadas sin temor. Entonces podemos evaluar constantemente el diseño del código, asegurándonos que es el más adecuado para los requerimientos actuales, y hacer las modificaciones que consideremos necesarias de manera disciplinada.

Esto es refactoring, la mejora disciplinada de la estructura interna del código existente sin afectar su comportamiento.
Varios entornos de desarrollo han comenzado a dar soporte extensivo a esta práctica. IntelliJ IDEA, Eclipse y Borland JBuilder incorporan funcionalidad que nos permiten realizar modificaciones de este tipo con un par de clics. Microsoft también incorpora algo similar en Visual Studio 2005 (en sus versiones Beta).

Sin embargo, el soporte de una herramienta para hacer cambios que mejoren la estructura interna del código es una pequeña parte de lo que necesitamos para sacarle provecho al refactoring. También tenemos que saber cuando aplicar estos cambios y como hacerlo de manera disciplinada. El libro de Martin Fowler Refactoring: Improving the Design of Existing Code es el material de referencia por excelencia en este tema. En http://www.refactoring.com, Martin Fowler mantiene un catálogo de maneras de aplicar refactoring. Esta es otra práctica que nos hace mejorar notablemente como desarrolladores porque nos permite mejorar nuestro código constantemente, para que siempre conserve su simpleza, flexibilidad y extensibilidad.

Estudiar, leer y aplicar diseño orientado a objetos


Desde hace un tiempo estoy dictando cursos sobre desarrollo de aplicaciones Web con C# y he podido detectar algunas tendencias en los desarrolladores que han asistido a los cursos. Los desarrolladores conocen los conceptos básicos de orientación a objetos: clases, instancias, herencia, polimorfismo; pero no saben aplicarlos para diseñar e implementar una aplicación. Leer sobre el diseño orientado a objetos puede ser de gran ayuda para mejorar porque comenzamos a ver de manera distinta lo que hacemos.

No escribiremos un método en un formulario que se encargue de validar los datos ingresados, mostrar mensajes de validación al usuario, conectarse a una base de datos, armar una sentencia SQL, ejecutarla y tratar los posibles errores de base de datos que se puedan dar. Tal vez esta sea la manera más rápida de implementar la funcionalidad pero sabemos que tendríamos una clase con baja cohesión y que seguramente tendríamos código duplicado. Cuando comenzamos a entender más las características de un buen diseño orientado a objetos estamos más cerca de poder alcanzarlas.

De todo el material que he leído al respecto dos libros me han ayudado de manera más marcada a entender el diseño orientado a objetos. Uno es Design Pattern: Elements of Reusable Object-Oriented Software de Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides. Cuando leí el ejemplo del primer capítulo del libro me sucedió lo que los americanos llaman “ah ha moments”. Por primera vez percibí las posibilidades de un buen diseño orientado a objetos, que iba mucho más allá de lo que yo podía pensar hasta ese momento.

El segundo es Agile Software Development: Principles, Patterns and Practices de Robert C. Martin. Posiblemente sea el libro que, a mi entender, mejor reúne y resume los conocimientos de orientación a objetos básicos y no tanto indispensables para cualquier desarrollador. Y como gran adepto a todo lo que escribe Robert Martin, no puedo dejar de mencionar sus artículos en http://www.objectmentor.com. Material sin desperdicio. No tengo dudas que estas lecturas nos dan los conocimientos para mejorar nuestro código.

Estas son algunas maneras de incrementar conocimientos, mejorar como profesionales y me animo a decir hacer más divertido nuestro trabajo.

En algunas oportunidades algunos conocidos me han mencionado el aburrimiento que les produce trabajar durante mucho tiempo con las mismas herramientas (Visual Basic por ejemplo). La necesidad de aprender una nueva tecnología o un nuevo lenguaje los motiva de una manera que un lenguaje que manejan hace años no puede hacerlo.

Pienso que existe otro camino: elevar nuestros estándares. Proponernos seriamente que nuestro código sea excelente, simple, claro, sin errores, fácil de mantener y extender, y hacerlo en tiempos mínimos. Prescindir de excusas (“Ah, en esta parte no capturo las excepciones porque teníamos un dead line y después me olvide de hacerlo”). Escribir código del que estemos orgullosos, que tengamos ganas de mostrarlo a nuestros colegas y amigos.

Este es un desafío definitivamente motivante.