jueves, 31 de julio de 2014

Gilded Rose Kata con SOLID


Me encontré la Kata de Gilded Rose en uno de mis libros de cabecera The Coding Dojo de Emily Bache. En breve prometo traducir la Kata al español, pero por ahora, pueden encontrar de que se trata acá.

En esos días el tema de SOLID andaba caliente en entre el grupo de codeadores, que si la responsabilidad del soltero que si se abre y se cierra o que si se invierten. La cuestión es que por más estudio y videos sólo se aprende a programar pues… programando. Así que les lancé el reto que inicialmente era de Refactor y le di un twist aplicando los SOLID Principles.

Emily es una programadora muy linda y hasta proporciona los junits en su GIT porque ya saben, hacer refactor sin junit es como matar gatitos o tuitear lo que comiste. Pero yo soy un poco menos linda y más latosa por lo que les di el código productivo sin junits. Ya sé, algunos me dirán Rox que culeis, pero no es la primera vez que me lo dicen:

Así que el reto era:
  1. Dar cobertura y hacer refactor sin tocar la clase Item class o la propiedad Items 
  2. Aplicar uno o varios principios SOLID al código refactoreado. Ahora sí ya podían tocar cualquier código. 
Los programadores de cabecera de este honorable blog de fanáticos del código limpio y las inspecciones explican de que va cada principio y enseñan su código en nuestro GIT para su deleite y crítica.

Single Responsibility por Luis y por Víctor

Open Closed Principle por Toño

Liskov Substitution por Carlos

Interface Segregation por Yorch

Dependency Inversion

¡Espera más principios prontamente!

solId (Interface Segregation Principle)

Buenas tardes y bienvenidos a su blog codea-mesta, siguiendo con la mítica y fabulosa saga de SOLID [como me emociono!!!] les vengo a platicar un poco del principio de segregación de interfaces. Aqui el Yorch [ZetoWP] diciendo “Dj, Spin that $#17”.


Platiquemos de SOLID, específicamente de la I que viene de Interface Segregation Principle o Principio de Segregacion de Interfaces. Peroquée es lo que esto significa? veamos... Wikipedia nos dice lo siguiente.
The interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use. ISP splits interfaces which are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them...
...

Y esto qué quiere decir??? Se acuerdan de lo que sus maestros les decían? Recuerdan el divide y vencerás? sabe usted dónde están sus hijos a esta hora? [ok, ya estoy divagando]. El asunto es muy sencillo, si tienes una interfaz que esta haciendo muchas cosas por qué no separarla en varias interfaces que hagan una sola cosa???

Nosotros como coders conocemos el poder de las interfaces y clases abstractas, ese poder que nos deja utilizar una solución muy específica para hacer la chamba que requerimos, esa posibilidad de poder utilizar nuestras clases como plug-ins, esa versatilidad para intercambiar las partes sin que se vea afectado el resto de nuestro programa (main) con un comportamiento diferente y mismos resultados, o así debería de ser. Sin embargo en ocasiones dejamos que una sola interfaz se encargue de todo, convirtiendo nuestro esfuerzo se liberación independiente en algo que depende de muchas partes. Veamos un ejemplo.

En GildeRose se tiene que estar actualizando valores de los productos que tienen, tanto la fecha en la que se tiene que vender como su calidad, esto de diferentes formas según el tipo que sea. Esto nos da la idea de generar una interfaz [o una clase abstracta] y que para cada tipo se haga su implementación, correcto? Veamos esta interfaz:

public interface ItemUpdater {

    void updateSellIn(Item item);
    
    void updateQuality(Item item);

}

Una interfaz muy sencilla que nos deja hacer las implementaciones como necesitemos. Suena a una buena y elegante solución. Veamos una implementación:

public class RegularItemUpdater implements ItemUpdater {


    @Override
    public void updateSellIn(final Item item) {
        item.setSellIn(item.getSellIn() - 1);
    }


    @Override
    public void updateQuality(final Item item) {
        item.setQuality(item.getQuality()-1);
    }
}



y así podríamos tener múltiples Items con diferentes políticas. Si bien es correcto imaginemos que un equipo de trabajo se encarga únicamente de las políticas de SellIn y otro de las políticas de Quality, esto nos deja dos problemas:

- Desde que están en la misma clase ambas políticas si se tiene que alterar el RegularItem se tendría que trabajar 2 equipos con el mismo código al mismo tiempo, cosa que resulta en ocasiones en problemas con tu sistema de versionamiento.

- La segunda, dado lo mismo, un equipo conoce las políticas del otro!!! Esto podría ser información sensible para la empresa!!! sin contar el hecho de que un equipo puede añadir bugs al desarrollo del otro equipo!!!


Esto nos deja con un proyecto el cual no se puede desarrollar ni liberar independientemente, ya que para que el equipo sel libere a producción el equipo Quality debe liberar antes... y vice versa!!! esto es un problema.

Ya que entendimos el potencial problema que tenemos, y con un poco de Single Responsability Principle, podemos hacer el siguiente refactor:


    public interface SellInUpdater {

        void updateSellIn(Item item);
    }

    public interface QualityUpdater {

        void updateQuality(Item item);
    }


 


public class ItemUpdater {


    private QualityUpdater qualityUpdater;
    private SellInUpdater sellInUpdater;

    public ItemUpdater(SellInUpdater sellInUpdater, QualityUpdater qualityUpdater) {
        this.sellInUpdater = sellInUpdater;
        this.qualityUpdater = qualityUpdater;
    }

    public void updateItem(Item item) {
        this.sellInUpdater.updateSellIn(item);
        this.qualityUpdater.updateQuality(item);
    }

}
Esto, sabiéndolo manejar y tal vez usando algo de Dependency Injection Principle, nos puede solucionar la vida y tener a dos equipos trabajando por separado y de una forma más limpia y organizada. 

Interface Segregation Principle se trata de independencia, independencia para poder liberar, independencia para poder decidir, independencia de lo que no nos sirve [creo que necesitamos algo de ISP en varios gobiernos del mundo, o no?] y esto es lo que nos dará más potencia a nuestras interfaces, claro, esto puede hacer que tengas un mar de interfaces e implementaciones pero recuerda los beneficios y que es un principio, no una regla. Si crees que te puede ayudar en tu  proyecto no dudes en usarlo!!!


Bueno, si le entendieron le entendieron, y si no pues pueden dejar un comentario y con gusto trataré de responder lo mejor que pueda, hasta luego y que tengan una buena codeada.

miércoles, 30 de julio de 2014

Principio de Responsabilidad Única (SRP - Single Responsability Principle)

Principio de Responsabilidad Única

(SRP Single Responsability Principle)


Este principio, desde mi punto de vista, es la base para lograr un buen diseño de tu software y la verdad es muy fácil de entender, la definición nos dice:
Tu clase solo deberá tener una razón para cambiar.
Esto también deberá llevarse a nivel de métodos, entendiendo que la razón principal se va descomponiendo en pequeños fragmentos de tareas para cumplir el objetivo inicial.

...ahora como yo lo veo….

Si tienes una clase que vas a actualizar porque se mejoró un cálculo y luego porque cambiaste de motor gráfico y después porque agregaste un nuevo reporte y quien sabe porque no funciona si no haces un cambio en ésta clase; bueno he aquí muchas razones por las cuales tu clase cambia, esto hace evidente que algo anda mal en el diseño de nuestro programa. Llego la hora de aplicar... ¡SRP is comming!.

Tratando de ayudar al entendimiento de este principio, expondré un ejemplo:

Caso de Uso: Una tienda tiene artículos a la venta, de estos artículos las principales características son la calidad y los días disponibles para venderlos, ambos valores se ven afectados conforme transcurren los días, aunque no para todos los artículos y no de la misma forma.

Un primer diseño de esta clase fue:

public class Item {
    private String name;
    private int sellIn;
    private int quality;
    private QualityUpdater qualityUpdater;
    private SellInUpdater sellInUpdater;


    public Item(String name, int sellIn, int quality) {
        this.name = name;
        this.sellIn = sellIn;
        this.quality = quality;
        selectUpdaters();
    }

    private void selectUpdaters() {
        this.sellInUpdater = DispacherUpdaters.getSellInUpdater(name);
        this.qualityUpdater = DispacherUpdaters.getQualityUpdater(name);
    }

    public String getters() {...}

    public void setters() {...}

    public void update(){
        updateSellIn();
        updateQuality();
    }

    private void updateQuality() {
        qualityUpdater.updateQuality(this);
    }

    private void updateSellIn(){
        sellInUpdater.updateSellIn(this);
    }
}

Con este primer diseño los artículos que no cambian deben tener un QualityUpdater y un SellInUpdater que no hagan nada. Esto quiere decir que los updaters no son necesarios para todos lo artículos y además ésta misma clase busca sus updaters que utilizará para actualizar la calidad y los días de venta; otra responsabilidad a parte de mantener su información. Una forma de aplicar SRP seria:

1. Separar la lógica de los articulos que cambian y los que no.
2. Inyectar, para los artículos que cambian, la forma en que estos cambian.

public class Item {
    public String name;
    public int sellIn;
    public int quality;

    public Item(String name, int sellIn, int quality) {
        this.name = name;
        this.sellIn = sellIn;
        this.quality = quality;
    }

    public String getters() {...}

    public void setters() {...}
}

public class ItemUpdateable extends Item implements Updateable{

    private QualityUpdater qualityUpdater;
    private SellInUpdater sellInUpdater;

    public ItemUpdateable(String name, int sellIn, int quality) {
        super(name, sellIn, quality);
    }

    public void setQualityUpdater(QualityUpdater qualityUpdater) {
        this.qualityUpdater = qualityUpdater;
    }

    public void setSellInUpdater(SellInUpdater sellInUpdater) {
        this.sellInUpdater = sellInUpdater;
    }

    @Override
    public void update() {
        sellInUpdater.updateSellIn(this);
        qualityUpdater.updateQuality(this);
    }
}

Con esta solución tenemos dos clases resultantes, así los artículos que no cambian utilizan la clase Item y los artículos que son variables utilizan ItemUpdateable y además la forma en que actualizan la calidad y los días para venta son inyectadas.

Aplicar SRP nos ayudará a tener un mejor diseño de nuestro software, será fácil de entender y de modificar…¡Suerte!