viernes, junio 02, 2017

QA no debe encontrar errores.


En equipos de desarrollo, además de las personas que programan, también hay personas que realizan las pruebas a los releases o entregas que realizan los programadores. Es el equipo de QA. Este equipo (como su nombre lo dice "Quality Assurance") se asegura de que el producto entregado por el equipo de desarrollo esté libre de errores o bugs.

Un "malentendido" que a veces veo en algunos equipos es: que creemos que las personas de QA están para probar nuestro código por nosotros. Que están ahí para revisar si el cambio que hicimos, lo hicimos bien. A veces nos da flojera y sentimos que no ocupamos correr el programa y revisar si lo que hicimos está bien. Solo cambiamos el código y lo enviamos a QA para que lo prueben ellos.

Es un "malentendido" porque QA no está para eso, QA no está para que nosotros los programadores hagamos cosas bien. Eso lo tenemos que hacer habiendo equipo de QA o no. Es responsabilidad de cada persona revisar que el trabajo que hizo se haya hecho bien, de manera profesional. Sin embargo, me ha tocado ver que llegan a ser ridículos algunos de los bugs que encuentra el equipo de QA. Cosas que si nosotros como programadores le hubiera dado una revisada lo hubiéramos visto. Nos debería de dar vergüenza que QA encuentre errores, no debería ser común. Evitemos esa actitud de que no nos importa cuantos bugs se encuentren.

Como programadores, debemos tener claro que la responsabilidad de que nuestro trabajo esté bien hecho no es responsabilidad del equipo de QA, es nuestra. El equipo de QA está ahí solo como una Safety-Net, una red de protección por si acaso fallamos, no es para que seamos flojos y entreguemos trabajo mediocre.

Robert C. Martin (aka Uncle Bob) habla un poco de eso en su presentación sobre profesionalismo. Les recomiendo que (si no la han visto) la miren.

miércoles, abril 05, 2017

Consultas y comandos

La mayoría de las aplicaciones en las que trabajo siguen un patrón. Son aplicaciones web que tienen consultas y comandos, ya sea acciones con los métodos HTTP GET o POST. Viene siendo el viejo y conocido patrón CQRS. No inició directamente con el patrón en mente; pero cuando el controlador empieza a tener mucho código en una acción, ahí es donde suena como buena idea introducir un comando o un consulta.



Imagina que estás desarrollando una aplicación para capturar ordenes de trabajo, la aplicación es solo un ejemplo por lo que las reglas serán básicas. Los requerimientos pueden ser los siguientes:
  1. Capturar orden de trabajo
  2. Consultar orden de trabajo
  3. Cambiar el estatus de la orden
  4. Marcar como pagada la orden
  5. Consultar ordenes de trabajo pendientes
Puedes ver que la mayoría son consultas o comandos; pero no inicies el desarrollo de la aplicación usando el patron por todos lados, deja que sea el código el que te diga cuando se necesita introducir una nueva abstracción. Al principio agregarías un OrdersController que use algo como EntityFramework con acciones para cada uno de los requerimientos. Y veras si el código se ve fácil de seguir.

Probablemente te pedirán que al momento de capturar una orden no solo se guarde en la db, sino que también hay que enviar correos, agregar un registro en algún log, realizar ciertas validaciones, etcetera. Si metes todo ese código en el action del controller será difícil seguir el código. Ahí es donde abstraer la creación de la orden en un comando tiene sentido. Lo que puedes hacer es agregar una clase "CreateOrderCommand" que seguramente tendría un método Execute que recibe como parámetro un objeto del tipo CreateOrderModel con toda la información necesaria para crear una orden. Este método puede regresar un objeto del tipo CommandResult que es un objeto con una lista de errores y un objeto con el resultado del comando (en este caso, puede ser una nueva orden). De este modo es fácil ver y modificar todo lo que se necesita para crear una orden en un solo lugar, sin tener que ver detalles de HTTP o del framework MVC. Es sencillo ver qué es lo que necesita el comando para funcionar correctamente.

Lo mismo puede pasar para las consultas, si la consulta es compleja será buena idea encapsularla dentro de un objeto Query que tenga propiedades con los posibles parámetros para la consulta y un método Execute o Find que regrese el resultado de la consulta.

Seguir este patrón también me ha servido cuando no conozco o no tengo control sobre la base de datos del sistema. Puedo ir armando los comandos y consultas que regresan valores fijos de prueba y construir la aplicación aunque aún no tenga acceso a la DB o aun no sepa de donde obtener los datos. Una vez que sé de donde consultar o qué actualizar puedo simplemente cambiar la clase consulta y comando indicado.

Seguir este patron cumple mejor con el principio de responsabilidad única, en lugar de tener una clase gigante "Repository" que hace todas la consultas y todos los comandos, tengo una clase comando o consulta para cada característica de la aplicación.

viernes, marzo 03, 2017

Código hediondo

Hay ocasiones en que el código huele mal, es a lo que se le llama code smell. El termino que encontré en español es "código hediondo". No es código que tenga un error obvio, el código que huele mal no necesariamente está mal; pero debes darle una revisada y quizás reescribirlo  porque generalmente cuando hay mal olor significa que algo se está "echando a perder".

Cuando veas código que huele mal... sí, el olor del código se ve, incluso se puede detectar mientras se escucha al código... bueno, decía que sí ves código que huele mal, cámbialo en el momento, no lo dejes para después porque si trabajas mucho tiempo con código que huele mal, puedes acostumbrarte al olor y después no darte cuenta de que tu código apesta.



Algunos de los malos olores en el código son:

Código Duplicado
El código duplicado no es en sí un error. El problema es que no ayuda al mantenimiento del código. Hace que sea fácil cometer errores en el futuro, además de que te llevará más tiempo modificarlo. ¿Te ha tocado hacer un cambio en un programa y tener que ir a muchos partes del código a hacer el mismo cambio? No solo te tardaste más, también existe la posibilidad de que hayas olvidado cambiarlo en algún otro lugar y por lo tanto has introducido un  error.

Para prevenir el código duplicado, lo que puedes hacer es que cuando necesites que se ejecuten instrucciones en varios lugares, en lugar de copiar y pegar, mejor corta y pega. Corta la parte que se repite, pégala en un nuevo método, lo que cambia lo defines como parámetros y mandas llamar (o ejecutas) ese método donde lo necesites.

Método muy largo
El problema con los métodos largos es que es difícil leer que es todo lo que hace. Se complica poder entenderlo y por lo tanto lograr notar a simple vista como puedes afectar la funcionalidad del método al introducir un cambio.

Si el método hace muchas cosas es mejor llamar a otros métodos que hagan una parte chica cada uno. Por ejemplo: si tienes un método que genera un archivo con mucha información (como la factura electrónica). En lugar de tener todo el código en el mismo método, puedes dividirlo en métodos que escriben cada parte del objeto al archivo (un método para escribir los datos del emisor,  receptor, otro para productos, etc.).

Función con muchos parámetros
Este es un mal olor que se va dando con el tiempo, empiezas con uno o dos parámetros y todo se ve bien, luego agregas funcionalidad, necesitas más información  y le vas agregando más y más parámetros y a veces algunos de esos son opcionales. Al final puedes terminar con un método (o función dependiendo como le llame el lenguaje) que recibe muchos parámetros. No es un error; pero puede hacer más difícil entender el código.

Lo que puedes hacer es que cuando empieza a crecer el número de parámetros, en lugar de recibir muchos parámetros, recibir uno solo, un objeto o estructura con atributos (o propiedades) para cada posible valor. Algo como lo que hace jQuery (por ejemplo) con la función ajax, en lugar de recibir muchos parámetros, recibe un solo objeto con atributos para cada opción esperada.

Magic Strings
No solo aplica para las strings, también para los números. Las magic strings son valores literales que aparecen en el código. Por ejemplo cuando en ASP.NET tienes algo como [Authorize(Role = "Administartor")] si te fijas escribí mal el nombre del rol Administrator y no me voy a dar cuenta hasta que vea que todos los usuarios pueden acceder a ese recurso (no solo los que tengan el rol administrador). Con los números el problema no es que lo escribamos mal, sino que no sabemos qué es, si tenemos algo como if order.status = 2 then  es difícil saber qué significa ese 2 por lo tanto si quiero modificar el código debo tener cuidado.

El uso de constantes para los strings y el de enums en los enteros ayuda a prevenir este feo olor. Usa cosas como [Authorize(Role = Role.Administrator)] porque así si lo escribes mal puedes darte cuenta en tiempo de compilación. Tener cosas como if order.status = OrderStatus.InProgress then hace que sea fácil de saber que está pasando en el código.

Complejidad innecesaria 
Es como cuando usas una bazuca para matar una mosca. La complejidad innecesaria hace que el código sea más difícil de seguir, de entender y de modificar. El desarrollo se vuelve más lento y sin ningún beneficio. Este olor puede ser difícil de detectar, más por uno mismo. Es como la persona que se pone mucho perfume pero no se da cuenta porque siempre se pone y ya se acostumbro. No es que huela feo; pero no es agradable el perfume en exceso.

Algunos proyectos son más complejos que otros; pero no debes empezar de lo complejo a lo simple, sino al revés (para seguir con la metáfora, no te puedes ir quitando perfume). A veces sí ocupas dividir tu proyecto en varias capas; pero ve agregándolas cuando sientas que lo necesitas. No empieces agregando capas solo porque sí, después es más difícil quitarlas.

Estos son algunos de los olores que identifico, hay más; pero hasta aquí la dejamos por hoy. Mantén tú código oliendo bien, evita el código hediondo.



lunes, febrero 13, 2017

Cohesión



La cohesión (en programación) se refiere a que tan bien están relacionados entre sí los elementos de un módulo. En el desarrollo orientado a objetos podría decirse que es el grado de relación que existe entre los métodos y variables de una clase. 

Conocer la cohesión te puede ayudar a saber si la clase cumple o no con el principio de responsabilidad única, el cual dice que una clase solo debe tener una razón para cambiar. A veces no se ve a simple vista si el diseño cumple con este principio. Midiendo la cohesion podría ayudarte a distinguir si realmente los métodos hacen cosas relacionadas entre sí.

He visto que hay más de una forma de medir la cohesión de una clase, hay herramientas que pueden auditar el código y decirte como está la cohesión en el proyecto. No he tenido oportunidad de jugar con esas herramientas, la verdad es que esta métrica no la aplico seguido; pero una forma sencilla de medirla es creando un diagrama donde a cada operación de la clase la representas con un rectángulo y cada variable como un circulo (o rectángulo con bordes redondeados). Después conectas los elementos relacionados con una línea. Una vez que se hacen todas la conexiones agrupas los elementos que tienen relación entre sí.

Si solo te sale un grupo entonces hay una alta cohesión y la clase tiene una sola responsabilidad. Si salen varios grupos entonces tiene una baja cohesión, significa que la clase tiene más de una responsabilidad  y quizás sea buena idea dividirla en otras clases, según los grupos resultantes en el diagrama.

Esto va a depender de lo que buscas con la clase, hay ocasiones en que la clase solo la quieres para tener datos relacionados entre sí, como una clase de tipo dirección sin operaciones, solo propiedades para cada parte del dato. Ahí tienes una baja cohesión; pero quizás quieras dejarlo todo en una sola clase. Esto dependerá de tu diseño, la métrica solo te da información, a ti te toca decidir que hacer con ella.

Haz un ejemplo, supón que estás trabajando en una aplicación que generará una factura electrónica, entonces creas una clase Factura con las siguientes operaciones y variables (omitiendo cosas porque esto es solo un ejemplo):

Ya que tienes las operaciones y variables dibuja unas flechas con las relaciones y reacomodas los elementos para que se vean mejor las relaciones:
Viendo las relaciones puedes identificar 4 grupos, eso te dice que la clase Factura tiene baja cohesión y que puede dividirse en varias clases. Puedes ver, también, que la clase tiene varias responsabilidades.

Separando las responsabilidades de la clase factura y buscando una alta cohesión puedes quedar con un diseño de 4 clases donde antes tenias solo una. Cada una con una única responsabilidad y "una sola razón para cambiar". 
Al final el objetivo es que el código sea fácil de entender y de mantener por ti o por alguien más. La meta no es lograr una alta cohesión, la meta es lograr un mejor diseño. Si después de separar en muchas clases, algo te dice que hubiera sido mejor dejar todo en una sola, no dudes mucho en hacer el cambio.  





jueves, febrero 02, 2017

Todo comienza con la escritura

Estaba escuchando el podcast de seanwes, un episodio donde comentaba (como muchas otras veces) que todo comienza con la escritura. Ya había escuchado esa opinión de Sean, de hecho él tiene un curso y toda la cosa sobre el tema. Cuando escuchaba esa frase, pensaba que eso aplicaba solamente para el content marketing; pero pensando un poco más me di cuenta que también puede aplicarse al desarrollo de software.

"Todo comienza con la escritura". Al pensar como aplica esa frase al desarrollo de software, recordé que como programador lo que me gusta es escribir código. No me gusta escribir palabras sobre lo que va a hacer mi programa, no me gusta realmente escribir documentación; pero... 

También recuerdo que en los proyectos donde he podido avanzar más rápido y sin estrés es cuando me entregan los requerimientos por escrito y bien explicados. Cuando la persona que describe el problema se tomó la molestia de escribir claramente el objetivo del proyecto. Me ha tocado estar en proyectos donde no hablo directamente con el cliente, donde mi trabajo es solo implementar una solución propuesta por el arquitecto, en esas ocasiones ha sido fácil llegar al resultado cuando el diseño está bien documentado. Cuando no tengo que estar en las juntas donde se habla de como sería bueno que funcionaran las cosas en lugar de definirlas por escrito.



Parte de la motivación diaria que me ayuda para no distraerme es tener tareas bien definidas, por eso creo que es bueno definir tareas antes de ponerse a programar... con esto me doy cuenta que realmente todo empieza con la escritura, también en el desarrollo de software. Se inicia con la definición de la idea, del objetivo y con la definición de tareas. Si tenemos el habito de escribir nuestras ideas, no nos dará flojera definir por escrito lo que vamos a realizar. De ese modo cuando tengamos definido lo que haremos podemos abrir el editor y solo preocuparnos por el código, seguir el flujo sin detenernos por falta de información.

Es claro que el escenario ideal no es muy común, por lo general no hay tiempo para definir todo a detalle e incluso cuando lo hay no tiene mucho sentido ya que seguramente los detalles de requerimientos cambiarán. Pero no por eso debemos dejar de definir el proyecto con escritura antes de iniciar, las especificaciones pueden cambiar y el habito de escribir nos va a ayudar a no postergar la actualización de la definición. Como todo, entre más practiquemos definir los proyectos con palabras más sencillo se nos hará. Será fácil que llegue una persona nueva al equipo y se ponga al corriente con lo que es el proyecto. 

miércoles, enero 18, 2017

Aprender o morir

Las cosas no son las mismas desde que aprendí a programar, los conceptos básicos son los mismos; pero las bibliotecas, plataformas, herramientas e incluso los lenguajes han cambiado. Aun así se espera que seas experto en poco tiempo, constantemente tenemos que estar aprendiendo para poder usar lo que tenemos disponible para sacar el proyecto adelante. Incluso dentro de la misma plataforma y lenguaje las cosas cambian. En el caso de JavaScript es fácil ver que en cuanto te distraes un poco las cosas ya cambiaron y lo que usan los cool kids ahora no es lo que tú conoces, en lo que aprendes lo que usan ellos ya cambiaron a otra cosa. Pero no debemos molestarnos por eso, es parte del trabajo.

Si no te gusta aprender constantemente, quizás el desarrollo de software no es para ti. Asumo que en todas las carreras es importante mantenerse al día, conocer las tendencias, los últimos adelantos. Pero en el desarrollo de software en particular, la velocidad con lo que van y vienen tecnologías es alta. Con internet y el OpenSource hay más opciones. Ya no basta comprar un libro y conocer el IDE actual mientras sale la nueva versión.

Como profesionales del desarrollo de software es nuestra responsabilidad conocer las nuevas bibliotecas, marcos de aplicaciones, lenguajes, plataformas y aprenderlas en caso de que sirvan para la solución del problema. Si no sabes, está bien decirlo, nadie sabe todo; pero eso no te justifica para no hacer tu trabajo. No digas: "es que eso no me gusta" cuando en realidad le sacas la vuelta porque no te has dado el tiempo de aprenderlo. Por lo menos debemos tratar de saber qué es lo que no sabemos para poder investigarlo cuando veamos la necesidad.

Aprender es parte del desarrollo de software (y del programador). Si no estás aprendiendo algo nuevo, lo estás haciendo mal.

miércoles, enero 11, 2017

Define las tareas antes de empezar

Es divertido iniciar proyectos e ir agregando funcionalidad que se nos va ocurriendo. Intentar usar nuevas tecnologías, nuevas formas de resolver problemas. Equivocarnos, aprender y volver a empezar.  Esto lo podemos realizar en un proyecto personal, en un super happy dev house o cualquier otro día.

Pero cuando se trata de entregar un proyecto con presupuesto fijo a tiempo, vale la pena definir desde un principio las tareas por realizar. Pensar qué es lo que queremos lograr y definir los pasos necesarios para llegar a esa meta. Esto no quiere decir que no podemos ajustar el plan después, el plan cambia. Para eso hacemos las iteraciones en el desarrollo. Revisamos como vamos y decidimos qué sigue.

Ha habido ocasiones que por sentir que tenemos el tiempo encima iniciamos el desarrollo del proyecto sin tener el backlog definido completo. Esto con la idea de que en cada iteración podemos irlo modelando, agregando elementos y definiendo el trabajo necesario. Para algunos proyectos ha funcionado más o menos; pero me he dado cuenta que durante el desarrollo del proyecto sentimos que vamos un poco sin rumbo. No sabemos cuánto nos falta o que porcentaje llevamos avanzado.

En cambio, cuando nos tomamos el tiempo de definir los objetivos y tareas necesarias a realizar. Aun cuando parece que no tenemos tiempo que perder y que debemos simplemente ponernos a programar en lugar de estar definiendo tarjetitas en un programa para administrar proyectos. Incluso cuando el proyecto ya se pasó del tiempo de entrega, vale la pena detenerse a pensar y definir eso que vamos a realizar. Con esa información podemos "saber" cuánto tiempo más necesitamos para completar el proyecto. Aunque nos fallen los estimados podemos revisar donde estuvo el error y mejorar el próximo proyecto. Sin tareas definidas y solo codificar es difícil medir el progreso e identificar áreas de oportunidad.

Tener el trabajo definido ayudará también a trabajar más rápido. Se evitan los tiempos muertos que surgen cuando al programar pensamos: "Ya terminé esta tarea... ¿ahora qué sigue?". Si ya tenemos un backlog de cosas por hacer bien definido podemos seguir programando en lugar de detenernos a pensar. Como ya no tenemos que pensar en detalles no técnicos podemos concentrarnos en lo que nos gusta. Disfrutar el viaje programando con nuestra dosis de motivación diaria.