Guillermo Valencia - Blog 
Este sitio web utiliza JavaScript. Por favor, habilítalo en tu navegador para que todo funcione correctamente.


Pruebas e Inversión de Control

Guillermo Valencia

Publicado el 02 de agosto de 2018

Tags: Patrones

Es habitual que tengamos la necesidad de integrar funcionalidad expuesta por componentes y servicios que están fuera del alcance del desarrollo que queremos probar. Las dependencias con sistemas externos afectan a la complejidad de la estrategia de pruebas, ya que es necesario contar con sustitutos de estos servicios externos durante el desarrollo.

Ejemplos típicos de estas dependencias son servicios Web, sistemas de envío de correo, fuentes u orígenes de datos, o simplemente, dispositivos hardware.

Estos sustitutos, muchas veces son exactamente iguales que el servicio original, pero en un entorno diferente al entorno de producción, es el caso de los entornos de desarrollo o de pruebas.

En otros casos es frecuente encontrarse con simuladores que exponen el mismo interfaz, pero realmente no realizan las mismas tareas que el sistema real, o las realizan contra un entorno controlado.

Para poder probar los escenarios más importantes, es necesario sincronizar el código de pruebas y el simulador de forma que desde la prueba se pueda saber a priori cómo será el comportamiento y así poder asegurar que el código a probar se ha ejecutado en las condiciones esperadas.
Simuladores

 

Este modelo de pruebas es muy conveniente para las pruebas de integración entre los diferentes módulos software de nuestra aplicación. Para ello es necesario que utilicemos interfaces que nos desacoplen de los sistemas externos, de manera que nuestros casos de uso del modelo de dominio trabajen directamente con las interfaces.

Para cada interfaz tendremos al menos dos implementaciones, una contra la fuente externa (o fuente real) y otra que la simule para nuestras pruebas.
Interfaces a implementaciones

 

¿Cómo elegiremos una u otra implementación dependiendo del entorno de ejecución?
Aquí nos surge un problema, y es que nuestra lógica de negocio debe ser capaz de instanciar tanto el objeto real como el objeto de pruebas, y decidir en cada caso cual debe utilizar.
Objetos reales o simulados

 

Y es aquí donde surge el término Inversión de control (IoC), que es el mecanismo de programación en el que el flujo de ejecución de un programa se invierte respecto a los métodos de programación tradicionales, en los que la interacción se expresa de forma imperativa haciendo llamadas a métodos o funciones. Tradicionalmente el programador especifica la secuencia de decisiones y procedimientos que pueden darse durante el ciclo de vida de un programa mediante llamadas a métodos, pero en su lugar, en la inversión de control se especifican respuestas deseadas a sucesos o solicitudes de datos concretas, dejando que algún tipo de entidad o arquitectura externa lleve a cabo las acciones de control que se requieran en el orden necesario y para el conjunto de sucesos que tengan que ocurrir.

Gracias a la orientación a objetos se puede definir un interfaz que cumplan tanto el objeto real como el objeto simulado, y hacer que el código a probar dependa tan sólo del interfaz que ambos implementan. Y se usará el patrón “Inversión de control” como mecanismo que permita elegir entre los dos tipos de objetos.

 

Dicho patrón puede ser implementado de diferentes formas. Las más comunes son:

  • Service Locator: en esta implementación, un servicio (Locator) es el encargado de saber qué instancia de un tipo concreto (interfaz) debe instanciar y retornar.
  • Service Locator

  • Dependency Injection: en esta implementación, existe un servicio (Builder) encargado de inyectar una implementación concreta de la interfaz al caso de uso. Esta implementación puede ser inyectada de varias maneras: por constructor, por propiedad o por parámetro.
  • Dependency Injection

Existen diferentes librerías que implementan el patrón “Inversión de Control”, como Microsoft Unity (https://msdn.microsoft.com/en-us/library/dn178463(v=pandp.30).aspx ) o StructureMap (http://structuremap.github.io/)



El Patrón CQRS

Guillermo Valencia

Publicado el 12 de marzo de 2018

Tags: Patrones

CQRS, del inglés “Command Query Responsibility Segregation” es un patrón arquitectónico que recomienda codificar los comandos y las consultas de forma separada, es decir, separar las consultas que no modifican el estado del sistema en una pila diferente y optimizada de los comandos que si modifican el estado del sistema.

CQRS puede ser implementado igualmente con Entity Framework, pero limitando las operaciones de cambio para que no tengamos la tentación de utilizarlas desde donde no debamos, saltándonos todas las reglas de negocio y directrices arquitectónicas.
Para ello, podemos utilizar un simple contenedor que encapsule la instancia del DBContext de EF y que solo exponga las operaciones de sólo lectura. Se puede ver un ejemplo en el siguiente enlace: https://msdn.microsoft.com/es-es/magazine/mt683793.aspx

La principal ventaja de CQRS es que eliminamos complejidad en el diseño del sistema, no es incompatible con DDD, sino que se trata de un patrón adicional a implementar dentro de DDD, haciendo que el dominio se centre en el modelo que modifica el estado del sistema, simplificando y optimizando la lógica encargado de las operaciones de lectura, generando un código más simple.

Aplicar CQRS no quiere decir que desde la capa de presentación instanciemos accedamos directamente a la capa de persistencia de datos, sino que utilizaremos un “microservicio” ubicado en la capa de Infraestructura que nos dará acceso a las operaciones de lectura de datos.

Patrón CQRS



El Patrón Unit of Work, manejando el contexto de Entity Framework

Guillermo Valencia

Publicado el 05 de febrero de 2018

Tags: C#, Patrones

Para la persistencia de datos siempre es recomendable utilizar un ORM (mapeo objeto-relacional) como Entity Framework (EF). A la hora de utilizar EF, hay que tener especial cuidado con el manejo del contexto de la BD , que implementa el patrón Unit of Work.

El patrón Unit of Work se explica aquí: https://coding.abel.nu/2012/10/make-the-dbcontext-ambient-with-unitofworkscope/

En el siguiente artículo se proponen una serie de recomendaciones sobre el manejo del contexto de EF: http://mehdi.me/ambient-dbcontext-in-ef6/

A continuación, incluyo un ejemplo de implementación del patrón Unit o Work basado en una variable “Thread Static”, ideal en entornos web, puesto que su tiempo de vida es por petición, y permite mantener cacheado el contexto de EF para una transacción completa entre las diferentes peticiones de usuario.


using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;

namespace MiEmpresa.MiAplicacion.Infrastructure.Services
{
    /// <summary>
    /// Ambito de vida "per request" del patrón unit of work.
    /// </summary>
    /// <typeparam name="TDbContext">The type of the DbContext</typeparam>
    public static class UnitOfWorkScope<TDbContext>  where TDbContext : DbContext, new()
    {
        /// <summary>
        /// Clase que encapsula el contexto real de la BD
        /// </summary>
        private class ScopedDbContext<T> : IDisposable where T : TDbContext, new()
        {
            /// <summary>
            /// Constructor
            /// </summary>
            public ScopedDbContext()
            {
                DbContext = new T();
                DbContext.Database.CommandTimeout = 100;
                ((IObjectContextAdapter)DbContext).ObjectContext.SavingChanges
                    += GuardAgainstDirectSaves;
            }
            
            /// <summary>
            /// Destructor
            /// </summary>
            ~ScopedDbContext()
            {
                Dispose(false);
            }


            /// <summary>
            /// El contexto real DbContext.
            /// </summary>
            public TDbContext DbContext { get; private set; }

            /// <summary>
            /// Evitamos llamadas directas a SaveChanges.
            /// </summary>
            public bool AllowSaving = false;

            /// <summary>
            /// Manejador para verificar las llamadas directas a SaveChanges.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void GuardAgainstDirectSaves(object sender, EventArgs e)
            {
                if (!AllowSaving)
                {
                    throw new InvalidOperationException("No realices llamadas directas a SaveChanges en un contexto perteneciente a UnitOfWorkScope. Utiliza UnitOfWorkScope.SaveChanges en su lugar.");
                }
            }

            /// <summary>
            /// Liberación explicita
            /// </summary>
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }

            /// <summary>
            /// Liberación implícita
            /// </summary>
            /// <param name="disposing"></param>
            protected virtual void Dispose(bool disposing)
            {
                if (disposing && DbContext != null)
                {
                    ((IObjectContextAdapter)DbContext).ObjectContext.SavingChanges
                        -= GuardAgainstDirectSaves;

                    DbContext.Dispose();
                    DbContext = null;
                }                
            }
        }

        /// <summary>
        /// Variable para almacenar el contexto de BD
        /// Se trata de una variable ThreadStatic, ideal para ser utilizada en web (una instancia por Request) y en servicios Windows.
        /// Para Windows Forms puede generar datos sucios puesto que la variable se quedaría a nivel de formulario.
        /// </summary>
        [ThreadStatic]
        private static ScopedDbContext<TDbContext> scopedDbContext;        

        /// <summary>
        /// Retorna el DbContext que utiliza este unit of work.
        /// </summary>
        public static TDbContext Context
        {
            get
            {
                if (scopedDbContext == null)
                {
                    scopedDbContext = new ScopedDbContext<TDbContext>();                    
                }
                return scopedDbContext.DbContext;
            }
        }

        /// <summary>
        /// Salva los cambios en el contexto
        /// </summary>
        public static void SaveChanges()
        {
            scopedDbContext.AllowSaving = true;
            scopedDbContext.DbContext.SaveChanges();
            scopedDbContext.AllowSaving = false;
        }

        /// <summary>
        /// Libera el contexto
        /// </summary>
        public static void Release()
        {
            if (scopedDbContext != null)
            {
                scopedDbContext.Dispose();
                scopedDbContext = null;
            }
        }
    }
}

 

También incluyo un ejemplo de “repositorio base” que puede ser utilizado para la implementación de los diferentes repositorios de entidades contra EF. Dicho “repositorio base” hace uso de “generics” para evitar el acoplamiento a un modelo o entidad concreta.


using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;

namespace MiEmpresa.MiAplicacion.Infrastructure.Data.Repositories
{
    /// <summary>
    /// Repositorio base de las operaciones contra BD
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal interface IBaseRepository<T> where T : class
    {
        /// <summary>
        /// Agrega una entidad
        /// </summary>
        /// <param name="entity"></param>
        void Add(T entity);

        /// <summary>
        /// Elimina una entidad por su identificador
        /// </summary>
        /// <param name="id"></param>
        void Delete(int id);

        /// <summary>
        /// Elimina una entidad
        /// </summary>
        /// <param name="entity"></param>
        void Delete(T entity);

        /// <summary>
        /// Obtiene todas las entidades
        /// </summary>
        /// <returns></returns>
        List<T> GetAll();

        /// <summary>
        /// Proporciona una entidad por su identificador
        /// </summary>
        T GetById(int id);

        /// <summary>
        //Libera el contexto
        /// </summary>
        void Release();

        /// <summary>
        /// Salva los cambios
        /// </summary>
        void Save();

        /// <summary>
        /// Realiza una búsqueda
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        List<T> SearchFor(Expression<Func<T, bool>> predicate);
    }


    /// <summary>
    /// Repositorio base de las operaciones contra BD
    /// </summary>
    /// <typeparam name="C"></typeparam>
    /// <typeparam name="T"></typeparam>
    internal class BaseRepository<C,T> : IBaseRepository<T> where T : class where C : DbContext, new()
    {
        /// <summary>
        /// Constructor sin parámetros
        /// </summary>
        public BaseRepository() { }

        /// <summary>
        /// Acceso al contexto de EF
        /// </summary>
        protected DbContext Entities
        {
            get
            {
                return UnitOfWorkScope<C>.Context;
            }
        }

        /// <summary>
        /// Proporciona una entidad por su identificador
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public T GetById(int id)
        {
            return Entities.Set<T>().Find(id);
        }

        /// <summary>
        /// Agrega una entidad
        /// </summary>
        /// <param name="entity"></param>
        public void Add(T entity)
        {
            Entities.Set<T>().Add(entity);
        }

        /// <summary>
        /// Elimina una entidad
        /// </summary>
        /// <param name="entity"></param>
        public void Delete(T entity)
        {
            Entities.Set<T>().Remove(entity);
        }

        /// <summary>
        /// Elimina una entidad por su identificador
        /// </summary>
        /// <param name="id"></param>
        public void Delete(int id)
        {
            T entity = GetById(id);
            Delete(entity);
        }

        /// <summary>
        /// Obtiene todas las entidades
        /// </summary>
        /// <returns></returns>
        public List<T> GetAll()
        {
            return Entities.Set<T>().ToList();
        }

        /// <summary>
        /// Realiza una búsqueda
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public List<T> SearchFor(Expression<Func<T, bool>> predicate)
        {
            return Entities.Set<T>().Where(predicate).ToList();
        }

        /// <summary>
        /// Salva los cambios
        /// </summary>
        public void Save()
        {            
            UnitOfWorkScope<PoolEntities>.SaveChanges();
        }

        /// <summary>
        /// Libera el contexto
        /// </summary>
        public void Release()
        {
            UnitOfWorkScope<PoolEntities>.Release();
        }

    }
}


Manipulación de objetos no manejados

Guillermo Valencia

Publicado el 08 de enero de 2018

Tags: C#, Patrones

En .NET Framework existe un mecanismo llamado “Garbage Collector”, GC o recolector de basura que se encarga de liberar aquellos objetos que ya no son necesarios o cuya referencia se ha perdido.
Esto supone una gran ventaja para los desarrolladores, ya que no se tienen que ocupar de dicha tarea, encargándose el propio GC de evitar la fragmentación de la memoria o su corrupción, evitando así las posibilidades de introducir errores adicionales en situaciones que no son triviales como sí ocurre con otros lenguajes de programación menos avanzados (C, C++).

El GC de .NET es un colector de basura generacional. Eso significa que clasifica los objetos en distintas generaciones, lo cual le permite realizar colecciones de basura parciales (de una o varias generaciones) y así evitar hacer siempre colecciones de basura completas de todo el heap de memoria del CLR de .NET. Esta característica es una de las más importantes en cuanto al rendimiento del GC, y permiten que el GC de .NET sea escalable para aplicaciones de alta concurrencia como por ejemplo aplicaciones ASP.NET.

El comportamiento del GC no exime por completo al desarrollador del uso de la memoria de la aplicación, ya que existen recursos que no son manejados por el CLR de .NET como son los recursos nativos que acceden por ejemplo a sistemas externos (BD, Servicios Web), acceso a ficheros o a APIS que interaccionan con el sistema operativo o con el hardware del sistema (tarjeta de video).
A continuación, se exponen los objetos más típicos con los que es necesario tener especial cuidado, pero hay muchos más, en general cualquiera que implemente la interfaz IDisposable:

  • Objetos de memoria no manejados: Stream, MemoryStream.
  • Objetos de conexión a BD: SqlConnection, DbConnection, SqlCommand, DbCommand, DataSet, SqlDataReader.
  • Clientes de WCF: ClientBase.
  • Modelo de Entity Framework: DbContext.
  • Acceso a recursos externos: WebClient, WebRequest, TcpClient.
  • Acceso a ficheros: FileStream, FileReader.

Un uso incorrecto de este tipo de objetos lastra sustancialmente el rendimiento general de la aplicación, ocasionando un gran uso de memoria en el lado del servidor.

Cuando trabajemos con objetos no manejados, es importante que seamos nosotros los responsables y encargados de liberar dichos objetos. Para ellos nos podemos ayudar del patrón “Dispose”: https://docs.microsoft.com/es-es/dotnet/standard/design-guidelines/dispose-pattern#basic-dispose-pattern

A continuación, muestro un ejemplo de implementación en C#:


/// <summary>
/// Ejemplo de clase que contiene objetos no manejados y que implementa la interfaz IDisposable
/// </summary>
private class MyCustomUnSafeObject : IDisposable
{
   /// <summary>
   /// Instancia de un objeto no manejado, que habrá que liberar adecuadamente
   /// </summary>
   private UnsafeObject instance;

   /// <summary>
   /// Constructor
   /// </summary>
   public MyCustomUnSafeObject()
   {
      instance= new UnsafeObject();      
   }
            
   /// <summary>
   /// Destructor
   /// </summary>
   ~MyCustomUnSafeObject()
   {
      Dispose(false);
   }

   /// <summary>
   /// Liberación explícita
   /// </summary>
   public void Dispose()
   {
      Dispose(true);
      GC.SuppressFinalize(this);
   }

   /// <summary>
   /// Liberación implícita
   /// </summary>
   protected virtual void Dispose(bool disposing)
   {
      if (disposing && instance!= null)
      {
         instance.Dispose();
         instance = null;
      }                
   }
}

Es muy importante implementar el destructor en este caso, ya que es el mecanismo que nos proporciona .NET para ejecutar código de finalización de un objeto de forma automática, antes de que el GC libere su memoria.

Este destructor debe ser muy rápido y óptimo, y nunca puede lanzar una excepción ni tampoco bloquear la ejecución debido a que todos los destructores de los objetos se ejecutan en un thread conocido como Finalizer.

Cuando el GC determina que los objetos están listos para ser finalizados los mete en una cola y dicho thread ejecuta los destructores de cada objeto secuencialmente. Por lo tanto, si se produce un bloqueo durante la finalización de alguno de los objetos, todo lo que venga detrás nunca será finalizado con todas las consecuencias que ello conlleva.
Para maximizar el rendimiento de nuestras aplicaciones .NET, debemos procurar que la menor cantidad posible de objetos sean finalizados por el GC, es decir, liberándolos nosotros manualmente.