miércoles, 15 de marzo de 2017

Cuando utilizar struct

Definir Struct cuando tenga las características siguientes:
  • Representa lógicamente un valor único, de forma similar a los tipos primitivos (intdouble, etc..).
  • Tiene un tamaño de instancia inferior a 16 bytes.
  • Es inmutable.
  • No tiene que aplicar la conversión boxing (cast) con frecuencia.
  • Como parámetro de un método es pasado por valor, en cambio una clase es pasada por referencia.
En los demás casos, debe definir los tipos como clases.

Error al resolver una dependencia

En muchas ocasiones cuando usamos abstracciones y tenemos un contenedor de inversión de dependencias que resuelve dichas abstraciones, como por ejemplo Unity o Autofac, es posible que nos surja un error similar al siguiente:

"An error occurred when trying to create a controller of type 'Prototype02Controller'. Make sure that the controller has a parameterless public constructor."

Esto ocurre porque tienes un controlador en una web Api similar al siguiente:

    [RoutePrefix("api/authentication")]
    [ExceptionsHandler]
    [AuthorizeAD(new string[] { "MasterRole" })]
    public class AuthorizationController : ApiController
    {
        private readonly IAuthorizationService _authorizationService;
        public AuthorizationController (AuthorizationService authorizationService)
        {
            Throw<ArgumentNullException>.WhenObject.IsNull(() => authorizationService);
            _authorizationService = authorizationService;
        }

        [HttpGet]
        [Route("getAuthenticatedUserAsync")]
        [ExceptionsHandlerAttribute]
        public async Task<HttpResponseMessage> GetAuthenticatedUserAsync()
        {
            dynamic user = await _authorizationService.GetAuthenticatedUserAsync();
            if (user == null)
                return null;
            return Request.CreateResponse(HttpStatusCode.OK, new { user });
        }
    }

Estamos pasando un objeto en lugar de una abstracción por lo que el contenedor de inversión de dependencias no sabrá resolverlo y nos lanzará el error que hemos visto.


viernes, 16 de diciembre de 2016

Inyección de dependencias

Inyección de dependencias






Explicaremos que es la inyección de dependencias y como se aplica.
También veremos porque la inyección de dependencias ayuda a tener un código más sencillo de mantener. Crearemos dos proyectos iguales, uno con inyección de dependencias y el otro sin ellas. Veremos porque el código con inyección de dependencias puede tener pruebas unitarias sólidas que solo prueban pequeñas partes de ese código, mientras que en el código sin inyección de dependencias las pruebas son frágiles, ya que dependerán de todo los artefactos que componen el software.
Es un patrón con el cual se consigue que las cosas que cambian más (las implementaciones concretas) dependendan de las cosas que cambian menos (abstracciones o interfaces).
Uno de los principios de diseño de software más conocido es el Principio de Responsabilidad única, el cual dice: “Un objeto solo tiene que tener una razón para cambiar”. Para conseguir que se cumpla este principio es necesario que el objeto delegue responsabilidades a otros objetos.
Por ejemplo, un objeto PaySheet tiene un método que calcula el total de la nómina. A primera vista esta clase cumple con su cometido que es el cálculo de la nómina, pero veamos un ejemplo muy básico de ese cálculo total:
public class Paysheet
{
    public decimal Total { getset; }
    public decimal Irpf { getset; }
    public decimal Base { getset; }
    public decimal Ssg { getset; }
    public void CalculateTotalPaysheet()
    {
        var valueIrpf = (Base  * Irpf) / 100;
        var valueSsg = (Base  * Ssg) / 100;
        Total = Base  - valueIrpf - valueSsg;
    }
}


Como podemos ver el cálculo de la nómina depende de dos descuentos, el Irpf y la seguridad social. Si mañana cambia la forma de calcular el valor del irpf o el valor de la seguridad social, tendríamos dos razones más para que este objeto cambie. Por lo tanto, esta clase tiene tres razones por la que cambiar, calcular el valor del irpf, calcular el valor de la seguridad social y calcular el total de la nómina.
Para evitar esto, tenemos que separar responsabilidades y lo podríamos hacer de la siguiente forma:
public class Irpf
 {
     private readonly decimal _irpf = 18m;
 
     public decimal Calculate(decimal paysheetBase)
     {
         return (paysheetBase * _irpf) / 100;
     }
 }
 public class Ssg
 {
     private readonly decimal _ssg = 4.10m;
     public decimal Calculate(decimal paysheetBase)
     {
         return (paysheetBase * _ssg) / 100;
     }
 }
public class Paysheet
{
    private decimal _total;    
    private decimal _base;
    public Paysheet()
    {
      _base = 2000m; 
    }
 
    public void CalculateTotalPaysheet()
    {
        Irpf irpf = new Irpf();
        var valueIrpf = irpf.Calculate(_base);
        Ssg ssg = new Ssg();
        var valueSsg = ssg.Calculate(_base);
 
        _total = _base - valueIrpf - valueSsg;
    }
 
}


Ahora si cambian los requisitos para calcular el valor del descuento del irpf y de la seguridad social, la clase Paysheet no tiene que ser modificada.
Este código tiene un problema y es que se están instanciando dos objetos dentro del método CalculateTotalPaysheet. ¿Por qué esto es un problema? porque estos objetos instanciados no tienen forma de poder ser sustituidos y evita que la clase se pueda heredar. Si heredas de Paysheet, el método CalculateTotalPaysheet va a realizar siempre el mismo cálculo. No se puede sustituir.
Vamos a ver qué pasa si heredamos:
public class Main
 {
     public Main()
     {
         PaysheetFirstChild paysheetFirstChild = new PaysheetFirstChild();
         paysheetFirstChild.CalculateTotalPaysheet();

         PaysheetSecondChild paysheetSecondChild = new PaysheetSecondChild();
         paysheetSecondChild.CalculateTotalPaysheet();
     }
 }
 public class PaysheetFirstChildPaysheet
 {

 }
 public class PaysheetSecondChild : Paysheet
 {

 }
public class Paysheet
{
    private decimal _total;    
    private decimal _base;
    public Paysheet()
    {
      _base = 2000m; 
    }
    public void CalculateTotalPaysheet()
    {
        Irpf irpf = new Irpf();
        var valueIrpf = irpf.Calculate(_base);
        Ssg ssg = new Ssg();
        var valueSsg = ssg.Calculate(_base);
 
        _total = _base - valueIrpf - valueSsg;
    }
 
}


Las dos sentencias en el cliente calcularán el mismo total. No hay forma de hacer que el cálculo sea distinto.
Se propone utilizar el patrón de inyección de dependencias para solucionar este problema.
public class Main
 {
     public Main()
     {
         IIrpf firstIrpf = new Irpf();
         firstIrpf.Calculate(10000);
         ISsg firstSsg = new Ssg();
         firstSsg.Calculate(10000);
         PaysheetFirstChild paysheetFirstChild = new PaysheetFirstChild(firstIrpf, firstSsg);
         paysheetFirstChild.CalculateTotalPaysheet();

         IIrpf secondIrpf = new Irpf();
         secondIrpf.Calculate(2000);
         ISsg secondSsg = new Ssg();
         secondIrpf.Calculate(2000);
         PaysheetSecondChild paysheetSecondChild = new PaysheetSecondChild(secondIrpf, secondSsg);
         paysheetSecondChild.CalculateTotalPaysheet();
     }
 }
 public class PaysheetFirstChild : Paysheet
 {
     public PaysheetFirstChild(IIrpf irpf, ISsg ssg) 
         : base(irpf, ssg)
     {
     }

 }
 public class PaysheetSecondChild : Paysheet
 {
     public PaysheetSecondChild(IIrpf irpf, ISsg ssg) : base(irpf, ssg)
     {
     }
 }
 public class Paysheet
 {
     public decimal Total { getset; }
     private decimal _base = 2000m;

     private readonly IIrpf _irpf;
     private readonly ISsg _ssg;
     public Paysheet(IIrpf irpf, ISsg ssg)
     {
         _irpf = irpf;
         _ssg = ssg;
     }
     public void CalculateTotalPaysheet()
     {
         var valueIrpf = _irpf.Calculate(_base);
         var valueSsg = _ssg.Calculate(_base);

         Total = _base - valueIrpf - valueSsg;
     }

 }
 public interface IIrpf
 {
     decimal Calculate(decimal _paysheetBase);
 }

 public class Irpf:IIrpf
 {
     private readonly decimal _irpf = 18m;

     public decimal Calculate(decimal _paysheetBase)
     {
         return (_paysheetBase * _irpf) / 100;
     }
 }
 public interface ISsg
 {
     decimal Calculate(decimal _paysheetBase);

 }
 public class Ssg:ISsg
 {
     private readonly decimal _ssg = 4.10m;
     public decimal Calculate(decimal _paysheetBase)
     {
         return (_paysheetBase * _ssg) / 100;
     }
 }



Está claro que tenemos que escribir más código, pero las ventajas a posteriori son muchas. Si en la mitad del desarrollo de nuestra aplicación nos cambian la forma de cálculo del Irpf solamente tengo que modificar la clase Irpf. El resto de mi código seguiría intacto. Sería fácil de modificar sin afectar a otras partes de nuestra aplicación sólo al cálculo del irpf.

         IIrpf firstIrpf = new Irpf();
         ISsg firstSsg = new Ssg();


Ahora podréis pensar que aún seguimos teniendo dos instancias en nuestro código, pero hay una diferencia fundamental y es que el objeto Paysheet ha delegado su instanciamiento a otro sitio, en este caso le ha dejado la labor al cliente. Aquí es donde entre la inversión de control (IoC) que se encarga de hacer esta instanciación por nosotros.

5.1 Definición de IoC

La inversión de control no es más que delegar ciertos trabajos a “agentes externos” a nuestro software. Por ejemplo, un agente externo a nuestro software puede ser el Framework .NET. Dejamos que muchos trabajos los haga él, por ejemplo:
string test = "Prueba-'1'";
test = test.Replace('-''/');

En este código estamos dejando que el Framework.Net se encargue de sustituir los guiones por barras en la variable “test”.
Cuando usamos el patrón de inyección de dependencias, para evitarnos la instanciación utilizamos un framework que se encargue de ello por nosotros, como por ejemplo Unity o Autofac.
En nuestro proyecto estamos utilizando Autofac para resolver la inyección  de dependencias. Un controlador común de nuestras webapi puede ser como el siguiente:
[RoutePrefix("api/authentication")]
 [ExceptionsHandler]
 public class AuthenticationController : ApiController
 {
     private readonly IAuthorizationService _authorizationService;
     public AuthenticationController(IAuthorizationService authorizationService)
     {
         Throw<ArgumentNullException>.WhenObject.IsNull(() => authorizationService);
         _authorizationService = authorizationService;
     }

     [HttpGet]
     [Route("getAuthenticatedUserAsync")]
     [ExceptionsHandlerAttribute]
     public async Task<HttpResponseMessage> GetAuthenticatedUserAsync()
     {
         dynamic user = await _authorizationService.GetAuthenticatedUserAsync();
         if (user == null)
             return null;
         return Request.CreateResponse(HttpStatusCode.OK, new { user });
     }
 }


¿Quién resuelve esta dependencia? Cuando se construye el controlador alguien tiene que pasarle al constructor de esta clase un objeto que implemente la interfaz IAuthorizationService. El contenedor de inversión de control (Autofac) se encarga de hacer esto por nosotros. Para que Autofac funcione tenemos que configurarlo donde comienza nuestra aplicación.

5.2 Configuración de Autofac

public static void Configure()
{
    var builder = new ContainerBuilder();
    var config = GlobalConfiguration.Configuration;
    var assemblies = new Assembly[]
    {
        typeof(Application.Authorization.AuthorizationService).Assembly,
        typeof(PersonnelRepository).Assembly,
        typeof(AuthorizationLogic).Assembly,
        typeof(IUnitOfWork).Assembly,
        typeof(DataFactory).Assembly,
        typeof(IExceptionsManager).Assembly,
         typeof(ClaimManagementFactory).Assembly,
         typeof(ICoreService).Assembly

    };
    builder.RegisterAssemblyTypes(assemblies)
      .AsImplementedInterfaces()
      .InstancePerRequest();
    //register web api controllers
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());


    var container = builder.Build();
    config.DependencyResolver = new AutofacWebApiDependencyResolver(container);   
}

Resumiendo este código, podríamos decir que el contenedor registra todos los ensamblados de la aplicación, indicándole una clase o interfaz de cada uno de ellos. Cuando la aplicación llame a AuthenticationController, Autofac construirá el objeto que solicita el constructor buscando la clase que tenga implementada la interfaz IAuthorizationService.


En el ejemplo mostraremos una solución con dos capas, la capa de negocio y la capa de datos en su forma clásica de implementación y con inyección de dependencias. Veamos el diagrama de uno y otro:

6.1 Diagramas de dependencias


La solución con inyección de dependencias consta de cuatro proyectos:
  • ·       Business
  • ·       Contracts
  • ·       Entities
  • ·       Data

La solución clásica consta de dos proyectos:
  • ·       Business
  • ·       Data

Como se puede ver en el diagrama la solución clásica tiene una dependencia muy clara, el proyecto Business está fuertemente acoplado al proyecto Data. La sustitución del proyecto data no se podrá realizar de forma sencilla. La capa de negocio se verá afectada y también la tendríamos que modificar. En cambio, en la solución con inyección de dependencias el proyecto Business no conoce nada del proyecto Data. Los dos proyectos dependen débilmente del proyecto Contracts. El proyecto Contracts contiene los contratos que debe cumplir el proyecto Data, es decir, cualquier proyecto que cumpla esos contratos podrá ser utilizado por el proyecto business.
En la solución de inyección de dependencias existe un proyecto Entities que usa el proyecto Business y el proyecto Data. Este proyecto evita el acoplamiento de Business con Data.
¿Se podría juntar lo que hay en el proyecto Contracts con lo que hay en el proyecto Entities? La respuesta es . Las dos cosas tienen que ser utilizadas por el proyecto Business y el proyecto Data. El motivo de separarlo es porque un proyecto cliente que implemente la capa data y la capa business no tiene por qué conocer las entidades. Si lo separamos en dos proyectos, el cliente no referenciará el proyecto Entities, en cambio el proyecto Contracts si es necesario.

6.2 Porque usar inyección de dependencias

En el siguiente ejemplo vemos cómo se implementaría la inyección de dependencias en la capa lógica de una aplicación y la diferencia con otra que no implementa dicha inyección.

En el ejemplo el cliente utiliza la capa lógica de clientes para obtener un listado de clientes. En el método convencional la capa lógica inicializa en el constructor la capa de datos, en cambio con la inyección de dependencias la capa lógica espera que le den un objeto que cumpla el contrato IClientData.
Para usar la inyección de dependencias, a priori, tenemos que escribir más código que del modo convencional, pero esto a largo plazo terminamos agradeciéndolo.
Imaginar que mañana nos piden una modificación. Ahora recibimos los clientes de dos proveedores de datos distintos. En el modo convencional tendríamos que modificar la lógica de la clase clientLogic o crear otra clase para el nuevo proveedor. En cambio con la inyección de dependencias la lógica no hay que tocarla.