Dependencias ocultas entre clientes y servicios

Hace unos días, en una revisión de código, encontré una definición de interfaz de un servicio que no me gustó. No fue inmediatamente evidente para mi pero uno de sus métodos era un code smell.

Esta es la interfaz:

<span style="color: blue;">public interface </span><span style="color: #2b91af;">IIpStsStore</span>{
    <span style="color: blue;">void </span>AddCredential(<span style="color: blue;">string </span>userName, <span style="color: blue;">string </span>password);
    <span style="color: blue;">void </span>RemoveCredential(<span style="color: blue;">string </span>userName);
    <span style="color: blue;">bool </span>CredentialExist(<span style="color: blue;">string </span>userName);
}

El método que me olía mal es el último. Luego de exprimir el cerebro un poco me di cuenta del motivo. Ese método, a mi juicio, propicia un acoplamiento innecesario entre el cliente del servicio y la implementación de dicho servicio.

Si exponemos ese método seguramente el cliente del servicio lo va a usar y no tendremos control de este uso, es decir, no sabremos exactamente cuando van a utilizarlo.

Supongamos que la primera implementación de ese servicio accede directamente al recurso donde se almacenan las credenciales. En ese caso, si el cliente llama a AddCredential() e inmediatamente llama a CredentialExist(), todo funcionará correctamente.

El problema aparecerá cuando hagamos otra implementación del servicio IpStsStore que funcione en forma asíncrona. En ese caso ya no habrá garantía de que la secuencia de métodos mencionada mas arriba siga funcionando.

En definitiva, tenemos un acoplamiento entre el cliente y la implementación del servicio, algo que siempre debe tratar de evitarse, además, como suele ocurrir en estos casos, luego de pensar un poco el diseño, ese método tampoco era necesario, un típico caso YAGNI.

Posted in arquitectura, diseño, tips | Leave a comment

Que nunca falte un registro de actividad en tu aplicación. Nunca.

La semana pasada un cliente me llamó debido a que una de sus aplicaciones recién lanzada estaba un tanto inestable. Quiero compartir hoy con ustedes la recomendación que le di, la mas simple y mas efectiva que recuerdo haber dado.

Mas allá de revisar algunas cuestiones directamente relacionadas con las inestabilidades reportadas por usuarios finales, lo primero que les pedí es que me mostraran los logs para enterarme de que no los tenían.

Hoy no hay excusas para no tener información de este tipo en la plataforma .NET, todos los tipos de aplicaciones (Web, Desktop, Servicios, etc.) proveen un mecanismo centralizado de

Aquí algunos consejos básicos:

  • Registren todas las excepciones (básico)
  • No es necesario utilizar try – catch innecesariamente en todo su código, es suficiente con engancharse en el handler centralizado.
  • Registre información con distinto nivel de detalle (los niveles corresponden a log4net pero los demás utilitarios tienen niveles similares), al menos:
    • ERROR: las excepciones, deje que el framework se encargue de mostrar mensajes, callstacks, etc. También registre errores de formato, de protocolo, etc, aunque también podría utilizarse el nivel WARNING (o WARN).
    • INFO: algunos puntos importantes del funcionamiento de la aplicación tales como el inicio, datos de configuración utilizados, finalización, etc.
    • DEBUG: en esta modalidad puede registrarse información mas detallada del funcionamiento de la aplicación.
  • Configure correctamente el nivel de registro en cada ambiente. Generalmente uso nivel INFO en ambientes de producción (que también registra WARN, ERROR y CRITICAL) y nivel DEBUG en ambientes de desarrollo.
  • Use herramientas sencillas (log4net, NLog) y registre la información en simple archivos de texto. Nunca me resulto cómodo utilizar el registro de eventos de Windows.

Para aplicaciones ASP.NET

<span style="color: blue;">protected void </span>Application_Start()
{
    Error += Application_Error;
}

<span style="color: #0000ff; font-size: x-small;"><span style="color: #0000ff; font-size: x-small;">private</span></span><span style="font-size: x-small;"> </span><span style="color: #0000ff; font-size: x-small;"><span style="color: #0000ff; font-size: x-small;">void</span></span><span style="font-size: x-small;"> Application_Error(    </span><span style="color: #0000ff; font-size: x-small;"><span style="color: #0000ff; font-size: x-small;">object</span></span><span style="font-size: x-small;"> sender, </span><span style="color: #2b91af; font-size: x-small;"><span style="color: #2b91af; font-size: x-small;">EventArgs</span></span><span style="font-size: x-small;"> e)

{
</span>
<blockquote><span style="font-size: x-small;">
</span><span style="color: #2b91af; font-size: x-small;"><span style="color: #2b91af; font-size: x-small;">Exception</span></span><span style="font-size: x-small;"> ex = Server.GetLastError();
</span></blockquote>
<span style="font-size: x-small;">
</span>
<blockquote><span style="font-size: x-small;">
log.Error(</span><span style="color: #a31515; font-size: x-small;"><span style="color: #a31515; font-size: x-small;">"Application_Error", ex</span></span><span style="font-size: x-small;">);
</span></blockquote>
<span style="font-size: x-small;">
<blockquote>
Server.ClearError();</blockquote>
}

</span>

Para aplicaciones Desktop

<span style="color: blue;">static void </span>Main()
{
<span style="color: #2b91af;"><span style="color: #333333;">    </span>AppDomain</span>.CurrentDomain.UnhandledException +=
        UnhandledExceptionHandler;

    <span style="color: #2b91af;">Application</span>.Run(<span style="color: blue;">new </span><span style="color: #2b91af;">Principal</span>());
}
<span style="color: blue;">private static void </span>UnhandledExceptionHandler(
    <span style="color: blue;">object </span>sender, <span style="color: #2b91af;">UnhandledExceptionEventArgs </span>args)
{
    <span style="color: blue;">var </span>e = (<span style="color: #2b91af;">Exception</span>)args.ExceptionObject;

    log.Error(<span style="color: #a31515; font-size: x-small;"><span style="color: #a31515; font-size: x-small;">"Application_Error", ex</span></span><span style="font-size: x-small;">);

</span>    <span style="color: blue;">if </span>(<span style="color: #2b91af;">MessageBox</span>.Show(<span style="color: #a31515;">"Reporte este error:\n" </span>+         e + <span style="color: #a31515;">"\n\n¿Desea copiarlo al portapapeles?"</span>,
        <span style="color: #a31515;">"Error en Clasificador"</span>,
        <span style="color: #2b91af;">MessageBoxButtons</span>.YesNo, <span style="color: #2b91af;"><span style="color: #333333;">        </span>MessageBoxIcon</span>.Error) == <span style="color: #2b91af;">DialogResult</span>.Yes)
    {
        <span style="color: #2b91af;">Clipboard</span>.SetText(e.ToString());
    }
    <span style="color: #2b91af;">Environment</span>.Exit(1);
}

Mas informacion:

Posted in arquitectura, tips | 3 Comments

¿Cuándo estaremos listos para Azure?

En la presentación de ayer en CodeCamp/09 uno de los colegas asistentes preguntó cuando estaría liberado Windows Azure para su uso en aplicaciones en producción.

No tenia idea de la respuesta en ese momento (ahora se que van a anunciarlo en Noviembre en el PDC), sin embargo salto a mi mente otra pregunta: ¿Cuándo estaremos nosotros listos para Azure?

Realmente es un entorno de ejecución diferente del que conocemos y que nos demandará bastante tiempo entender, dominar y encontrar la mejor manera de hacer las cosas.

También importante entender que Azure apunta a resolver problemas que muchos aún no tienen y, seguramente, las concesiones de diseño que se han hecho parecerán limitaciones excesivas. Suena raro que no tengamos file system, que no haya soporte para sesiones in process, que no existan otras comodidades similares pero son “pérdidas” razonables para aplicaciones masivamente escalables.

Estoy seguro de que Azure estará listo mucho tiempo antes que nosotros.

Sean buenos.

Posted in eventos | Tagged , , | Leave a comment

Azure en CodeCamp09 – Salió bien

Hace minutos terminamos con Mariano la conferencia sobre Azure en CodeCamp. Todo salió bien, un poco ajustados con el tiempo.

Dejo aquí los links de la charla.

Windows Azure Platform:
http://www.azure.com/

Space de la charla en Assembla:
https://www.assembla.com/wiki/show/prx-guamini

El repositorio con todos los artefactos de la charla:
http://code.assembla.com/prx-guamini/subversion/nodes/trunk

Gracias por venir!

Sean buenos

Posted in eventos | Tagged , | Leave a comment

Resulta que en la versión July 2009 CTP de las Windows Azure Tools for Microsoft Visual Studio se escapo un error. El proceso de build no copia el App.config del proyecto del WorkerRole.

Tiene solución, no se preocupen. Solo busquen en Google.

Sean buenos.

Posted on by Carlos Peix | Leave a comment

Azure mejora

Una buena noticia para el sufrido administrador de servicios Azure. El proceso de actualización de un servicio ahora permite realizar la operación en un solo paso: Upgrade.

Hasta hace unos días era necesario seguir el siguiente proceso: a) detener la aplicación; b) borrarla; c) subir la nueva y d) ponerla en marcha.

Aquí se ve la nueva opción:

image

Aquí pueden ver la pantalla que informa sobre el avance del proceso de actualización.

image

Aún hay que esperar varios minutos para que el proceso termine pero al menos puedo dedicarme a otra cosa.

Sean buenos.

Posted in tips | Tagged , | Leave a comment

CodeCamp 2009

El viernes pasado me enteré de que la charla con que nos postulamos para la edición 2009 de CodeCamp junto con Mariano había sido aceptada.

El título preliminar es “Cloud Computing – Explorando Windows Azure Services” asi que estaremos investigando más profundamente la plataforma Azure.

Publicaré en este blog los avances en el proceso, los interesados estan invitados a volver.

Nos vemos allá.

Posted in eventos | Tagged , | Leave a comment

Aggregates and repositories

This an informal post about this message in the DDD  list.
I really know that this should be answered by a DDD guru but, seeing that no one showed up, I’ll try to fill the space.
UPDATE Nov/19: Added section titles, service implementation to answer Tom’s comment, changed wrong method name from GetActorsNotAssociatedWithPictures to GetActorsNotAssociatedWithMovies (thanks Tom).
Specifications
Let’s say we have this domain: movies and actors acting in that movies.
The goal of this article is to outline how to design this simple domain, to define aggregates (and identify aggregate roots) and the corresponding repositories.
The domain model specifications:
  • Many actors can act in a movie
  • An actor could act in many movies
  • I should be able to remove movies (actors shouldn’t be removed)
  • I should be able to remove and actor (provided it is not associated with any movie)
Let me detail aside the query specifications:
  • I want to retrieve all the movies in what an actor participated
  • I want to retrieve all the movies older that 10 years
Model design
Now let me design the model. We should have at least two objects, Movie and Actor, so let’s start with that classes:
NOTE: code is in C# without IDE assistance and incomplete, for example, trivial accessors omitted.
public class Movie {
private string name;
private int yearPresented;
}
public class Actor {
private string name;
private int yearBorn;
}
OK, pretty simple. Now I’ll try to connect actors and movies. Let’s look for a classic in IMBD, Gone with the wind. If you scroll a page you can see the actors on that movie, they are the Cast, we could build an object Cast but I’ll choose a simple path, more on that later.
Let’s see, for example, for the Scarlett O’Hara character, the actress was Vivien Leigh.
OK, it’s enough of IMDB, let’s go to the model but let me clarify, it’s very important to make the best effort to find the formal (and ubiquitous) language, that’s why I gone to IMDB.
So, seems like a good first step is to build the Character object.
public class Character {
private Actor actor;
private string name;
}
Now is time to define aggregates, I see two:
  • The Actor aggregate including just an Actor instance as aggregate root.
  • The Movie aggregate including a Movie instance as an aggregate root and one or more Character instances. Each Character instance references one Actor aggregate (kind of foreign key in RDMS parlance).
Let me do another round adding some code to my classes (I’m showing code in the  Fowler‘s way):
Mental note: if Martin changed that old picture in his home page I think it’s time to change mine, it’s 10 years old.
public class Movie {

private IList cast = new List();
public Character AddCharacter(Actor actor, string characterName) {
Character newCharacter =
new Character(this, actor, string characterName);
cast.Add(newCharacter):
return newCharacter;
}

}
And the Character class
public class Character {

internal Character(Movie movie, Actor actor, string name) {
this.movie = movie;
this.actor = actor;
this.name = name;
}
private Movie movie;

}
Repositories design
Now I have this domain model pretty much I like it, let me outline the repositories interfaces (one for each aggregate). As you will see, I use the “one method per query” approach, I could use the more concise GetByCriteria approach but it tends to force me to leak the query API to the model.
public interface MovieRepository {
Movie GetByName(string name);
(1) IList GetByActor(Actor actor);
(2) IList GetByCharacterName(string characterName);
(3) IList GetAgedMoreThan(int years);
(4) void Delete(Movie movie)
}
public interface ActorRepository {
Actor GetByName(string name);
(5) IList GetActorsNotAssociatedWithMovies();
(6) void Delete(Actor actor)
}
(1) Should retrieve movies doing a simple join to compare the actor. Pretty easy to do with a good ORM.
(2) and (3) This is a easy queries as well.
(4) Should delete the Movie instances and all the Character instances associated. Actor instances remain untouched.
(5) Not a difficult query, after obtaining the Actors list we could use (6) to delete un referenced actors.
Services design (some of them)
Tom is curious on how to implement the “I should be able to remove and actor (provided it is not associated with any movie)” specification.
I would like to put this into a more real specification like that: “I should be able to purge old pictures and unreferenced actors”. For this spec I would build a maintenance domain service like that:
public interface CatalogMaintenanceService {
public void DeleteDataOlderThan(int yearsOld) {
IList oldMovies = moviesRepository.GetAgedMoreThan(yearsOld);
foreach (Movie movie in oldMovies)
moviesRepository.Delete(movie);

IList orphanedActors =
actorsRepository.GetActorsNotAssociatedWithPictures();
foreach (Actor actor in orphanedActors)
actorsRepository.Delete(actor);
}
}
This service call should be wrapped by a unit of work. The implementation depends on the persistence layer and application platform, for example, in a Web application with NHibernate, it’s usually implemented with a HttpModule.
Please, feel free to ask any question, I would try to answer according my possibilities.
See you
Posted in arquitectura, diseño | 7 Comments

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.

Posted in diseño, Q&A | Tagged | Leave a comment

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.

Posted in diseño | Tagged , | 2 Comments