jueves, 18 de noviembre de 2010

Violando la D de S.O.L.I.D

A principios de semana tuve la suerte de asistir al curso de TDD que impartió Enrique Comba en Madrid. Me lo pasé genial pero me fui aún más convencido de que programar es muy difícil.
Aunque el temario del curso fue bastante amplio, yo sólo voy a centrarme en los principios S.O.L.I.D. Si queréis saber más sobre lo que hicimos allí, Jesús Jiménez ha escrito este post explicándolo.

El primer día del curso, Enrique nos dividió en 5 grupos y nos asignó la exposición de un principio S.O.L.I.D. a cada equipo. A nosotros (Amalia Hernandez, Jesús Jiménez, Leo Antolí y yo) nos tocó explicar la D.

Inversión de Dependencias (D)

High level modules should not depend upon low level modules. Both should depend upon abstractions
Abstractions should not depend upon details. Details should depend upon abstractions

Los módulos de alto nivel no deberían depender de módulos de bajo nivel. Ambos deberían depender de abstracciones
Las abstraccciones no deberían depender de los detalles. Los detalles deberían depender de las abstracciones

Cuéntamelo con código
El segundo día lo dedicamos a crear el software que controla un cajero automático (haciendo T.D.D., claro). El código que creó nuestro equipo (los mismos cuatro que el día anterior) lo tenéis completo aquí, pero yo me voy a centrar sólo en nuestra implementación de la clase Banco:



Lo que hace la clase Banco es realizar una petición de validación mediante el Conector a una url. Dicha validación nos devuelve un json a partir del cual se puede crear el token de seguridad con el que se realizarán las siguientes operaciones del usuario validado.

¿Habremos sido capaces de respetar el principio que nos tocó explicar el día anterior?

Los módulos de alto nivel (Banco) no deben depender de módulos de bajo nivel(Implementaciones de Conector y GeneradorToken), ambos deben depender de abstracciones. Nuestro Banco depende de la abstracción Conector y de la abstracción GeneradorToken, pero no "conoce" que implementación de cada abstracción está usando (Ambas se le inyectan en el constructor). Parece que esta parte es correcta.

Las abstracciones (Banco) no deben depender de detalles. Los detalles deben depender de abstracciones. En esta parte es donde hemos metido la pata. Si Banco no debe depender de detalles ¿Qué pinta la construcción de la url contra la que debe operar el Conector? ¿Por qué el Banco conoce que el Conector devuelve json?

Pensando en esto se me ocurre el siguiente refactor de Banco:



Nuestro módulo de alto nivel depende ahora de una abstracción más general, dejándole a los módulos de bajo nivel (Las implementaciones de OperacionesBancarias) todo lo que tiene que ver con la infraestructura (tipo de comunicación, transformación de la respuesta, etc). Pero, ¿no es el token un detalle de bajo nivel? Si la respuesta es afirmativa deberíamos eliminarlo de Banco y OperacionesBancarias devolvería directamente la Cuenta, haciendo que nuestra clase Banco fuera redundante. Sin embargo, yo (que soy el que está programando :P ) creo que cualquier autenticación bancaria me va a devolver un token (hablo desde la ignorancia, pero suena bien) con lo que deja de ser un detalle para formar parte de la abstracción. Eso sí, no estaría mal que fuera una clase Token en lugar de un String, que no todos los tokens tienen porque ser iguales. La clase Banco que no viola el principio de inversión de dependencias quedaría así:



Conclusiones
Yo ya conocía los principios S.O.L.I.D. y se que mis compañeros también (aunque de este código tenemos la culpa Leo y yo :D ). Nos habíamos preocupado de leerlos y de intentar entenderlos mucho antes de dar este curso. Entonces, ¿por qué no fuimos capaces de recordar la dichosa D. incluso habiendo tenido que explicarla el día anterior? Yo pienso que es porque no lo tenemos interiorizado. Hace falta mucha práctica y mucha experiencia trabajando con los principios S.O.L.I.D. en la cabeza para que no se te olviden mientras programas. Por eso considero importante practicar T.D.D. con ejemplos sencillos, porque lo importante no es resolver el problema, lo importante es el proceso mental con el que resuelves el problema.


Criticadme, por favor
Lo que os he contado en este artículo es como entiendo yo el principio de inversión de dependencias. ¿Coincide con lo que entendéis vosotros? Si no es así, ¿en que me he equivocado?

3 comentarios:

  1. Mas o menos lo veo correcto, a nivel de abstracción, yo le hubiera dado una vuelta de tuerca más y en vez de (String usuario, Pin pin) hubiera hecho una clase abstracta llamada Credencial o algo similar. Y ya hubiera quedado bordado según mi ojo, claro.

    ResponderEliminar
  2. Efectivamente, como dices, programar bien es muy difícil!
    Tienes toda la razón! La verdad es que no le di tanta importancia a ese detalle que dices pero es cierto que como lo has puesto al final queda muchísimo más claro.

    Los principios SOLID en sí son una tontería, los lees y los entiendes, sabes lo que tienes que hacer, otra cosa es ponerse a ello... Yo se de que va la maratón, distancias, tiempos, etc. otra cosa distinta es que pueda correr una sin llevar mucho tiempo entrenando.

    Me has convencido con el tema katas, creo que me pondré a hacer muchas en casa tranquilamente :)

    ResponderEliminar
  3. Buen post. Programar es muy difícil y por eso el personal "poco cualificado" no puede hacerlo.
    Sobre cómo mejorar aun más el código, estoy complemente de acuerdo con José Luis Barrera, hubiera introducido una "Credencial", seguramente un ValueObject.
    Quiero que os fijéis en algo, la legibilidad de tu tercera versión de código es muy superior con respecto a la primera. De hecho, cuando hice una lectura rápida del código de la primera versión no me enteré de nada de la lógica de negocio, pero en el último caso la lógica está muy clara. Es un buen ejemplo de que un buen diseño mejora la legibilidad, que es crítico a la hora del mantenimiento.

    ResponderEliminar