jueves, 31 de julio de 2014

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.