lunes, 24 de noviembre de 2014

Webinar TDD y Clean Code: la calidad de código importa

Kent Beck dice “No sé si soy un gran programador, pero definitivamente son un programador con grandes prácticas”. ¿Cuáles son estas grandes prácticas? Test Drive Development y Clean Code son dos de ellas. La adopción de estas prácticas nos ayuda como programadores para que perdamos el miedo a usar código nuevo y confiemos en nuestros compañeros de equipo. También ayuda a reducir la tan odiada documentación o peor, tener documentación incorrecta (como comentarios obsoletos) .

Fernando y Jorge, contribuidores de esta página, dieron este webinar en Software Gurú Campus.


Las diapositivas en Slide Share

martes, 19 de agosto de 2014

Clean Code, primer asalto...

Señores, cuando escuché por primera vez Clean Code como buen programador rápidamente lo relacioné con algún tipo de framework o tecnología y bueno, pues resulta que no. Es más bien una forma de programar como Dios manda y evitar pecar al codear como suele decirse: 'con las patas'.

Casi es seguro que más de alguna vez como programadores hemos regresado a un código propio, le damos una revisada y hasta pena nos da al verlo ya que por la presión del tiempo o por malas costumbres nuestro código resulta un verdadero "espagueti". Y vaya que esto no sólo trata de elegancia. Trata de alta mantenibilidad con todo lo que este factor implica en el desarrollo de sistemas (Invertir tiempo, esfuerzo, retrabajo, dinero. ¿Te suena? amigo inversionista en software). Además como dice el buen Uncle Bob "La única manera de ir rápido, es ir bien" así que tiempo al tiempo y calidad a nuestro código. Seamos profesionales! Y a la vez artistas, hagamos de nuestro código poesía.


Tengo poco de haberme metido con Clean Code y por eso les dejo un tipo de mapa mental (o al menos esa era la intención). Incluye sólo  ideas introductorias ya que hay mucho más, así que os invito a darle rienda suelta a su curiosidad y meterse al mundo de Clean Code, aplicarlo a sus proyectos del día a día y que mejor aplicarlo si están emprendiendo dentro del mundo del software. Hagamos software con calidad!


miércoles, 13 de agosto de 2014

Not a number es un not a number?

Que tal codeamesteros esta vez andaba revisando unas reglas de análisis estático de código y me encontré con una regla media extraña con el NaN, así que la pregunta es que imprime el siguiente programa?:

    public static void main(String[] args) {
        double notANumber = Double.NaN;
        System.out.println(notANumber == Double.NaN);
    }

la idea es que me dejen en sus comentarios que es lo que CREEN que imprime antes de ejecutarlo, después lo ejecuten y vean el resultado real, investiguen y que comenten por que sucede.

Por esta vez es todo, espero sus comentarios.

martes, 12 de agosto de 2014

CleanCodeando la Planeación

Yo tengo el superpoder de reconocer a gente chingona a primera vista. Algo así como un Chingoneómetro integrado que hace que mis ojitos parpadeen rápido y comience a babear. No es una escena bonita, pero bueno, así me pasa. La cuestión es que, cuando vi un video del Uncle Bob en YouTube hablando de funciones, descompuse el teclado de la compu por tanta baba. Así que tuve que molestar gente (mi segundo superpoder) para obtener todo lo de CleanCoders.com y por eso este grupo de codeamestadores hablan de SOLID y demás. Si no los han visto, ya se están tardando. En esos videos por fin entendí qué era eso de TDD y cómo se usa. 

Podría pensarse que el concepto es sencillo: probar antes de programar... pero la realidad es que va más allá. Estas son las reglas en español del Tío Bob:


Antes que nada quiero aclarar para aquellos que no me conocen que yo ya no hago código productivo. Entonces, ¿cómo me atrevo a hablar de Clean Code y TDD? HEREJE DEL MAL. Mi pretexto es que me alejé del camino del bien porque me chocaba hacer front ends o debuggear para testear. Así que mejor me hice tester, ya que pensaba que eso sería la salvación de la calidad de software. No me juzgen; era más joven y menos sabia. Después herré aún más mi camino qualitoso al hacerme de procesos... pero ya no quiero acordarme. La cosa es que hoy sé que la calidad está en el código y que un código limpio y hecho con TDD me hace llorar.

Mi primera vez con TDD y Clean Code

Que no haga código productivo no quiere decir que no le entre a las Katas de Codeamesta (que próximamente subiremos) y entendí que sólo viviéndolas se pueden entender estas 3 leyes. Con la Kata de StringCalculator y Bowling, entendí la maravilla de comenzar con los escenarios más sencillos y aguantarse de hacer más código productivo del necesario; con la de Pokar, a limpiar y refactorear para que las reglas de negocio las lea cualquier ser humano.

Algo sucede al hacer estas katas y ver esos videos que los conceptos le alteran uno el ADN y uno comienza a CleanCodear aunque no haya código. Algo así nos pasó al estimar y planear un nuevo desarrollo.

Estimando y Planeando a la Clean Coder

Alberto y yo tuvimos que estimar un desarrollo. En realidad Alberto ya lo había estimado con Armando, pero básicamente la regaron: no usaron casos de uso y la arquitectura son los casos de uso. Entonces cuando quisimos planear en base a un diseño y dar entregables funcionales nos dimos cuenta de que no podíamos desacoplar la planeación de nuestro diseño. No era funcionalmente incremental. 

Así que como dije, volvimos a estimar. Esta vez hice casos de uso y los validé con gente de negocio e incluso algunos escenarios de pruebas de funcionalidades base. Ya habiendo entendido qué se espera de nuestra aplicación, hicimos un diseño con la funcionalidad más básica que se nos ocurrió. Nada de configuraciones ni reportes ni logs ni esas cosas que el usuario pide. Partimos el diseño en tareas y estimamos. Poco a poco fuimos “complicando” la funcionalidad. 

Mientras diseñábamos nos preguntábamos ¿cuál es el siguiente caso de uso más sencillo? ¿Quién debe hacer eso? Nos dimos cuenta que estábamos aplicando una variante de “As the tests get more especific, the code gets more generic” y “Single Responsability”.

Conforme avanzábamos en la planeación, dibujábamos en el pintarrón el pedacito de diseño que hacía la funcionalidad más específica y escribíamos tareas para una funcionalidad más genérica… El resultado, los últimos sprints fueron más rápido de diseñar y planear.

Y ahora, a codificar

El desarrollo comenzó con la estimación aún calientita y muchos unknowns. Incluso, hoy revisamos con arquitectura nuestro hermoso diseño y uno de los Arquitectos dijo, quitándose los lentes y removiendo una lagrimita, “si hubieramos hecho esto hace un año”. En fin. Ahora los programadores tienen que volver a estimar, tomar decisiones sobre la implementación y la organización de su grupo y si todo resulta como dice la teoría, Clean Code nos hará más rápidos… ya se enterarán.

Uncle Bob dice que TDD no es religión, yo la verdad tengo mi cartita de Uncle Bob en la cartera.


sábado, 9 de agosto de 2014

El diseño interno visto desde fuera

Que tal gente, este es mi primer post y antes de empezar les quiero dar las gracias al equipo de codeamesta ya que ustedes son las espermas que a partir de su perseverancia, inteligencia innata y esfuerzo empiezan a engendrar un buen desarrollo, incrustándose en en el IDE y el compilador para dar como resultado un hermoso código, código que al principio todos miran y dicen que bonito es, pero que conforme pasa el tiempo terceros dicen no manches como es que llegó a estar esto como está, pero lo bueno es que es tarea de nosotros mismos el hacer que este código crezca con la posibilidad de una vida mejor a la de sus antecesores y que al final del camino sea un código de bien y que ayude a la sociedad a lograr su cometido.... ha cabrón como que ya me fui por otro lado, bueno el chiste es que gracias a ustedes por hacerme crecer y creer.

Ahora si empezamos.....

En la semana pasada estábamos en la junta diaria y un desarrollador comentó que ya casi terminaba su tarea que solo le faltaba llenar un POJO necesario para crear estadísticas y que era responsabilidad de otro crear, en ese momento sentí algo raro en la panza, ¿por qué esperar si tu tarea es hacer ciertas transformaciones sobre datos, no llenar un POJO para estadísticas? y recordé los principios enseñados por en tío Bob, y empecé a divagar y pensar sobre eso y llegue a la conclusión que lo que el desarrollador pensaba es meter en su clase una instancia del POJO para poder así llenarla para luego crear su respectivo método getter para que quien la usara pudiera obtener el POJO creado y hacer uso de él, en ese momento algo no me gustó y pensé en proponer algo para dejar un poco mas mejor esa clase y les dije cuidado al hacer eso, por que es como llamar al chamuco para que te haga un favor, al principio te puede hacer respirar y hacer que la situación en la que está "mejore" de pronto, pero te vas a quedar con un pedo más en la cabeza y no vas a estar a gusto con la decisión que tomaste y a largo plazo puede ser que te cause mas problemas de los que te "resolvió", así que lo que vimos es que esa clase tendrá más de una razón por la que podría cambiar, si el POJO cambia hay que cambiar la clase y si la forma de hacer la transformación cambia entonces hay que cambiar la clase lo cual vimos que no es lo mejor de acuerdo al principio de responsabilidad única, así que llegamos a una mejor solución en la que la clase que hace la transformación sólo hace eso, la transformación, pero puede entregar también una descripción de lo que hizo y quien es, de forma que la clase externa sea quien genere el POJO y así hacer que esta clase de transformación tenga una responsabilidad única.

Bueno lo chistoso acá es que me pongo a pensar en cuánto código así de feo generé yo en su momento y que seguramente aún sigo generando y me doy cuenta que no se por que pero cuando el desarrollador tira código no piensa claramente, o se nubla, tal vez por que está en "la zona", pero cuando el mismo desarrollador ve un código o escucha de otro su posible solución dice ....mmmmm.... como que algo está jodido ahí y entramos en el asunto de que no es lo mismo ver algo desde afuera que estar en la situación, es como cuando te vas de parranda y ves a una chava que te late, pero no sabes por que te friqueas y no haces nada y no sabes por que, pero cuando esa mista situación le pasa a tu amigo le dices no mames yo ya hubiera hecho x, y o z, esto para mi es exactamente lo mismo y es en donde creo en que es bueno que alguien desde fuera del desarrollador vea el código y de su punto de vista, para esto es para lo que yo creo que deben de servir mas las inspecciones de código.

Bueno, espero que les haya sido entretenida la lectura y que pensemos ¿qué podemos hacer para pensar claramente al tirar código? ¿como puedo ayudar a los demás a encontrar una mejor solución?, así que a ser críticos de nuestro código y del de nuestros compañeros que aunque al principio pueda ser molesto al final te genera mas experiencia y armas para solucionar futuras situaciones en el bar, antro o donde sea que estés.

Bueno, tal vez se pregunten donde quedo yo en el asunto de la esperma y todo ese choro,pues yo soy el tío del código, lo aclaro por que ya que leí el post como que parecía que estaba evitando decir algo sobre mi y nunca dejaba claro mi lugar en esa historia, así que ahí está antes de que me albureen.


NOTA: Este post está basado en un suceso real y ha sido exagerado para tratar de hacerlo mas entretenido jeje.

viernes, 1 de agosto de 2014

EL PRINCIPIO DE LISKOV SUSTITUTION

El propósito de una abstracción es separar comportamiento e implementación. Es decir separar la abstracción de cómo esta es implementada, así implementaciones de la misma abstracción pueden ser sustituidas libremente.

El principio de Liskov Sustitution se vuelve muy importante en el diseño de un programa ya que de este depende mucho la mantenibilidad y la correcta funcionalidad de un sistema cuando nuevas implementaciones son creadas.

El principio dice lo siguiente:

Si tenemos una objeto o1 de la clase A y un objeto o2 de la clase B entonces en un programa escrito en función de B podemos sustituir el objeto o1 por o2 si alterar la funcionalidad del sistema si A es un subtipo de B.

public class LiskovSustitution {
    public static void main(String[] args) {
        OtroItem o1 = new OtroItem();
        Item o2 = new Item();
        hacerAlgo(o1); Aquí podemos reemplazar o1 por o2 sin afectar la funcionalidad.
    }

    static void hacerAlgo(Item b){
        b.update();
    }
}

class OtroItem extends Item{
    public void hacerOtraCosa(){
        System.out.println("Hacer otra cosa");
    }
}

class Item{
    public void update(){
        System.out.println("Item updated");
    }
}
El problema viene con un mal manejo de la herencia. Imaginen el caso donde se tiene una clase Set que hereda de List (podríamos decir que un Set es un List dada la herencia). Como ya sabemos la clase Set guarda solo una instancia del mismo objeto aunque este le sea pasado dos veces, es decir si hacemos Set.add(objeto) y de nuevo Set.add(objeto) solo una instancia es almacenada a diferencia de List que guardaría las dos instancias. Ahora bien imaginen el caso donde un método requiere de un List para trabajar pero dada la herencia es posible pasar un objeto de la clase Set, es muy probable que con esto cambiemos la funcionalidad de ese método si darnos cuenta hasta el punto en que el sistema quede inestable.

Con este ejemplo vemos como un subtipo cambia la funcionalidad de su tipo padre. Ademas de violar el principio de liskov sustitution también esta faltando al principio open close modification.

Tomando nuestro ejemplo anterior:

public class LiskovSustitution {
    public static void main(String[] args) {
        OtroItem o1 = new OtroItem();
        Item o2 = new Item();
        hacerAlgo(o1); Aquí podemos reemplazar o1 por o2.
    }

    static void hacerAlgo(Item b){
        b.update();
    }
}

class NoUpdatableItem extends Item{
    public void update (){
        throw UnsoportedOperation();
    }
}

class Item{
    public void update(){
        System.out.println("Item updated");
    }
}

Si un subtipo no tiene todas las operación que su tipo padre, entonces este no se debe considerar como un subtipo, es decir si NoUpdatableItem no soporta la operación update entonces no se puede decir que sea un Item. Esto es un indicativo que algo anda mal en nuestro diseño. Por otro lado si cada que creamos un nuevo subtipo la clase que hace uso del polimorfismo debe ser cambiada esto también es un indicativo que algo va mal en el diseño. Por ejemplo:

public class LiskovSustitution {
    public static void main(String[] args) {
        OtroItem o1 = new OtroItem();
        Item o2 = new Item();
        hacerAlgo(o1); Aquí podemos reemplazar o1 por o2.
    }

    static void hacerAlgo(Item b){
        if( ! b instanceof NoUpdatableItem)
b.update();
    }
}

class NoUpdatableItem extends Item{
    public void update (){
        throw UnsoportedOperation();
    }
}

class Item{
    public void update(){
        System.out.println("Item updated");
    }
}

Esta variante en el método static void hacerAlgo(Item b) tiene que hacer uso de instanceof para saber si una operación es permitida. Es decir, si el método que es cliente de nuestra clase tiene que saber el tipo de dato que se le pasa para saber que operaciones puede realizar es sin duda un mal diseño y una violación al princiopio que aquí estamos analizando.

Lo correcto para nuestro ejemplo seria separar los Items en dos tipos diferentes, UpdatableItems y NoUpdatableItems.

class Item{
    String nombre;
    public Item(final String nombre){
        this.nombre=nombre;
    }
}

class UpdatableItem extends Item{

    public UpdatableItem(String nombre) {
        super(nombre);
    }

    public void update(){
        System.out.println("Update item");
    }
}

class NoUpdatableItem extends Item{

    public NoUpdatableItem(String nombre) {
        super(nombre);
    }
}

Y llegaramos a crear subtipos de UpdatableItems estos subtipos deben mantener la misma funcionalidad que su clase padre para poder ser considerados subtipos de UpdatableItems.


Importante: este post es autoría de Carlos, quien no lo subió por causas de fuerza mayor provocadas por su voluntad.

El Principio de Responsabilidad Única (The Single Responsibility Principle)


El Principio de Responsabilidad Única (The Single Responsibility Principle)

Bueno Team, el día de hoy revisaremos uno de los principios de SOLID, el cual es el principio de responsabilidad única, bueno para comenzar este termino o mas bien principio fue introducido en los 90 por Robert C. Martin o más conocido por el Tio Bob y lo define de la siguiente manera “El Principio de responsabilidad única establece que cada modulo de software debe tener una y sólo una razón para cambiar”, esto de entrada suena bien y con mucha lógica, pero primero hay que establecer que el Tio Bob cuando dice modulo de software incluye una amplia gama de opciones donde aplicar dicho principio ya que esto aplica para diseño, clases, funciones, variables, etc...

Con esto en mente por el momento podemos pasar a lo siguiente a que se refiere con una y sólo una razón para cambiar, esta idea lo que quiere decirnos es que cada modulo de software debe tener una responsabilidad bien definida y encapsulada, este concepto esta muy relacionado a un principio de diseño de separación de responsabilidades que habla de modularidad y encapsulación, la realidad es que esta idea le vemos día a día he incluso la implementamos, en nuestro trabajo las responsabilidades están bien definidas, las responsabilidades del su jefe y ustedes como parte de su equipo de trabajo, de entrada esta idea suena bien ya que si la aplicamos para muchas cosas en nuestra vida puede aplicar para diseñar software, una ves aceptada la idea de repartir responsabilidades bien definidas llega la pregunta, ¿que define una razón para cambiar?, algunos pensaran puede ser la resolución de bug encontrado en alguno de nuestros módulos o aplicar un refact a nuestro modulo, aquí lo que nos comenta el Tio Bob que estos dos temas, tanto resolución de bugs y refact no cuentan como razones para cambiar un modulo, ya que la aplicación de estos dos son mas responsabilidad del desarrollador mismo.

Dado que soy un fan del Fútbol pondré unos ejemplos esperando que esto ayude un poco a comprender este principio, primero la idea separación de responsabilidades, por un lado tenemos al dueño del equipo que tiene a grandes rasgos la parte administrativa de dicho equipo esa es su responsabilidad, por otro lado esta el director técnico del equipo y su responsabilidad es clara dirigir al equipo de fútbol y pues también están los jugadores y su responsabilidad de jugar al fútbol, veamos otra idea del este principio que es que un modulo sea capaz de realizar otras responsabilidades no quiere decir que deba hacerlo, esto lo podemos ver en el equipo de fútbol, que aun que el director técnico sea un ex-jugador de fútbol no quiere decir que deba entrar a jugar durante un partido aun que pueda y sepa hacerlo su responsabilidad esta clara dirigir al equipo de fútbol, de igual forma aun que el dueño sepa de fútbol no quiere decir que deba dirigir al equipo para eso esta el director técnico, y así podríamos seguir definiendo cada responsabilidad de cada modulo en el equipo de fútbol sin importar en que nivel se encuentra ya sea diseño, clases, funciones, variables, etc... como definimos previamente.

 Bueno ahora la pregunta ¿que define una razón para cambiar? Bueno esto va enfocado a la responsabilidad que tiene un modulo para atender las necesidades de un actor( persona, grupos de personas, módulos, etc...) , veamos lo desde el ejemplo del equipo el dueño del equipo tiene la necesidad de tener un equipo ofensivo por lo cual requiere un director técnico que cumpla con estas características, la única razón de cambio para el modulo de director técnico seria que el dueño ya no quisiera un director técnico ofensivo si no mas bien defensivo, esta cambiando la necesidad del dueño, dado que si cambia un director técnico ofensivo por otros de las misma características lo veríamos mas como corrección de un bug o refactor dado que el director técnico no estaba funcionando como lo esperado, lo mismo lo podemos ver a nivel del director técnico y los jugadores cuando cambia la estrategia o parado del equipo se puede tomar como una razón de cambio, pero cuando cambia a un jugador sin alterar la estrategia se podría ver como una resolución de un bug o un refact. Espero que este ejemplo le haya servido para entender la idea de el principio de responsabilidad única, pero dejemos un poco la teoría y veamos un ejemplo mas practico y enfocado al software que es lo que nos gusta e interesa.


Con mi equipo de trabajo hemos estado realizando Katas que la idea básica es ponernos ejercicios diarios que nos ayuden a mejorar y perfeccionar nuestras habilidades al momento de programar, muy parecido a una kata dentro de las artes marciales, bueno una de estas Katas era sobre un programa que se encargaba de actualizar el inventario de quesos de una empresa llamada GildedRose la cual contaba con varios tipos de quesos y dependiendo el tipo se actualizaba de una forma u otra, las características que se actualizaban ere la calidad del queso y su fecha limite de venta, la idea de esta kata era partir de un sistema ya echo y que estaba englobado todo en una sola clase y la idea era utilizar los principios de SOLID y rehacer este sistema sin alterar el funcionamiento actual de dicho sistema y a continuación les mostrare como aplique el principio de responsabilidad única, donde lo separe en 3 actores el sistema, los tipos de quesos y las reglas de negocio.


Código al Inicio de la Kata:
package gildedrose;

class GildedRose {

    Item[] items;

    public GildedRose(final Item[] items) {
        this.items = items;
    }

    public void updateQuality() {
        for (int i = 0; i < items.length; i++) {
            if (!items[i].name.equals("Aged Brie")
                    && !items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
                if (items[i].quality > 0) {
                    if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
                        items[i].quality = items[i].quality - 1;
                    }
                }
            } else {
                if (items[i].quality < 50) {
                    items[i].quality = items[i].quality + 1;

                    if (items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
                        if (items[i].sellIn < 11) {
                            if (items[i].quality < 50) {
                                items[i].quality = items[i].quality + 1;
                            }
                        }

                        if (items[i].sellIn < 6) {
                            if (items[i].quality < 50) {
                                items[i].quality = items[i].quality + 1;
                            }
                        }
                    }
                }
            }

            if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
                items[i].sellIn = items[i].sellIn - 1;
            }

            if (items[i].sellIn < 0) {
                if (!items[i].name.equals("Aged Brie")) {
                    if (!items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
                        if (items[i].quality > 0) {
                            if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
                                items[i].quality = items[i].quality - 1;
                            }
                        }
                    } else {
                        items[i].quality = items[i].quality - items[i].quality;
                    }
                } else {
                    if (items[i].quality < 50) {
                        items[i].quality = items[i].quality + 1;
                    }
                }
            }
        }
    }
}
Veamos el Sistema ya con los cambios:
package gildedrose;


public class GildedRoseSystem {
    
    private ItemUpgradeInstanceable factory;

    public GildedRoseSystem() {
        this(GildedRoseMainFactory.getItemUpgradableFactory());
    }

    public GildedRoseSystem(final ItemUpgradeInstanceable factory) {
        this.factory = factory;
    }

    public void updateItem(final Item item) {
        ItemUpgradeable upgratable = this.factory.getInstance(item);
        upgratable.updateQuality(item);
        upgratable.updateSellIn(item);
    }

}
El sistema tiene como responsabilidad es actualizar de cada tipo de queso(item) su calidad y su fecha limite de venta, sin siquiera saber el detalle de como se actualiza cada propiedad de los tipos de quesos, ni que reglas de negocio aplican para cada propiedad y tipo de queso, su responsabilidad es clara, modular y encapsulada.


Veamos ahora un ejemplo de los tipos de quesos(item):
package gildedrose;


public class NormalItemUpgradeable implements ItemUpgradeable {
    
    private GildedRoseBusiness business;

    public NormalItemUpgradeable() {
        business = new GildedRoseBusiness();
    }

    @Override
    public void updateQuality(final Item item) {
        this.business.degreteQualityInOne(item);
        if (item.sellIn <= 0) {
            business.degreteQualityInOne(item);
        }
    }

    @Override
    public void updateSellIn(final Item item) {
        this.business.degreteSellIn(item);
    }

}
Los quesos normales saben que su calidad se degrada en uno y que si su fecha de venta limite ya paso se degrada al doble, ha reglas de negocio que se aplican a dicho degradado pero es una responsabilidad que no es propia del tipo de queso. Veamos otro tipo de queso:
package gildedrose;

public class BackstageSpecialItemUpgradeable implements ItemUpgradeable {

    private GildedRoseBusiness business;

    public BackstageSpecialItemUpgradeable() {
        business = new GildedRoseBusiness();
    }

    @Override
    public void updateQuality(final Item item) {
        business.incrementQualityInOne(item);
        updateQualityInSpecialSellinTime(item);
    }
    
    @Override
    public void updateSellIn(final Item item) {
        business.degreteSellIn(item);
    }

    private void updateQualityInSpecialSellinTime(final Item item) {
        if (item.sellIn < 11)
            business.incrementQualityInOne(item);
        if (item.sellIn < 6)
            business.incrementQualityInOne(item);
        if (item.sellIn <= 0)
            item.quality = item.quality - item.quality;
    }

}
Este queso a diferencia del normal aumenta su calidad con forme se acerca a su fecha limite de venta en uno, dos o tres dependiendo el rango de proximidad a dicha fecha y una ves que llega a la fecha la calidad es cero, a cada incremento se le aplica una regla de negocio que no es responsabilidad como tal de el queso.

Veamos a continuación el negocio:
package gildedrose;


public class GildedRoseBusiness {
    
    public void degreteSellIn(Item item) {
        if (!item.name.equals("Sulfuras, Hand of Ragnaros")) {
            item.sellIn = item.sellIn - 1;
        }
    }

    public void incrementQualityInOne(Item item) {
        if (item.quality < 50) {
            item.quality = item.quality + 1;
        }
    }

    public void degreteQualityInOne(Item item) {
        if (item.quality > 0) {
            item.quality = item.quality - 1;
        }
    }

}
Ven esta clase se encuentran todas las definiciones del negocio en cuanto al decremento e incremento de la calidad sin importar como las aplique cada item y al decremento de la fecha limite.


Cual es la idea, bueno el sistema su responsabilidad es garantizar que de cada item se tiene que actualizar la calidad y la fecha, dirige la actualización, los tipos de item su responsabilidad es saber como se actualizan si incrementan o decrementan y cuantas veces ocurren estos incrementos y decrementos, y el negocio es quien establece los limites para cada incremento y decremento. Esto en que no ayuda, de entrada las responsabilidades están bien definidas, modulares y encapsuladas, aun que el sistema pudiera realizar todas las operaciones no seria bueno que lo hiciera ya que seria muy rígido y frágil ya que cada cambio que se realizara se afectaría todo el sistema, con esta separación de responsabilidades es menos rígido o en otras palabras muy fácil de realizar cambios y menos frágil un cambio no me rompe todo el sistema, dado que si el negocio cambia para cambiar los rangos de incremento o decremento los tipos de queso no se ven afectados su responsabilidad sigue siendo la misma o si se agregan, quitan o cambian su implementación los tipos de quesos el sistema no se ve afectado.


Para concluir podemos decir que el principio de la responsabilidad única es de los mas simples de los principios de SOLID, pero a la ves es de los mas difíciles de hacer bien, ya que a pesar que la separación de responsabilidades es algo natural en nuestro día a día, encontrar y separar bien estas responsabilidades en un programa es algo mas complicado y lo mejor es practicarlo he ir lo mejorando.


Por mi parte no me queda mas que agradecerles su tiempo y espero que el tema haya sido de su agrado y les sirva para su día a día y recuerda...




... hackea tu código!!!