domingo, 18 de agosto de 2013

Ejemplo MVC - Controladora base / Evento OnActionExecute

Para el inicio de la serie Ejemplos MVC vamos a ver sel siguiente ejemplo:

Crear una clase abstracta controladora y sobrescribir evento OnActionExecute
El ejemplo sirve para: 
  1. Tener Constructor/Objetos/propiedades/Dispose comunes para todos los controladores.
  2. Uso centralizado de sesiones y facilitar pruebas unitarias.
  3. Gestión de permisos.

Si heredamos las controladoras de la aplicación de una clase abstracta, podemos añadir objetos y/o propiedades comunes en el constructor. 

Primer paso. Clase abstracta básica de ejemplo

public abstract class ControllerBase:Controller
{
        protected IAplicacion oApp;
        protected BDEntities db = new BDEntities();

        public ControllerBase()
        {
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
}

Con este código se consigue:
Tener objetos comunes compartidos por todos los controladores. En el ejemplo un objeto tipo IAplicacion y BDEntitie. Son dos ejemplos básicos, IAplicacion es un ejemplo tipo de una interfaz con un objeto/s básico/s necesario en toda nuestra aplicación: Usuario, Permisos, Breadcrumbs, etc... BDEntitie representa un objeto de Entity Framework, también muy común en todo controlador de cualquier aplicación que use Entity.
Tener un constructor común de inicialización, en este caso ControllerBase, que está vacio.
Destructor común que liberará los recursos.

Segundo paso. Sobrescribir evento OnActionExecute
Además, si sobrescribimos el evento OnActionExecute en la clase base, podemos tratar de forma centralizada el estado del contexto http, es decir principalmente las sesiones. Esto permite facilitar la gestión de las mismas al estar centralizado, y a la vez facilita las pruebas unitarias. El evento OnActionExecute, es un evento del contexto http, y no se ejecuta al realizar las pruebas, por tanto facilita tener que hacer mocking del contexto de la sesión, bastará con hacer mocking de la interfaz de aplicación IAplicacion para realizar las pruebas. 
No obstante, quiero aclarar que esta es una solución para centralizar el contexto http y evitar tener que simularlo en las pruebas, sin embargo también es posible hacer mocking de las sesiones, dejo un link de ejemplo. 

protected override void OnActionExecuting(ActionExecutingContext ctx)
{
   //En la pantalla de Login NO se comprueba estado sesión.
    if (ctx.ActionDescriptor.ControllerDescriptor.ControllerName == "Login") return;

   //Recoger variable de sesión objeto Aplicación.
   oApp = System.Web.HttpContext.Current.Session[Constantes.sesApp] as Aplicacion;

   //Chequear permisos (Se trata este tema en el siguiente Post)

   if (oApp.Permisos.TienePermiso){
    //Si tiene permisos sigue el flujo de ejecución
    base.OnActionExecuting(ctx);
    return;
   }

   //Si no tiene permisos se limpia la sesión
   System.Web.HttpContext.Current.Session.Clear();
   //Redirige a pantalla de Login
    ctx.Result = RedirectToAction("Index", "Login");
}

Tercer paso: Declarar todos los controladores como heredados de la clase ControllerBase.
                    Declarar constructor que recibe por parámetro la interfaz IAplicacion.
Se consiguen controladores limpios de variables de sesión, fáciles de testear simulando el estado del objeto oApp, simulando el objeto/estado deseado a través de la interfaz IAplicacion.
La clave está en que al ejecutar los controladores el estado del objeto oApp se recoge de sesión, y al realizar las pruebas se le pasa falsificado(mockeado) por parámetro al constructor. Al estar el tratamiento de la sesión en el evento OnActionExecuting, no se producirá ninguna excepción.

    public class HomeController : ControllerBase
    {
        public HomeController(IAplicacion aplicacion)
        {
            oApp = aplicacion;
        }

        public ActionResult Index()
        {
           //Tu Código que hace uso de un objeto oApp(de IAplicacion)
        }
    }




jueves, 15 de agosto de 2013

Serie de ejemplos MVC

Hola de nuevo,

A riesgo de repetirme, voy a iniciar una serie de ejemplos de MVC, en concreto versión 4, con C#, pues no solo de reflexiones vive el programador, también debe de trabajar. Como estoy con un nuevo proyecto con MVC 4, a medida que avance, me voy encontrando con numerosos problemas comunes, que soluciono en su mayoría googleando. No obstante no siempre hago un copiar/pegar, sino que en ocasiones añado mejoras a esas soluciones o las tomo como base para adaptarlas a mi escenario. Con esto quiero decir que no tengo la intención de publicar nada que sea un copiar/pegar de otra web; todo lo que publique tendrá un añadido o adaptación personal, con la intención de agregar valor.

Voy a empezar con los temas que citaré a continuación, aunque por supuesto tengo la intención de ir ampliando el número de temas a tratar. De momento expondré ejemplos de los problemas que he adaptado, sobre los problemas con los que aun no me he enfrentado ni aun se que existen, espero poder escribir pronto. Así que espero que la serie sea tan larga como sea posible, tanto como dure mi trabajo como programador MVC y tenga vida la aplicación, que según se dice, si es útil, ha de ser por un tiempo indefinido.

Temas a tratar en los siguientes Posts:

Controladoras. Crear una clase abstracta controladora y sobrescribir evento OnActionExecute. Ejemplo de aplicación uso de sesiones y permisos.

Patrón ViewModel: Aplicar patrón ViewModel. Crear una clase abstracta para todos los viewModels. Ejemplo de aplicación control básico de navegación.

Vistas modales. Como simular vistas modales típicas de aplicaciones Windows, equivalente a ShowDialog() de Winforms.


domingo, 11 de agosto de 2013

Antipatrones (o antimarranadas)

Patrones de diseño de Software hay y muchos, en el artículo de la wiki son todos los que están, pero no están todos los que son, la lista es en realidad mucho más larga.
Ya que estamos de Vacaciones, hay tiempo de ponerse filosófico, el post de hoy trata sobre antipatrones de diseño, y no sobre patrones. La reflexión que hago es que tan importante o más es saber como no se deben hacer las cosas, que saber un patrón en concreto. Por poner un ejemplo, con el patrón singleton podremos resolver un problema de sección crítica en un lenguaje orientado a objetos, pero también podremos resolverlo de otras formas en un lenguaje funcional. Es decir que un patrón es una solución a un problema, pero no la única.

Sin embargo si hay un consenso universal sobre los antipatrones, que traducido a lenguaje llano quiere decir "No hagas marranadas". Si entras en un nuevo proyecto que utiliza el patrón X podrás adaptarte a gusto, sin embargo si tienes el legado de un programa que hace uso de antipatrones vas a odiar al programador que lo hizo y las horas que pasas con el mismo; esto es algo que a muchos programadores nos ha pasado alguna vez, y creo que también coincidiremos en esta sensación.

Cito algunos de los antipatrones más comunes, con los que casi todos nos hemos topado:

Botón mágico   Incrustar la lógica de la aplicación en el clic de un botón. Un secreto inconfesable de la mayoría de los principiantes.

Código espagueti Otro secreto inconfesable de los principiantes. En los años 90, cuando aun no existian frameworks web, era algo inevitable.

Cadenas mágicas Cadenas de texto "inteligentes" que determinan el flujo del programa, definen sesiones etc. Es un pecado cometido incluso por los generadores de código, por ejemplo el propio visual studio 2012 lo hace con el scaffolding y con los links a las vistas. Esto puede dar lugar a muchos errores tontos por errores tipográficos. Deben substituirse por constantes.

Programación por excepción y Ocultación de errores   Programar la lógica a base de Try/Catch, y para asegurarse, en caso de que falle algo imprevisto, no mostrar ningún mensaje de error. Así el programador cree que se lava las manos.

DRY (Don't Repeat Yourself): Copiar/Pegar código en un programa. Muy típico.

Reinventar la rueda: Aveces a los programadores nos gusta más inventar nuevas soluciones a un problema, que buscar si ya existe una solución para ese problema. Terrible error muy antiproductivo.



viernes, 9 de agosto de 2013

GDSYCT - Desarrollo guiado para que se pueda probar

Hola de nuevo,

Esta semana he estado un día aplicando en mi nuevo proyecto los patrones de diseño y principios relacionados con las pruebas: DI, IoC, Mocking, pruebas unitarias, TDD.

Hoy en día están muy de moda, así que como no quiero quedarme chapado a la antigua, he decidido que como estoy empezando un proyecto nuevo en MVC, era un buen momento para ponerme con el tema. Aparte de estar muy de moda, me lo habían aconsejado (eufemismo de casi obligado).

Bueno, no voy a ser yo quien defina estos conceptos, para eso ya está la wikipedia y numerosos posts. Esto es literaturaprogramada, no un blog para repetir los que otros dicen. Tengo la intención de postear artículos técnicos, pero solo si aportan algo que no sea fácil de encontrar; no es este el caso. Espero encontrar una excusa pronto para hacerlo.

En conclusión, yo tenía una idea equivocada del concepto TDD (Definición Wikipedia) , que es el que engloba todos estos conceptos. Hacer pruebas me parece bien, pero no acababa de entender el orden propuesto pero esta práctica:
  1. Elegir un requisito
  2. Escribir una prueba
  3. Verificar que la prueba falla
  4. Escribir la implementación

Mi opinión era que, me parecía absurdo escribir la prueba(paso 2) y verificar que falla(paso 3), antes que escribir la implementación (4).  El caso es que como soy muy cabezota, me he empeñado en que este orden estaba mal planteado (aunque no he llegado a presentar una queja a la wikipedia), y he hecho el paso 4 antes que el 2 y el 3.

Con esta decisión me he generado un problema. En concreto estaba probando una acción simple de un controlador. La prueba fallaba, pero la razón no era la lógica de la función que quería probar. La lógica era correcta, pero el problema es que no se podía probar porque la función tenía dependencias vinculadas al contexto de la petición Http y a la sesión. Por tanto de ahí se concluye que ese código, aunque solo cumplía un objetivo, tenía dependencias acopladas nada deseables y que era conveniente desacoplar. 

Aunque la función en si misma era trivial, solo el hecho de utilizar TDD obliga a programar de forma desacoplada, siguiendo por tanto uno de los principios fundamentales de la ingenería: "Una cosa es una cosa, y otra cosa es otra cosa".

No me detendré en detallar el problema técnicamente, el objetivo del post es dar mi opinión favorable sobre el TDD. Es un placer dejaros el link de los dos posts que me han ayudado a aplicar esta técnica, a comprender mejor el TDD, y por tanto a programar mejor:

En resumen, que el TDD es una muy buena práctica, en mi opinión más que por ejecutar las pruebas unitarias (que también), porque obliga a programar bien para que estas se puedan realizar.

La confusión que me generó este concepto es solo por el nombre, creo que el nombre que propongo deja más claro el concepto, y puede ayudar a otra gente a no generarse el mismo prejuicio que yo me cree. El nombre es , GDSYCT, acrónimo de "Guided Development So You Can Try" , que según el traductor de google es la traducción al inglés de "Desarrollo guiado para que se pueda probar".

Para finalizar remarco que el objetivo es programar mejor, no garantizar que el programa no vaya a tener errores, por supuesto. Seamos honestos, dentro de unos límites razonables, por nuestro bien, es deseable que un programa pueda fallar, para que el cliente/empleador necesite de nuestros servicios.

Hasta otra.