Tengo un colega que siempre me recuerda que esto que hacemos de desarrollar software no es nada del otro mundo.

«¡No es difícil; cualquiera podría hacerlo!»

La conversación una y otra vez es la misma, yo intento convencerle de que esto es algo único, de que somos creadores de un mundo de clases y objetos donde negocios enteros son capaces de moverse en torno al modelo que imagina nuestra cabeza; pero estoy convencido de que lleva razón. Esto es fácil. A mí me gusta discutir y quiero que en él aún quede un atisbo de que lo que hacemos es difícil; pero es mentira.

En el mundo tecnológico casi todo es complicado. Hay que saber demasiado: Git, ASP.NET MVC, Angular, Gulp, Bower, XAML, React, JavaScript, C#, Docker, Azure, HTML, CSS, Autofac, Ninject, WCF, etc. Demasiadas tecnologías y sólo tenemos una vida para aprenderlas todas. ¿Qué hace la gente que sabe todo esto?

La respuesta es sencilla. Les encanta programar. Siempre quieren más. Acaban de aprender una tecnología y ya quieren el conocimiento de la siguiente. Quieren saber que viene después, que hay detrás de esa nueva idea, quieren más y más y son seguidores leales a este mundo, lo sienten.

Yo, como mi colega, estoy dentro de este grupo de incondicionales y tengo mis trucos para adaptarme a esta vorágine de devorar conocimiento. Así que voy a quitarme un poco la careta y me voy a sincerar en este post, intentando extender la teoría de «hablar con las piezas» que acuñó el GM Jonathan Rowson para que uno pudiera mejorar su ajedrez; pero esta vez aplicándolo al desarrollo del software. Voy a contarles como hablo con mis objetos.

SOLID – OOP

No creo que haya que decir nada más acerca de los objetos que la Programación Orientada a Objetos no haya dicho ya. No es mi intención hacer una introducción sobre como es el paradigma de la orientación a objetos. Los programadores solemos ser tan buenos como el tiempo que llevamos programando y es nuestra responsabilidad tener unas bases sólidas en OOP. La experiencia siempre es un grado. Pero aún con unas bases sólidas y una buena experiencia me entristece ver como no existe el concepto de intuición en informática. Normalmente nos regimos estrictamente a las reglas que hemos aprendido y pocas veces te recomiendan dejarte llevar por lo que te dice tu instinto, tu intuición.

El primer pecado capital del libro de Jonathan Rowson «Los siete pecados capitales en Ajedrez» es el pensamiento. Este es un pecado que también se comete en el desarrollo del software. La mente humana tiende a pensar en modo secuencial, es su naturaleza. También tendemos a echarle la culpa de que algo no funciona a la parte que menos entendemos. Así, si no dominamos bien la parte de por ejemplo un cliente realizado con un framework en Javascript, cuando algo no funcione bien nuestro primer pensamiento va a ser: «Mi backend funciona bien, el error tiene que estar en esa parte.»

No quiero decir que pensar sea malo o erróneo, sino que debido a que pensamos y por la manera que lo hacemos, puede llegar el error. El pensamiento implica demasiadas cosas; pero, a veces, puede llegar a limitarnos.

«No piense. Sienta.»

Todos los desarrolladores somos educados para ser «intelectualmente productivos». Es nuestro sino. En consecuencia, todo proyecto de software tiene una carga emocional elevada. La gestión del mismo se convierte en un punto importante, hay que repartir los egos de los programadores, posibles códigos antiguos, presiones de tiempos, etc. Y en medio de todo este revuelo están nuestras clases y nuestros objetos. Al fin y al cabo el código que dejamos escrito es lo que realizamos, es físicamente el legado que dejamos.

Nosotros queremos a nuestras clases y objetos, los hemos creado y los defenderíamos a muerte. Son nuestras piezas de un puzzle que encaja todo a la perfección o esa es nuestra perspectiva… pero ¿y si le preguntamos a ellos? ¿Están en consonancia con todo lo que les rodea?

 

errordto

 

Me pase toda una semana con este «Dto». ¿No creen que esta incómodo con ese nombre? Tiene tres métodos. Puede que al principio fuera un simple Dto pero al crecer se ha convertido en un modelo, en algo que no es un Dto. Es un ejemplo tonto; pero mi sensación con este objeto era molesta. Se pasaba el día «dándome codazos» y preguntándome «¿estás seguro que soy un Dto?».

Cuando hablo a mis objetos, traigo a la superficie juicios totalmente diferentes a los que pueden surgir en mi cabeza. Les permito «decirme» lo que «opinan» acerca de cómo están interactuando con los demás objetos, cuál es su responsabilidad e incluso si están cómodos con su nombre. A veces es mejor echar una mirada fresca a tu desarrollo y hablar con tus clases y objetos puede ser una manera efectiva de hacerlo.

Finalmente cambié el nombre de  ErrorDto por ErrorModel. Fue un gran alivio para mí y el refactor de código de Visual Studio lo hizo todo automático. Pero imaginen esa situación en la que han estado trabajando con objetos y han notado como había algo que no encajaba del todo. Algo en su intuición les decía esto no puede ser así y aun así por X o por Y han pasado de puntillas por esa situación sin refactorizarlo. ¿No es una situación incómoda? ¿No creen que sus objetos se merecen el mejor trato?

Code Smell. Hablar con tus objetos de manera individual.

Una de las formas de hablar con tus objetos es hacerlo de manera individual. Esto sirve para detectar los problemas que tienen que ver con el propio paradigma de la Orientación a Objetos y la deuda técnica que podemos tener en ellos. Conocer y entender las bases de la OOP es tan importante como conocer un patrón de diseño. Existe un concepto en informática que ya estudia estas cuestiones llamado «Code Smells».

Un Code Smell es un indicador que usualmente corresponde a un problema más profundo en el sistema. http://martinfowler.com/bliki/CodeSmell.html Martin Fowler nos alienta a utilizar nuestra intuición, a ver que algo huele mal en el código. Esto encaja perfectamente con la personalidad de los objetos y como éstos están molestos en el sistema, como son capaces de alertarnos de que algo va mal.

En mi experiencia, siempre hay clases que no queremos ni abrir, porque sabemos inconscientemente que tocar el código de esa clase puede implicar problemas. Para mí esto ya sería un Code Smell, una clase suplicándonos su ayuda, una necesaria refactorización.

Un ejemplo de Code Smell sería algo así:

CodeSmell

Os adjunto un resumen de la clasificación de Code Smells:

Bloaters
  • Long Methods
  • Large Classes
  • Primitive Obsesions
  • Long Parameters List
  • Data Clumps
Indican código que se degradará con el tiempo.
Object Orientation Abusers
  • Switch Statements
  • Temporary Fields
  • Refused Bequest
  • Alternative Classes with Diferent Interfaces
Abusos en el uso de la orientación a objetos.
Change Preventers
  • Divergent Changes.
  • Shotgun Surgery
  • Parallel Inheritance Hierarchies
Indican que un código no está preparado para sufrir modificaciones o nuevos desarrollos con facilidad.
Dispensables
  • Comments
  • Duplicate Code
  • Lazy Class
  • Data Class
  • Dead Code
  • Speculative Generality
Código muerto, innecesario.
Couplers
  • Feature Envy
  • Innapropiate Intimacy
  • Message Claims
  • Middle Man
  • Incomplete Library Class
Código acoplado.

Fernando Escolar (@fernandoescolar) dio una muy buena charla sobre Code Smell y todos sus tipos en la Dot Net Conference de 2015. Podéis echarle un vistazo a sus diapositivas en este enlace: http://es.slideshare.net/fernandoescolar/dotnet-conference-code-smells . He sacado el ejemplo de estas diapositivas y están todos los Code Smell muy bien resumidos.

Recuerdo esta charla de manera especial porque genero mucha controversia y creo que la razón principal, a mi manera de ver, fue porque él se sinceró y nos contó su manera de hablar con sus objetos.

Muchas veces estos Code Smells pasan delante de nosotros desapercibidos. Sí que es cierto que lo mejor para detectarlos es tenerlos es haberlos visto y tenerlos como modelos en nuestra mente. Al final nuestro pensamiento inconsciente reconoce modelos y estos modelos siempre están registrados en nuestro cerebro. Por tanto, para alertarnos de estas señales la experiencia es sin duda una herramienta de gran ayuda; pero pienso que unas bases sólidas en OOP también pueden darnos la habilidad de detectar este tipo de problemas.

El estancamiento. Objetos olvidados.

«Si funciona, no lo toques.»

No me gusta el pensamiento anterior. No cuadra con mi manera de programar. Si hablo con mis objetos y estos tienen un montón de problemas, por mucho que el programa funcione siempre tiendo a tocar el código y escuchar las peticiones de los objetos.

A mí personalmente no me gusta el concepto de «haz sólo lo que tengas que hacer y si en el futuro hace falta ya se refactorizará». Tenemos que guiarnos más por nuestra intuición. Sentir en lugar de pensar. Poniendo un hipotético caso, si un método es largo aunque no lo suficiente para partirlo y tú sientes que en el futuro se va a volver más grande, o tienes la sensación de que vas a poder reutilizar algún conjunto de código de ese método, yo no esperaría a que se diese el caso en sí. Si sientes eso, si tú intuición te lo dice, da igual que no se ha dado el caso aún: hazlo. Sácalo fuera, refactorizalo, no dejes la posibilidad que el siguiente que toque esa parte del código pueda no ver, no hablar con tu objeto y no darse cuenta de lo que tu propio código te está diciendo a ti ahora.

Voy a intentar representar esto con un ejemplo:

filterenum

customatributefilterenum

El peligro de los enums y usar atributos en ellos. Si hablamos con este enum lo primero que grita es que quiere ser una clase. Empezó seguramente representando una estructura, un valor de un Filtro. Después hubo la necesidad de crear un Field al cual atribuirle un valor y seguramente no fue necesario con uno y por eso DbFields se convirtió en un Array. ¿Quién debe refactorizar este Enum a un objeto? ¿En este punto hubiera sido ya suficiente? ¿O cuando se añadieron los Types sería el momento ideal? Mi opinión al respecto es que este Enum nunca debió haber existido. Este Enum debería haber sido una clase desde el minuto 1. Por si crecía o porque (juego con ventaja y después de haber visto lo que crece) tengo la intuición de que se convertirá en un monstruo.

Desde mi punto de vista, aquí entra más en juego la intuición. No conformarse con una solución pasiva puede ahorrarnos problemas en el futuro. Es cierto que no tiene sentido crear algo monstruoso para desarrollar algo simple, de ahí a que nuestra intuición nos guíe a ver si algo merece la pena o no; pero no debemos detenernos sólo porque aún no ha surgido la necesidad si tenemos la incertidumbre que en un futuro surgirá.

Hablar con tus clases y objetos pone estas ideas en tu cabeza y hace que te atrevas con desarrollos más incisivos.

Arquitecturas. Hablar con tus objetos en conjunto.

He observado que uno de los fallos más repetidos en los proyectos software es la mala coordinación de los objetos y las clases creadas por diferentes desarrolladores. Los objetos no se coordinan porque normalmente sus creadores no se coordinan entre ellos. Aunque también se da el caso de programadores que siempre que quieren crear algo nuevo, crean clases nuevas. Al final, nuestro proyecto es un conjunto de clases y objetos y éstos se tienen que entender entre sí.

Aquí aún cobra más valor lo de hablar con tus objetos. El concepto de que son y cómo se quieren organizar lo tienen ellos. Un ejemplo que yo he sufrido a lo largo de mi trayectoria profesional es donde colocar los Modelos y Dtos de mis objetos de negocio. La historia es que cuando ves los ejemplos simplistas siempre en una app ASP.NET MVC (por poner un ejemplo, la propia plantilla que viene por defecto) tienes una carpeta Model donde colocan los Dtos en el propio proyecto MVC. Esa carpeta Model dura ahí dos segundos cuando tienes una aplicación lo suficientemente grande y toca reorganizarla ya que normalmente la transformación de los objetos de dominio a Dtos se suele realizar en una capa de servicios.

Supongamos una arquitectura como la siguiente:

arquitectura1

Cuando llegué a mi último proyecto, esa carpeta se encontraba en el nivel de los Servicios. Al hablar con los Modelos, la realidad era que éste no era su sitio, no estaban cómodos. La capa de servicios normalmente está destinada a los servicios que conectan nuestra capa de presentación con nuestros repositorios. Quizá sí, ahí funcionaban porque eran los servicios los que convertían los objetos de dominio en esos Dtos pero ¿realmente estaban en el sitio correcto?

 

Surgió una nueva necesidad, había que crear documentos a partir de éstos Dtos creados. El proyecto de la creación de documentos era un proyecto aparte y necesitaba la capa de servicios para poder comunicarse con la capa de Presentación Web; aunque también tenía que hacer referencia a dicha capa en sentido inverso para poder tener una referencia de esos Dtos. Tenemos una referencia cíclica:

 

arquitectura2

Aquí, aplicando la regla de «ahora que ha surgido esta necesidad, refactorizamos» todo habría ido bien; pero la llamada de atención estaba desde antes. Creo que el sitio de los propios Dtos es un proyecto a parte, para ellos solos ya que tienen el suficiente valor como para poder considerárseles un todo. Y también creo que nadie escucho a estos Dtos. No tuvieron todo el cariño que merecían y al final todo se acabó pagando con una refactorización costosa.

arquitectura3

A mí modo de ver, estas refactorizaciones son deuda técnica, son clases y objetos que no han sido escuchados por sus programadores. ¿Hay que esperar a que surja una necesidad nueva como la de la creación de documentos para colocar en el lugar adecuado a los Dtos o deberíamos desde el principio colocar en su lugar adecuado los Dtos? Yo pienso que los Dtos tendrían que haber estado en un proyecto a parte en la Capa de Dominio desde el principio.

Conclusiones. ¿Por qué hablar con tus objetos?

El pensamiento es mucho más complicado de lo que solemos creer y, por consiguiente, damos buenas razones a los errores para que se manifiesten.

Deberíamos pensar siempre en objetos; aunque nuestra tendencia sea pensar en un programa como algo secuencial.

La intuición en informática es importante y no deberíamos tener miedo a utilizarla.

Por ello, mi truco para mantener los 3 puntos anteriores en mi cabeza es mantener estas conversaciones con mis objetos. Para mí ellos tienen personalidad, sienten emociones y son capaces de transmitir sus problemas; aunque la ventaja que más me gusta de hablar con ellos es el cariño que les puedes dedicar con este método.

Al fin y al cabo nos gusta programar, nos gusta nuestro trabajo y nos gustan nuestros objetos, por lo que hay que comprometerse con nuestro proyecto y darle cariño para que si un compañero es el siguiente en programar sobre lo nuestro vea que lo hemos hecho con la mayor ilusión posible.

«Codifica siempre como si la persona que finalmente mantendrá tu código fuera un psicópata violento que sabe dónde vives».

Creo que hablando con tus objetos nunca tendrás que preocuparte de esta frase.

Y después de una reflexión como esta, ¿seguís pensando que mi colega lleva razón y que esta profesión la puede hacer cualquiera o hace falta estar un poco loco para seguir programando? 🙂

 

Ángel Carlos López (@_aclopez)