Archivo de la etiqueta: ood

Take it easy, we have builders

As I said before, it’s a valuable experience for me to keep in touch with different development teams.

Last week we were discussing the best method to validate domain model objects. My first response to that question is: model objects should never be invalid, in the first place.

Each domain object should be fully initialized in its constructor, either by initializing default values or receiving values ​​from the constructor.

Sometimes someone says that does not appreciate consructors with 20 parameters, then I question if the object is large because one or more objects are not yet discovered.

Not to make this post too long, suppose we agree that completely initialize the object with valid values ​​in the constructor and that no public method allows us to modify the state leaving it invalid. In this case, it is never necessary to validate our object because we know that it can never be invalid.

And here we come to the practice recommended to fellow developers last week: if it’s not trivial to validate a data and, once validated, to build the object, then use a Builder. Builder’s responsibilities are:

  • Make sure you have all the necessary data to construct the object
  • Provide a friendly interface for specifying the data
  • Construct the object

The following example “fluent API”:

public class InvoiceBuilder {
    private Customer _customer;
    private DateTime _date;

    public InvoiceBuilder WithCustomer(Customer customer) {
        _customer = customer;
        return this;
    }

    public InvoiceBuilder WithDate(DateTime date) {
        _date = date;
        return this;
    }

    public Invoice Build() {
        AssertDataCompleteAndValid();
        return new Invoice(_customer, _date);
    }

    private void AssertDataCompleteAndValid() {
        if (_customer == null)
            throw new ArgumentNullException("customer");

        if (_date < DateTime.Today)
            throw new ArgumentOutOfRangeException("date");
    }
}

And this code would be used this way:

var invoice = new InvoiceBuilder().
    WithCustomer(jose).
    WithDate(DateTime.Today).
    Build();

See you!

No desesperen, tenemos los builders

Como ya he dicho antes, el estar en contacto con equipos de desarrollo me resulta una experiencia muy valiosa.

Estábamos la semana pasada discutiendo sobre el mejor método para validar objetos del modelo de dominio. Mi primera respuesta ante esa pregunta es: nunca los objetos del modelo debieran estar inválidos, en primer lugar.

Cada objeto de dominio debiera inicializarse completamente en su constructor, ya sea inicializando valores por defecto, ya sea recibiendo valores desde el inicializador.

Algunas veces alguien menciona que no aprecia los constructores con 20 parámetros a lo cual respondo con un cuestionamiento sobre si realmente ese objeto debe ser tan “grande” o si hay uno o mas objetos no descubiertos aun.

Para no hacer esta entrada demasiado larga, supongamos que acordamos que inicializamos completamente el objeto, con valores válidos en el constructor y que ningún método publico nos permite modificarlo dejándolo en estado invalido (1). En este caso, nunca es necesario validar nuestro objeto puesto que sabemos que, si esta instanciado, nunca puede ser inválido.

Y aquí llegamos a la práctica que recomendé a unos colegas la semana pasada: si no es trivial validar una serie de datos y, una vez validados, construir el objeto, entonces usen un Builder. Las responsabilidades del Builder son varias:

  • Asegurarse de tener todos los datos necesarios para construir el objeto
  • Proporcionar una interfaz amigable para la especificación de todos los datos
  • Construir el objeto

A continuación ejemplo con “fluent API”:

public class FacturaBuilder {
    private Cliente _cliente;
    private DateTime _fecha;

    public FacturaBuilder ConCliente(Cliente cliente) {
        _cliente = cliente;
        return this;
    }

    public FacturaBuilder ConFecha(DateTime fecha) {
        _fecha = fecha;
        return this;
    }

    public Factura Build() {
        AssertDatosSuficientesYCorrectos();
        return new Factura(_cliente, _fecha);
    }

    private void AssertDatosSuficientesYCorrectos() {
        if (_cliente == null)
            throw new ArgumentNullException("cliente");

        if (_fecha < DateTime.Today)
            throw new ArgumentOutOfRangeException("fecha");
    }
}

Y este código se usaría de esta manera:

var factura = new FacturaBuilder().
    ConCliente(jose).
    ConFecha(DateTime.Today).
    Build();

Nos vemos!

¿Cuál es la diferencia entre el patrón strategy y state?

El jueves pasado estuvimos viendo temas de polimorfismo en el curso Elementos avanzados de arquitectura de software con objetos y, al cabo de un ejemplo, yo plantee que lo que habíamos visto era el patrón State. Hernán me puso cara de “no tanto” y sospecho que en próximas clases entenderé el porqué.

Sin embargo surgió un mini debate con unos de mis compañeros de curso: el argumentaba que en realidad lo que habíamos visto era el patrón Strategy. Creo que esta es una duda común porque ambos patrones son parecidos en algunos aspectos de la implementación y en el diagrama de clases pero son conceptualmente distintos, por lo tanto me pareció bueno escribir un pequeño post.

El patrón State permite hacer diferentes cosas dependiendo del estado del objeto. En otras palabras, lo que cambia de acuerdo al estado es que se hace. Además, todas las posibilidades están incluidas en el código del modelo. A la hora de agregar nuevos estados y su correspondiente acción asociada basta con agregar una subclase sin tocar las demás (observando el Open-Close principle).

En cambio el patrón Strategy permite hacer lo mismo de diferentes maneras. En otras palabras, lo que cambia es como se hace. Este patrón usualmente permite que la implementación específica (la estrategia) se pueda seleccionar por configuración, por el estado de cierto objeto, etc.

Les dejo algunos links en inglés que aportan mas detalles:

http://stackoverflow.com/questions/1658192/what-is-the-difference-between-strategy-design-pattern-and-state-design-pattern

http://www.c-sharpcorner.com/UploadFile/rmcochran/strategy_state01172007114905AM/strategy_state.aspx

http://c2.com/cgi/wiki?StrategyPattern

[PDF] http://userpages.umbc.edu/~tarr/dp/lectures/StateStrategy.pdf

Volviendo al preescolar en diseño orientado a objetos

Ayer comencé el curso Elementos avanzados de arquitectura de software con objetos de 10Pines, a cargo de Hernán Wilkinson (@HernanWilkinson).

Intentaré contar mis vivencias luego de cada una de las 6 clases, sin mucho análisis, en su versión cruda. Luego vendrá el tiempo de las conclusiones.

Antes de comenzar el curso estuve releyendo algún material relevante sobre diseño orientado a objetos (DOO), sobre todo el libro Smalltalk, Object and Desing, de Chamond Liu. Recomiendo este libro que, a pesar de su apariencia sencilla, no tiene desperdicio, una ganga por USD 24.

Vuelvo al curso. Es evidente que Hernán tiene mucha experiencia enseñando “objetos” ya que nos mantuvo interesados durante cuatro horas con tres simples conceptos: objetos, colaboración y mensajes, todo esto sin tocar las computadoras.

Lo primero que nos pidió fue que, momentáneamente, nos olvidáramos de todo lo que sabíamos de diseño orientado a objetos (DOO). Creo que es el enfoque apropiado para el curso ya que es usual que tengamos muchos conceptos mal aprendidos y eso dificultaría bastante el aprendizaje.

Aquellos con los que he hablado del tema sabrán que hace varios años hice mi “click” y comencé a dar el próximo paso en DOO, empezando a prestar mas atención al comportamiento en los objetos y menos al estado.

Ese fue el eje de la clase de ayer, el funcionamiento de cualquier programa consiste en objetos colaborando entre si mediante el envío de mensajes (“aproximadamente” métodos en Java o .NET). Cuales son esos objetos, cuales son esos mensajes forma parte de la tarea difícil del diseñador. Es ahí donde esta la fortaleza del diseño que hará que nuestro código sea fácil de mantener o una verdadera pesadilla.

Hernán destila Smalltalk por los poros y no tiene manera de disimularlo (y creo que tampoco quiere), personalmente valoro mucho esto porque nos permite aprender las técnicas en un entorno puro, ya habrá tiempo luego para “perder flexibilidad” en otras plataformas.

El próximo jueves o viernes la próxima entrega.

Nos vemos.

Principios SOLID 1, ejemplo con SRP, DIP y OCP

Les presento el primero de una serie de videos donde repetiré los refactorings basados en principios SOLID que mostré en la VAN de AltNetHispano. La ventaja que tienen estos videos sobre los de la VAN es que estan particionados, uno para cada ejemplo y vienen acompañados con el código fuente antes y después del ejercicio.

El repositorio de código fuente podrán encontralo en aquí y, una vez descargado, deberían ejecutar el siguiente comando para que quede tal como lo ven al principio del ejemplo:

$ git checkout ejemplos-base

Este comando posiciona el repositorio en el tag “ejemplos-base”, para dejarlo tal como queda al final de este ejemplo:

$ git checkout ejemplos-verificador

Mas abajo comento ciertos momentos interesantes en el video para aquellos que deseen un acceso directo.

En el minuto 1:20 presento el ejemplo del verificador.

En el minuto 3:45 explico el refactoring aplicando el principio de responsabilidad única (SRP).

En el minuto 6:35, una vez concluido el refactoring anterior, comienzo a analizar el código para identificar otro problema de diseño. Explico el principio de inversion de dependencias (DIP) y como aplicarlo al ejemplo.

En el minuto 11:10 doy un paso más con un problema de diseño mas sutil que termina con la descripción y aplicación al ejemplo del principio abierto-cerrado (OCP).

En el minuto 16:15 repaso los refactorings aplicados.

Si tuvieran alguna consulta o duda, no duden en contactarme.

Nos vemos.

VAN sobre principios SOLID en AltNetHispano

El sábado pasado participé como ponente en una VAN (reunión virtual) de AltNetHispano sobre principios SOLID (uno de los temas que más me gusta de esta profesión). Aquí podrán encontrar el listado completo de videos de VANs o verla directamente aquí:

Presentación: aquí. Código antes de aplicar los refactorings: aquí.

Les dejo el video gentilmente editado por la gente de AltNetHispano, si quieren un adelanto, lean el resumen que dejo abajo.

Quiero compartir en este post es un breve resumen sobre los temas que surgieron como preguntas y las repercusiones con el fin de que sirva de guia para aquel que quiera ver el video de 2 horas y algo más.

Mostré 3 o 4 ejemplos de código real de alguno de mis proyectos o extractado de algún caso real de clientes de consultoría.

En el primer ejemplo transformamos una clase que violaba claramente el principio de responsabilidad única. Separamos el código en dos clases. Luego avanzamos un poco más sobre el caso analizando una violación al principio de inversión de la dependencia y también codificamos una solución.

En el segundo ejemplo tomamos como base una consulta hecha por Edgar Ramos la lista de AltNetHispano, en el que planteaba un problema que me pareció muy útil para demostrar el principio abierto-cerrado.

El tercer ejemplo vimos el principio de segregación de interfaces. Presenté una refactorización del patrón repositorio separándolo en un repositorio básico basado en generics y uno o más Enhanced Query Objects del gran @fabiomaulo (el gran ausente de la VAN, el pobre estaba sin PC, parece).

Hablando sobre el ejemplo anterior conté una anécdota sobre un reemplazo de repositorios que tuvimos que encarar (desde IBatis.NET a NHibernate) y nos costó bastante por estar en clara violación del principio de sustitucion de Liskov.

El cuarto ejemplo fue una respuesta a la consulta de un colega sobre un procesador de archivos basado en reglas que fuera configurable. Propuse una solución basada en interfaces y Windsor como container de inyección de dependencias.

Tanto durante la VAN como en twitter (aquí y aquí) surgieron comentarios interesantes y preguntas (ver repercusión aquí). Sobre todo esto trataré de escribir posts ampliando mis respuestas.

Por último los comentarios que me llenan de orgullo (aquí, aquí y aquí) puesto que vienen de mis colegas, a los cuales también respeto mucho.

Si lo desean pueden descargar la presentación y la

Referencias:

[1] http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
[2] http://en.wikipedia.org/wiki/Solid_(object-oriented_design)
[3] http://www.lostechies.com/blogs/chad_myers/archive/2008/03/07/pablo-s-topic-of-the-month-march-solid-principles.aspx
[4] http://blogs.msdn.com/b/cdndevs/archive/2009/07/15/the-solid-principles-explained-with-motivational-posters.aspx
[5] http://cdn.cloudfiles.mosso.com/c82752/pablos_solid_ebook.pdf
[6] http://www.hanselminutes.com/default.aspx?showID=163

Gracias a todos.

Refactoring State/Strategy

Este post nació a partir de una consulta en la lista de Patrones del Grupo de Usuarios Microsoft.

En mi opinión y partiendo de la poca información que puede intercambiarse en las listas sobre el problema concreto, una de las posibilidades es el uso combinado de los patrones State/Strategy (un refactoring definido por Fowler en su libro, un esquema puede verse aquí).

Brevemente, Leandro necesitaba calcular un impuesto sobre una transacción y el algoritmo de cálculo depende del tipo de cliente y de algun dato adicional (supongamos que entendí correctamente el problema).

La condición para aplicar State es que tenga un caso en el cual el comportamiento del cliente (en este caso, el tipo de liquidador de impuesto) dependa del estado (de un estado o situacion) que el cliente tenga en ese momento. Otra de las condiciones es tener un switch que reemplazar.

Bueno, ahi va algo de codigo (escrito directamente en el blog, sería raro que compile!!!)…

// La clase Cliente
public class Cliente {
   // Este es el estado en cuestion, en principio puede ser privado
   private TipoCliente tipoCliente;

   // Estamos suponiendo, tambien, que cuando se crea el cliente
   // queda ya configurado el tipo, aunque nada impide que
   // este estado cambie durante la vida del cliente.
   public Cliente( TipoCliente tipoCliente ) {
      this.tipoCliente = tipoCliente;
   }
}

// Ahora definimos el tipo, una clase abstracta
public class TipoCliente {
}

// Un tipo de cliente concreto
public class TipoClienteExtranjero : TipoCliente {
}

// Otro tipo de cliente concreto
public class TipoClienteEmpresa : TipoCliente {
}

Bien, hasta aca tenemos la estructura basica armada, ahora veamos como resolvemos el tema de obtener el tipo de calculador de impuesto.

// Primero definimos la interfaz para el calculador
public interface ICalculadorImpuesto {
   // Este metodo deberia calcular el impuesto sobre
   // la transaccion y devolver un objeto que defina
   // el impuesto aplicado (no defini estas dos clases)
   Impuesto CalcularImpuesto( Transaccion trx );
}

// Ahora definimos un calculador facil, para empresas extranjeras
public class CalculadorImpuestoExento : ICalculadorImpuesto {
   public Impuesto CalcularImpuesto( Transaccion trx ) {
      // Aca, de paso aplicamos el patron SpecialCase,
      // algo parecido al DateTime.MinValue
      return Impuesto.Zero;
   }
}

Esta bien, hagamos uno un poco mas complejo

// El que calcula el impuesto a los movimiendos de debito
// y credito para ctas ctes...
public class CalculadorImpuestoLey25413CtaCte : ICalculadorImpuesto {
   public Impuesto CalcularImpuesto( Transaccion trx ) {
      return new Impuesto( trx.Monto * 0.012 );
   }
}

// y el impuesto a los movimiendos de debito y credito para
// cajas de ahorro
public class CalculadorImpuestoLey25413CA : ICalculadorImpuesto {
   public Impuesto CalcularImpuesto( Transaccion trx ) {
      return new Impuesto( trx.Monto * 0.006 );
   }
}

Ahora apliquemos esto en nuestra clase Cliente

// La clase Cliente
public class Cliente {
   ...
   // Este metodo delega en el metodo del tipo de cliente
   public ICalculadorImpuesto ObtenerCalculadorImpuesto() {
      return tipoCliente.ObtenerCalculadorImpuesto( this );
   }
   ...
}

Falta ahora modificar las clases de tipos de cliente

// En la clase abstracta
public class TipoCliente {
   public abstract ICalculadorImpuesto ObtenerCalculadorImpuesto( Cliente cliente );
}

// Un tipo de cliente concreto
public class TipoClienteExtranjero : TipoCliente {
   public override ICalculadorImpuesto ObtenerCalculadorImpuesto( Cliente cliente ) {
      // Aqui devuelvo el claculador que necesito
      // Para extranjeros, exento, por ejemplo
      return new CalculadorImpuestoExento();
   }
}

// Otro tipo de cliente concreto
public class TipoClienteEmpresa : TipoCliente {
   public override ICalculadorImpuesto ObtenerCalculadorImpuesto( Cliente cliente ) {
   // Aqui devuelvo el claculador que necesito
   // Aqui vemos el caso en que el State consulta al
   // objeto que lo contiene para decidir.
   // ( implementacion sencilla! )
   if ( cliente.TipoCuenta == "CtaCte" )
      return new CalculadorImpuestoLey25413CtaCte();
   else
      return new CalculadorImpuestoLey25413CA();
   }
}

Por ultimo, veamos como se usaria esto en el ejemplo que se me ocurre, por ejemplo, en metodo que tiene que calcular el impuesto de la transaccion:

public void RegistraTransaccion( Cliente cliente, Transaccion trx ) {
   ICalculadorImpuesto ci = cliente.ObtenerCalculadorImpuesto();
   Impuesto imp = ci.CalcularImpuesto( trx );
   RegistrarTansaccionEImpuesto( trx, imp );
}

Bueno, espero que esto ayude. Aqui el patron State esta en la familia de clases TipoCliente y el Strategy en el calculador de impuestos.

TDD y Arquitectura en Rosario

Luego de tres años, el último viernes y sábado estuve en Rosario compartiendo buenos momentos con colegas de esa ciudad.

Lo mejor (y el verdadero motivo del viaje) fue la cena y el almuerzo (pizza y asado respectivamente).

El viernes los aburrí un poco con una sesión sobre TDD. Si alguien esta interesado puede acceder a la grabación aquí.

También pueden descargar el archivo WMV desde este link (click secundario y guardar destino – el tamaño aproximado es 80MB).

El sábado (mientras haciamos tiempo antes de ir a la parrilla), hablamos de MonoRail.

Muchas gracias a mis colegas rosarinos. Nos veremos pronto.