martes, 4 de septiembre de 2007

[Patterns] Distributed Applications using Facade Pattern

Este patrón tan sencillo es seguramente uno de los más importantes en el desarrollo de aplicaciones que publican sus servicios mediante Web Services. El motivo de este post es ayudar a entender la forma correcta de implementar Web Services con .Net.

El problema

Afortunadamente hoy contamos con muchas herramientas y facilidades para la creación y publicación de servicios web. En .Net, es increiblemente facil crear un servicio web a partir de una clase, solo hay que extender nuestra clase de la clase System.Web.Services.WeServices y adornar el o los metodos que queremos publicar con [WebMethod] y listo. Por ejemplo:


using System;
using System.Web.Services;

public class HelloWorld: WebService {
[WebMethod(Description="Returns Hello", EnableSession=false)]
public string Say() {
return "Hello";
}
}

El problema con estas facilidades es que muchos desarrolladores entienden que el objetivo de esto es exponer en el cliente, proxies mediantes, los objetos de negocios que se encuentra en el servidor. Esta creencia promueven un mal estilo de programación de los servicios web. Es más, no son servicios ya que se parecen mas a llamadas RPC o RMI. Esto es un error. No deben exponerse los objetos de negocio mediante un WebService.

Un escenario real: En un desarrollo para una empresa de reservas de hoteles, teniamos las clases Hotel, Habitacion, Reserva, Pasajero, Temporada y otras más. Un amigo se encargaba del desarrollo del cliente y sus necesidades eran claras, "necesito una lista con las disponibilidades (con los dias disponibles) y precios de las habitaciones de los hoteles en esos dias y la descripción de las comodidades o servicios que incluyen en esa temporada". Este y otros requerimientos no se corresponden con ningún objeto del negocio, es decir, sencillamente no se resuelven serializando y enviando ningún objeto del negocio.

La solución

La solución consiste en crear un Facade cuyos métodos representen los servicios que puede brindar la aplicación como por ejemplo: obtener disponibilidades de tal fecha a tal fecha para tantas personas en determinado sitio turístico, obtener nuevas reservas para un hotel determinado, reservar, cancelar reserva, etc.

Ahora, por lo general los métodos del Facade no tendrán problemas en cuanto a los tipos de parámetros a recibir ya que serán (repito, por lo general) tipos simples como int, DateTime, String, Boolean, Double, etc. Pero sí requerirán retornar al cliente tipos especiales que, como dije antes, no se corresponden con los objetos de negocio. Entonces esto ya no es una simple clase "ReservationFacade" sino que se trata de un componente (o layer) con sus propios tipos como Availability, Recommend, etc. Si bien estos tipos pueden, por sus nombres, parecer que pertenecen a los tipos del dominio en realidad no lo son. Por ejemplo, Recommend puede contener un destino o zona turística recomendada junto con una lista de ofertas de tipos de habitaciones con sus precios en distintos hoteles y los periodos de validez de estas recomendaciones.

Ventajas de este patron:


  • Facil de responder a los cambios. Si el Web Service debe modificarse para ajustarse a los nuevos requerimientos del negocio entonces solo es necesario modificar el Facade.
  • Facil de mantener. Es posible modificar la estructura interna (refactoring) de las clases de negocio sin alterar el contrato con los clientes de WS. Ya que no se crean dependencia entre las clases de negocio con las aplicaciones clientas.
  • Responde a la idea de servicios. Los servicios se consumen en operaciones atómicas. Es decir, el servicio de "Reservar habitación" se realiza mediante un solo mensaje con toda la información necesaria y es el Facade quien se encarga de realizar todas las operaciones (seguramente en una transacción).
  • Son mas veloces. Por la misma razón que expongo arriba se realizan muchas menos idas y vueltas desde el servidor al cliente y viceversa.


La ventaja quizás mas importante es independizar el WS del resto de la aplicación ahorrandonos de tener que regenerar el WS (salvo cuando tocamos el Facade) y por lo tanto evitamos tener que regenerar los proxies en todos los cliente de nuestro WS y recompilar todo, tanto nosotros como todos nuestros clientes que pueden estar utilizando nuestros servicios somos más felices.

Otra ventaje que se deriva del punto anterior es que el versionado de nuestro servicio se simplifica considerablemente.

Lucas Ontivero

No hay comentarios: