viernes, 30 de noviembre de 2007

Arquitectura ASP Net clásica, modelo de WebForms


Una aplicación web creada con Asp Net de la forma en la que nuestros amigos de Microsoft la han ideado, implica una arquitectura de 2 capas como la siguiente:


En el caso de la capa de aplicación, Asp.Net 2.0 no requiere que se ubique necesariamente código de la lógica de la aplicac. en el archivo code-behind, ya que también se puede agregar el mismo en el código de presentación (.aspx). De todas formas siempre es aconsejable mantener separado las lógicas de aplicación y presentación.

En el caso de la capa de acceso a datos, no es aconsejable acceder desde la capa de aplicación directamente a la BD ( ya sea a través del llamado a procedimientos almacenados ó vía ejecución de comandos SQL) , siempre es mejor crear clases que accedan a la tecnología usada en el acceso a datos; porque ?
Porque con esta decisión de diseño, tendremos las siguientes ventajas:

  • El código de acceso a datos se aísla en una clase separada, por lo cual podemos poner a trabajar a nuestros expertos en BD, mientras los analistas y programadores de lógica de aplicación trabajan en la otra capa.
  • Podemos afinar la perfomance de la BD (tiempos de acceso, pruebas de stress, etc) sin afectar el resto de la aplicación con nuestros cambios.
  • Podemos migrar de tecnología de acceso a datos, por ej.: de SqlServer a Oracle, ó a un ORM (Nhibernate ó Linq, etc); sin afectar las otras capas. (capas como módulos pluggables)

OK, me convencí, voy a generar mis clases de acceso a datos con las operaciones básicas de persistencia (CRUD: Create-Retrieve-Update-Delete), aunque tener esta flexibilidad, no posee ningún costo asociado?
SI lo posee, debido a que Asp.Net está diseñado para trabajar con los controles de las fuentes de datos embebidos en nuestras páginas .aspx, soluciones?:

  • No usar las fuentes de datos (DataSources) de Asp.Net, lo cual significa que no podremos usar “data-binding” en nuestras presentaciones, por lo cual debemos escribir el código que conecta la interfaz de usuario (IU) a las clases de acceso a datos.
  • Usar la nueva fuente de datos de objetos (ObjectDataSource) de Asp.Net 2.0, la cual está diseñada para ligar los controles Asp.Net a clases de acceso a datos, aunque esto agrega una capa de complejidad que en algunos casos tampoco soluciona el problema.
Como es una aplicación web Asp Net??
Los sitios web Asp Net son desarrollados via el uso de los Web Forms (.aspx), éstos brindan la funcionalidad web a los clientes. Un request a un recurso .aspx, como por ej.: http://miWeb.com.ar/CarritoCompras/default.aspx, resulta que sea ejecutado el archivo default.aspx (junto con su archivo code-behind) en el server, luego el resultado será una página html que se enviará al cliente.
En la siguiente imagen podemos ver una pantalla completa de ejemplo de desarrollo con la ide Visual Studio 2005, donde se aprecia una ventana con el "explorador de soluciones" (ver las extensiones .aspx de los WebForms y .aspx.cs del code behind), una ventana "toolbox" donde se ven la gran cantidad de controles Web server de AspNet que pueden agregarse al WebForm; y una página que aparece en modo de diseño, mostrando un control GridView que es usado para mostrar y editar los datos del carrito de compras.

Existen además otros archivos para el diseño de la IU como Web User controls y Master Pages, los cuales son similares a los Web Forms (están compuestos de HTML y código c# ó vb.Net en su code-behind), aunque no pueden ser accedidios de forma directa por los clientes. Estos son usados para componer el contenido de los Web Forms.
Los Web User controls (.ascx) se incluyen en los Web Forms y permiten la reutilización de código en la capa de presentación.
Los Master Pages (.master) son templates que pueden ser aplicados a gran número de Web Forms , para asegurar consistencia visual y funcionalidad a través de varias páginas del sitio. Normalmente usados para encabezado y pie de nuestro sitio, mapa del sitio, columnas con menúes.

Controles del lado del servidor, existen 2 categorías:
  • Html, permiten acceder a los elementos HTML de la página a través del código (en el code-behind). Se transforma un control Html (Button, TextBox, RadioButton,...) a un Html server agregandole el atributo “runat=server”. La mayoría de los controles Html están duplicados con mayor funcionalidad en los controles Web server, aunque a veces ud. deberá usarlos.
  • Web server, son clases .NET compiladas que, al ser ejecutadas, generan código Html como salida, eventualmente pueden incluír scripts del lado del cliente.
    Pueden ser usados en los Web Forms en forma directa ó a través de la creación de Web User controls. Estos incluyen controles simples como TextBox ó Button, y otros más complejos como el GridView (el viejo DataGrid) que permite mostrar datos de la BD en forma de tabla con manejo de muchas propiedades de diseño y eventos.
A continuación les muestro algunas pantallas que fueron obtenidas del VS 2005 para ejemplificar características importantes que hacen al desarrollo de páginas Asp Net (WebForms)
El VS me permite visualizar las páginas en 2 modos: el de diseño


que me permite visualizar como se verá la página en el Browser, en el ejemplo se ve "deshabilitado" el acceso a la cabecera y pie del sitio que son parte del master page al cual pertenece esta página.
Y el modo de "código fuente":


Aquí se puede editar el código html y los controles Web de asp net que han sido agregados en modo de diseño (encapsulados en los tags ).





Por último un ejemplo del code behind (.aspx.cs) de esta página, donde normalmente generamos nuestro código de manejo de eventos de la página y de los controles :



Con este post he intentado demostrar a aquellos que no han programado con AspNet, las principales características de la arquitectura clásica de desarrollo web, así el lector podrá comprender mejor las diferencias existentes contra la nueva propuesta del MVC para AspNet posteada anteriormente.

martes, 27 de noviembre de 2007

EL futuro MVC de Asp Net

Luego de haber leído los artículos de Scott Guthrie y Dino Esposito voy a realizar un resúmen de la propuesta MVC para ASP NET.

Para crear una aplicación de este tipo con VS, elegimos un nuevo proyecto de tipo “ASP.NET MVC Web Application”, de esta forma se creará una nueva solución y se añadirán dos proyectos: un proyecto web en el que implementaremos nuestra aplicación y un proyecto de testing que usaremos para escribir test unitarios (TDD...)
La estructura por defecto de un ASP.NET MVC tiene 3 directorios:

  • /Controllers
  • /Models
  • /Views
Por lo cual, crear las clases controladoras en el directorio /Controllers, las de modelo de datos en /Models, y las vistas en el directorio /Views.
Cabe aclarar que el Framework no te obliga a usar esta estructura, pero el template usa este patrón. Consultando a Scott sobre el uso de ensamblados (dll) para la controladora y el modelo (mis capas de negocio y acceso a datos), dijo no existir problemas en agregar las referencias a los mismos y usarlos en el MVC en vez de las carpetas creadas por default; si no fuera así no podríamos usar nuestras controladoras y modelos de un proyecto a otro, debiendo reescribir código en cada solución.


Por defecto los proyectos MVC tienen unas reglas de enrutado de urls preconfiguradas, de esta forma podemos empezar a escribir el código usando un conjunto de convenciones para nombrar las urls que van a usarse en nuestra aplicación.

Las Controladoras...
El convenio por defecto es mapear el path de la url de una petición HTTP (por ejemplo: /Products/) a una clase cuyo nombre siga el patrón UrlPathController (por ejemplo: una url que termine con /Products/ se mapeará a la clase ProductsController).
Por lo tanto si agregamos la clase “ProductsController” (que herede de System.Web.MVC.Controller) a nuestro proyecto, el framework ASP.NET MVC la usará para procesar todas las peticiones cuya url contenga la cadena “/Products”. Es decir, será llamada para procesar las urls “/Products/Categories”, “/Products/List/Beverages”, “/Products/Detail/3″ (donde 3 será el id. del producto), etc.



El framework MVC nos permite definir “métodos de acción” en nuestro controladora, y la clase base Controller invocará el método apropiado, así que cuando recibimos una petición de la forma "/Products/Categories”, la regla de enrutado tratará la parte “Categories” como el nombre de la acción, y se invocará el método Categories() para procesar la petición, si recibimos una petición a la url "/Products/Detail/5", la regla tomará el nombre “Detail” como el nombre de la acción y se invocará al método Detail(), etc.

Como accedemos a los parámetros de las urls?
La clase base Controller expone un conjunto de objetos Request y Response que podemos usar. Estos objetos tienen la misma estructura que los objetos HttpRequest/HttpResponse a los que estamos acostumbrados en ASP.NET, la diferencia es que estos objetos están basados en interfaces en lugar de en clases selladas (sealed) (MVC trae las interfaces System.Web.IHttpRequest y System.Web.IHttpResponse), esto nos da la posibilidad de poder implementarlos como queramos, uno de sus usos será crear test unitarios para clases controlador.

En la acción List , aparece un parámetro de la categoría, que es parte de la URL, y un índice de página opcional (implementaremos paginado en el servidor y usaremos ese valor para indicar qué página de categoría mostrar en la petición).
Los parámetros opcionales se manejan usando tipos de datos nullables en los métodos de acción de las controladoras. El parámetro “int?” de nuestra acción List es nullable.



Construyendo las clases del Modelo
Para crear nuestras clases que accedan a la información de la BD, Scott lo realiza mediante "Linq to Sql" (ORM), el cual me permite obtener como resultados listas de objetos. También podría usar NHibernate o cualquier otro tipo de ORM, ó Ado.Net (no recomendado, ya que debo mapear registros a listas de objetos) para construir mis clases del Modelo.



Volviendo a nuestra controladora, vemos el uso que se hace del modelo creando un objeto de tipo "NorthwindDataContext" (clase creada con la utilidad de Linq), y llamando a sus métodos, como por ej.: en el método "Detail(int id)" donde llamamos a "northwind.GetProductById(id)".


Y la Vista??
Cuando implementamos los tres métodos de acción del controlador en la clase ProductsController, usamos los parámetros de la URL para obtener los objetos adecuados de nuestra BD, para luego seleccionar una vista adecuada para generar una resputesta HTML. Usaremos uno de los métodos RenderView() de la clase base Controller para espcificar la vista que queramos usar, así como explicitamente le pasaremos los datos específicos que queremos que la vista use para renderizar la respuesta. Por ej: RenderView("Detail", product), donde product es el objeto de tipo Product obtenido del llamado al Modelo.
Para crear la vista a la cual hacemos referencia en el ej. ("Detail"), podemos usar cualquier motor de templates para ayudarnos a generar la interfaz de usuario (incluyendo motores como NVelocity, Brail - y cualquiera que escribamos ). Por defecto ASP.NET MVC usa las páginas ASP.NET (.aspx), Master Pages (.master) y UserControls (.ascx).


Conclusiones
Este framework no reemplaza el modelo basado en WebForms de Asp.Net, sólo nos agrega la posibilidad de crear nuestras aplicaciones bajo este paradigma, aplicando a la perfección este viejo patrón de arquitectura (MVC).


En el post de Dino, se le pregunta a los lectores si han escuchado hablar de REST (Representational State Transfer) , el cual es otro patrón de arquitectura que encaja perfectamente en el proceso del MVC AspNet, que describimos anteriormente.
REST define cómo los recursos de la red deberían ser definidos y direccionados con el objetivo de: obtener menores tiempos de respuesta y separar las responsab. entre front-end y back-end. Se basa en los sig. principios:

  • Una aplicación expresa su estado e implementa su funcionalidad actuando sobre recursos lógicos.
  • Cada recurso es direccionado usando una URL específica.
  • Todas las ventajas que poseen esos recursos direccionables se agrupan en un juego de operaciones.

Por lo tanto el framework MVC de AspNet usa un modelo REST que compite con el modelo clásico de "postback" de AspNet.



Cada página se separa en 2 componentes (controladora y vista) que operan sobre el mismo modelo de datos; esto es opuesto al clásico modelo "code-behind" donde no existen barreras que nos fuercen a separar las responsab. entre controladoras y vistas.


Aunque manteniendo las clases "code-behind" (nuestras aspx.cs) lo más ligeras que sea posible y diseñando la capa de negocios de forma apropiada (ver ejemplo de capa de negocio), un buen desarrollador logra separar estas responsabilidades manteniendo la lógica de la aplicación en la capa que corresponda.

Bueno, en este post se ha intentado aclarar un poco de que trata un framework MVC, tomándolo como una opción más a la hora de desarrollar software para Web. Cualquier extensión al tema leer los posts de Scott y Dino que están referenciados al principio.

viernes, 23 de noviembre de 2007

Introducción a los frameworks MVC

Ya hemos visto una arquitectura de 3 capas lógicas, ahora investiguemos como desarrollar un MVC (model-view-controller) , que fue explicado muy someramente en este post.












Sin lugar a dudas estos frameworks han ganado terreno en el desarrollo de sitios Web, donde RubyOnRails ha sido la inspiración de otros desarrolladores de frameworks de este tipo. En el caso del mundo .NET, la creación de MonoRail sumó muchos adeptos en la comunidad de desarrolladores y todos comenzamos a mirar de reojo para cuando Microsoft sumaría una propuesta de desarrollo que rompiera con el modelo basado en WebForms (.aspx), ó al menos agregara la posibilidad del MVC.

El modelo actual de MS impone que los request de los clientes son solicitudes a páginas (WebForms) aspx que contienen controles Web ASP.Net, los cuales disparan eventos a una controladora de esa página. Esta controladora es normalmente código C# ó VB.Net agregado al WebForm, y conocido como "code behind" (aspx.cs ó aspx.vb). En este tipo de arquitectura el cliente hace Request a objetos de la capa de presentación (WebForms aspx), que luego llaman a su objeto controlador para pedirle funciones, estas luego harán solicitudes sobre el Modelo (mi acceso a datos en el 3 capas lógicas).

En el caso de un MVC, el Request se realiza a un objeto de tipo Controlador que crea una presentación como Response a esa solicitud. Si se fijan en el diagrama MVC dice que la "Controladora selecciona la Vista que irá como respuesta".

Pues bien, Microsoft responde a la comunidad de desarrolladores .NET con la siguiente sorpresa (quizás no tanto...) el dia 13/11/2007 : The Asp.Net MVC framework. Ver el extenso post que publicó el gran Scott Guthrie (jefe de proyectos de MS: IIS, ASP.NET, Atlas, CLR, Compact Framework, Windows Forms, etc, etc.).
Allí se aclara que será agregado al VS 2008 como una ventaja opcional, a través de un template para la creación de proyectos de tipo MVC, también que este modelo fuerza a una limpia separación de responsabilidades de la aplicación, que permite realizar testeos de los componentes soportando TDD (desarrollo manejado por el testing), y que provee mayor control sobre las URLs que se publican en su aplicación, y mayor control sobre el código HTML que se emite desde ellas.

Esta es una vista de como las URLs se mapean a clases Controladoras:

En el post de Scott, se aclara que en la mayoría de los frameworks Web (ASP Net WebForms,PHP,JSP,...) las URLs se mapean con archivos template almacenados en el disco del servidor web, por ej: un url "/Productos.aspx" tiene un archivo subyacente Productos.aspx en disco que maneja el procesamiento de la misma.

En cambio, en los frameworks MVC las URLs se mapean directamente a clases, estas son denominadas "Controladoras" y son las que procesan los Request entrantes, manejando las entradas del usuario, sus interacciones y ejecutando la lógica apropiada para el proceso. Una clase controladora llama a una vista, la cual genera la salida HTML que se enviará como Response.
En prox. posts entraré en más detalles sobre este ASP.Net MVC y en el modelo de WebForms.

martes, 20 de noviembre de 2007

Arquitectura del software?


Muchas veces nos hablan de la arquitectura en el desarrollo de sistemas. Palabrita de moda quizás...; ingenieros, analistas y programadores que se hacen llamar "Arquitectos de software" como si de un título se tratase. Hasta yo la he puesto como título en mi Blog, entonces, cual es el significado de la Arquitectura en el desarrollo de un sistema?, tratemos de averiguarlo.

En setiembre de este año se realizaron las 36 jornadas de la Jaiio en mi ciudad (Mar del Plata), y al ver el temario de los seminarios, me informo de un curso especial de 8 hs. seguidas, llamado "Introducción a la arquitectura del software", dictado por el Gerente de relac. académicas de Microsoft y profesor de la UBA Pablo Michelis. Por supuesto para entender mejor este concepto y para agregar valor a mis clases me inscribí; esto intenta ser un breve resúmen del mismo.

Comencemos por definir "Arquitectura del soft":
"Estructura de sistemas o sistema de estructuras que consisten en elementos, sus propiedades externamente visibles y la relación entre ellos"
"Propiedades externamente visibles: qué es lo que debe saber/suponer un componente sobre otro?"
Por último :
"
Toda la arquitectura es diseño, pero no todo el diseño es arquitectura. La arquitectura representa las decisiones de diseño significativas que le dan forma a un sistema, donde lo significativo puede ser medido por el costo del cambio". (Grady Booch)

Creo que es la más simple y directa definición de arquitectura.

Basándonos en esta última definición podemos suponer que lo que distingue a la arquitectura de otro tipo de diseño es la significancia expresada en la dificultad ó costo del cambio.
La arquitectura del soft mantiene unidas las nociones de : diseño, estructura, estilo, racionalidad, proceso y costo.
Ahora bien, como podemos evaluar la calidad de una determinada arquitectura para nuestra solución de software? , quizás una buena arquitectura sea aquella en la que las decisiones de diseño significativas se lograron minimizar, evitando riesgos de cambio futuros. De esta forma estaríamos libres de cambiar varios aspectos del sistema sin el miedo a que tales cambios produzcan cascada de errores y cambios en el diseño que nos llevarían a altos costos de mantenimiento. Una buena arquitectura debe ser sustentable.

Como se relaciona esta visión de la arquitectura con la estructura del sistema?, pues construyamos componentes, clases, paquetes, ensamblados, etc. que sean altamente cohesivos y con bajo acoplamiento (nuestro ying y yang recuerdan?).
En una arquitectura con bajo acoplamiento, donde los puntos de variación futuras estén bien encapsulados, los efectos del cambio estarán bien aislados y el costo será relativamente bajo.
Por esto es que a nivel de arquitectura hablamos de los patrones de diseño, que nos permiten el desarrollo de mejores arquitecturas de software como por ejemplo la 3 capas explicada y ejemplificada en previos posts.

lunes, 19 de noviembre de 2007

Desarrollar en 3 capas con .NET (parte 2) - La controladora y la presentación

Antes de mostrar el manejo de la capa de negocio, les aclaro el concepto de Viatico:
"es una retribución diaria que cobra un empleado cuando la empresa lo envía a realizar alguna tarea fuera de su ámbito normal de trabajo (normalmente a otra ciudad), este importe diario depende de la categoría del mismo. A esto se le suman todos los gastos extras que surjan por movilidad, inscripción a cursos, etc. Normalmente se genera una Solicitud que , en caso de ser aprobada por un superior genera el Viático correspondiente." (los sustantivos marcados en negrita corresponden a algunos de los objetos de negocio de nuestro sistema).

Aclarado este punto importante para poder entender mínimamente el objetivo del sistema, a continuación veremos como desarrollar nuestra capa de negocio.

La capa de negocio (ó dominio del problema) de nuestro sistema, estará compuesta de todos los procesos que fueron analizados como casos de uso, por lo que es común denominar a estas clases : controladora del caso de uso XX.

Capa de negocio (componente ViaticoProcesos)

En mi caso de ejemplo tengo una clase CSolicitud que posee la responsabilidad de controlar todos los procesos inherentes al manejo de Solicitudes de viáticos.
Si quisiéramos darle más flexibilidad (y en consecuencia mayor reutilización futura) al sistema, deberíamos desarrollar una interfaz que agrupe los métodos comunes a todos los posibles sistemas de Viáticos (IViaticoSolicitud) .
Logrando cierta abstracción defino los contratos de mi interfaz:

public interface IViaticoSolicitud
{
void CrearSolicitud(Solicitud nueva);
Viatico AutorizarSolicitud(Solicitud s);
void ImprimirSolicitud(Solicitud s);
List BuscarSolicitud(Solicitante s);
List
BuscarSolicitud(Solicitante s, DateTime Desde);
List BuscarSolicitud(Solicitante s, DateTime Desde, Boolean Aprobadas);
Solicitud BuscarSolicitud(int id);
}

Asi que entonces mi clase CSolicitud implementará mi IViaticoSolicitud:


public class CSolicitud:IViaticoSolicitud
{
// Declaro los DAOs con los que va a trabajar mi controladora

ISolicitudDao solicitudDao;

IViaticoDao viaticoDao;

IEmpleadoDao empleadoDao;
IMovilidadDao movilidadDao;


public CSolicitud()

{ // Creo la fabrica y los DAOs que usaré
NHibDAOFabrica fabricaDAO = new NHibDAOFabrica();

this.solicitudDao = fabricaDAO.GetSolicitudDao();

this.viaticoDao = fabricaDAO.GetViaticoDao();

this.empleadoDao=fabricaDAO.GetEmpleadoDao();

this.movilidadDao = fabricaDAO.GetMovilidadDao();

}


#region IViaticoSolicitud Members


public void CrearSolicitud(Solicitud nueva)

{
if (nueva.Solicitante != null)
{ try { this.solicitudDao.Save(nueva); }
catch { thro
w; }
}
}

public Viatico AutorizarSolicitud(Solicitud s)

{
try
{ // Marco como aprobada la Solicitud
s.Aprobada = true;
// Creo Viatico basado en la Solicitud aprobada
Viatico v = new Viatico();
v.Estado = Viatico.estado_viatico.Creado;
v.Solicitud = s;

v.Numero = this.viaticoDao.DarUltimoNro()+1; // Verificar concurrencia...
// Persisto cambios en Solicitud y Grabo nuevo viatico
this.solicitudDao.SaveOrUpdate(s);

this.viaticoDao.Save(v);

return v;
}
catch { throw ; }
}

public void ImprimirSolicitud(Solicitud s)
{
throw new Exception("The method or operation is not implemented."); }

public List BuscarSolicitud(Solicitante s)
{
try

{
List lista = this.solicitudDao.DarSolicitudesXSolicitante(s,null,null);

return lista;
}
catch { throw ; }

}


public List BuscarSolicitud(Solicitante s, DateTime Desde)
{
try
{
List lista = this.solicitudDao.DarSolicitudesXSolicitante(s, Desde, null);
return lista;
}
catch { throw ; }

}


// etc, etc ..............


#endregion

}

Como verán muchos de los métodos solicitan objetos a la capa de acceso a datos (clases DAO), por lo que termina siendo un llama
do a un método similar en el DAO. Aquí es donde mis alumnos dicen " porqué debemos hacer las cosas por duplicado?, y si llamamos desde la capa de presentación al método del DAO directamente ? ".
OK, el tema es que la Controladora posee métodos como
AutorizarSolicitud(Solicitud s), donde debemos desarrollar código que sólo es inherente al proceso de negocio y además trabajar en una transacción con varios objetos DAO.
En este ejemplo se cambia un atributo del objeto Solicitud, se crea un objeto Viatico, se pide un nro. de viático a un método estático de Viatico, y se persisten ambos objetos, vía llamado a los métodos de sus DAOs.

Capa de presentación Web (componente ViaticoWeb)

Por último, veamos un ejemplo de mi Capa de presentación Web, que permite la autorización de determinada solicitud de viático.
La página web muestra una lista de las solicitudes a autorizar por este usuario (jefe).
Selecciona una, y pulsa el botón "Autorizar".



Al pulsar este botón lo captura el evento "click" del mismo y este es el código:

protected void ButtonAutorizar_Click(object sender, EventArgs e)
{
Solicitud elegida=(Solicitud)Session["SolicitudBuscada"];
if (elegida!= null)
{
// creo controladora de Proceso de Solicitudes
CSolicitud cSolicitud = new CSolicitud();
try
{
Viatico v=cSolicitud.AutorizarSolicitud(elegida);
this.CargarGrid((Usuario)Session["Usuario"]);
this.LabelError.Text = "Viatico"+v.Numero.ToString()+" CREADO";
}
catch
{
Exception ex = new Exception();
this.LabelError.Text = ex.Message;
}
Response.Redirect("~/Admin/Autorizar.aspx");
}
else
this.LabelError.Text = "Seleccione una Solicitud para Autorizar...";
}

Como ven , se crea un objeto de tipo CSolicitud y se llama a su método AutorizarSolicitud pasándole como parámetro la solicitud seleccionada por el usuario. Cualquier error en el proceso llamado será capturado (catch), mostrándose el mensaje de error pertinente.

Capa de Objetos de negocio (componente ViaticoBO)

Mis objetos de negocio son clases independientes de la tecnología que se use para persistencia.
Ejemplo: mi BO Solicitud.

public class Solicitud
{
public Solicitud()
{ }

int id;

public int Id
{
get { return id; }
set { id = value; }
}
Solicitante solicitante;

public Solicitante Solicitante
{
get { return solicitante; }
set { solicitante = value; }
}
System.DateTime fecha_soli;

public System.DateTime Fecha_soli
{
get { return fecha_soli; }
set { fecha_soli = value; }
}
string motivo;

public string Motivo
{
get { return motivo; }
set { motivo = value; }
}

int numero;

public int Numero
{
get { return numero; }
set { numero = value; }
}
string origen;

public string Origen
{
get { return origen; }
set { origen = value; }
}
string destino;

public string Destino
{
get { return destino; }
set { destino = value; }
}
System.DateTime desde;

public System.DateTime Desde
{
get { return desde; }
set { desde = value; }
}
System.DateTime hasta;

public System.DateTime Hasta
{
get { return hasta; }
set { hasta = value; }
}
Movilidad ida;

public Movilidad Ida
{
get { return ida; }
set { ida = value; }
}
Movilidad vuelta;

public Movilidad Vuelta
{
get { return vuelta; }
set { vuelta = value; }
}

Boolean aprobada;

public Boolean Aprobada
{
get { return aprobada; }
set { aprobada = value; }
}

}

En este componente también poseo los archivos de mapeo XML que necesita NHibernate (1 por clase BO), ya que recomiendan que estén en la misma .dll que las clases que mapean.

Bueno, hasta aquí, esta breve explicación de mi desarrollo con la arquitectura 3 capas usando .NET y NHibernate; no quise profundizar en el uso de ninguna herramienta, sólo mostrar ejemplos del desarrollo a nivel de arquitectura y componentes de soft.
Quedo a las órdenes de cualquiera que desee aportar comentarios sobre mejoras, experiencias, ó preguntas sobre la forma de trabajo; que quizás no hayan quedado del todo claras en este post.


jueves, 15 de noviembre de 2007

Desarrollar en 3 capas con .NET y NHibernate - Parte 1 (Acceso a datos)

Luego de haber posteado que es el diseño en 3 capas, y que es un ORM con ejemplos de NHibernate, estamos en condiciones de comprender el desarrollo de software mediante esta arquitectura con el framework .NET.
Echemos un vistazo a este diagrama de componentes que aplica esta arquitectura de 3 capas (para el desarrollo de un sistema de viáticos):


















Podemos ver que además de las capas de presentación, procesos del negocio y acceso a datos, tenemos los objetos de negocio aparte como si de otra capa se tratase. Aunque en la realidad debería estar en la capa del medio, esto presenta problemas en la capa de acceso a datos que pasaría a desconocer los objetos con los que debe trabajar NHibernate en nuestras clases DAO. Para comprender claramente de que estoy hablando debemos ver las clases que se encuentran en cada componente de software.

Empezando por el acceso a datos:




















NHibernateCore

Aqui estan : una interfaz para los DAO (data access object) genérica (IDAO), una clase abstracta que implementa IDAO (NHibDAOAbstracto), y manejo de sesiones y transacciones de NHibernate. Su contenido responde al excelente trabajo de Billy McCafferty: NHibernate best practices with ASP.Net, cuya lectura recomiendo, antes de comenzar a desarrollar una capa de acceso a datos.

Por ej. IDAO:

public interface IDAO // maneja Generics de Net 2.0
{
T GetById(IdT id, bool shouldLock);
List GetAll();
List GetByExample(T exampleInstance, params string[] propertiesToExclude);
T GetUniqueByExample(T exampleInstance, params string[] propertiesToExclude);
List Find(string consulta);
IList FindRetLista(string consulta);
T Save(T entity);
T SaveOrUpdate(T entity);
void Delete(T entity);
void CommitChanges();
}

  • ViaticoDAO
  • Aquí se encuentran : la fábrica de DAOs, y los DAO de cada objeto de negocio.
    Por ej. la clase SolicitudDAO :
    public class SolicitudDAO : NHibDAOAbstracto, ISolicitudDao
    // Hereda del DAO abstracto definido en NHibernateCore e implementa ISolicitudDao
    // para no hacer uso directo del DAO abstracto
    {

    public List DarSolicitudesXSolicitante(Solicitante s, Nullable Desde, Nullable Aprobadas)
    {
    string criterios = "FROM Solicitud a WHERE a.Solicitante.ID = " + s.ID.ToString();

    if (Desde != null)
    criterios += " and Fecha_soli >=" + ((DateTime)Desde.Value).ToShortDateString();
    if (Aprobadas != null)
    {
    if (Aprobadas == true)
    criterios += " and Aprobada=1";
    else
    criterios += " and Aprobada=0";
    }

    IDaoFabrica daoFabrica = new DAOFabrica();
    ISolicitudDao soliDao = daoFabrica.GetSolicitudDao();

    List solicitudes;
    solicitudes = soliDao.Find(criterios);
    return solicitudes;
    }

    public Solicitud DarSolicitudXid(int id)
    {
    IDaoFabrica daoFabrica = new DAOFabrica();
    ISolicitudDao soliDao = daoFabrica.GetSolicitudDao();

    Solicitud s = soliDao.GetById(id, false);
    return s;
    }
    }


    ISolicitudDao:

    public interface ISolicitudDao : IDAO
    {
    List DarSolicitudesXSolicitante(Solicitante s, Nullable Desde, Nullable Aprobadas);

    Solicitud DarSolicitudXid(int id);
    }

    Por último un ejemplo de DAOFabrica:

    public class DAOFabrica : IDaoFabrica
    {
    public IEmpleadoDao GetEmpleadoDao()
    {
    return new EmpleadoDAO();
    }


    public ICategoriaDao GetCategoriaDao()
    {
    return new CategoriaDAO();
    }


    public ISolicitudDao GetSolicitudDao()
    {
    return new SolicitudDAO();
    }

    ...
    }

    Lo destacable en esta capa de acceso a datos es su independencia del motor de NHibernate, gracias al uso de la Fábrica de DAOs. Por ej. si quisiera reemplazar el NHibernate por Linq for Sql (del Net 3.0), cambiaría en mis DAOs la herencia de la clase abstracta que implementa los métodos contra el motor de acceso a datos:
    public class SolicitudDAO : NHibDAOAbstracto, ISolicitudDao por
    public class SolicitudDAO : LinqDAOAbstracto, ISolicitudDao

    Por supuesto deberé desarrollar mi clase LinqDAOAbstracto para que implemente los métodos de la interfaz IDAO.

    En parte 2 veremos la capa de negocio (procesos y reglas; ó controladoras de los casos de uso) y ejemplos de los objetos de negocio, cuyas clases están implementadas en su propio componente.


    miércoles, 31 de octubre de 2007

    Que es un ORM (object-relational mapping)

    El ORM es un componente de software que me permite trabajar con los datos persistidos como si ellos fueran parte de una base de datos orientada a objetos (en este caso virtual). Debido a que lo standard es trabajar con BD relacionales, se deben realizar operaciones que permitan transformar un registro en objeto y viceversa. A esta funcionalidad se la llama Mapeo objeto-relacional (ORM).
    Uno de los componentes ORM más utilizado (sino el más...) es el Hibernate, surgido del ambiente Java y llevado al uso del framework .NET con la versión NHibernate
    Para poder explicar el porqué de la existencia de esta tecnología, nada mejor que un ppt que preparé para una clase sobre este tema a los alumnos del último año de TSSI, que les dejo disponible a continuación.



    *(Si les aparece el mensaje que "ha sido removido o es privado" pulsen en "VER"
    al lado del logo de "slideshare", gracias)

    sábado, 22 de septiembre de 2007

    Sigamos solucionando nuestro diseño con los patrones

    Siguiendo con nuestra charla de diseño, determinemos la granularidad de los objetos intervinientes .
    Los objetos varían enormemente en tamaño y número, y representan cualquier cosa desde hard a sistemas completos, por lo que como decidir que debería ser un objeto?
    Veamos algunos patrones:
    • Fachada (GoF) describe como representar subsistemas ó procesos completos como objetos.
    • FlyWeight(GoF) describe como permitir un gran número de granularidad muy fina.
    • Abstract Factory (GoF) produce objetos cuya única resp. es crear otros objetos.
    • Visitor y Command (GoF) generan objetos cuya resp. es implementar una petición en otros objs. ó grupo de objs.

    Especificar las interfaces de los objs.

    Los patrones nos ayudan a definir interfaces identificando sus elementos clave y los tipos de datos que se envían a la interfaz. También especifican relaciones entre interfaces, ya que: requieren que algunas clases tengan interfaces parecidas ó les imponen restricciones; por ej:

    Decorador y Proxy (GoF) requieren que las interfaces de sus objs. sean idénticos a los objs. deocrado y representado, respectivamente.

    Especificar las implementaciones

    Herencia de clases vs. herencia de interfaces, muchos de los patrones de diseño dependen de esta distinción. Por ej:

    • Los objs. de una cadena en Chain of Responsability (GoF) deben tener un tipo en común, pero normalmente no comparten la misma implementación.
    • En Composite (GoF), el componente define una interfaz común mientras que el compuesto suele definir una implementación en común.
    • Command, Observer, State y Strategy (GoF) suelen implementarse con clases abstractas que son interfaces puras.

    En este tema, debemos tener en mente uno de los principios fundamentales del diseño OO: programar para interfaces, no para una implementación. Por que?

    • Ventajas de manipular objs. solamente en términos de la interfaz definida por las clases abstractas. Los clientes no tienen que conocer los tipos específicos de los objs. que usan, basta con que estos adhieran a la interfaz que esperan que esperan los clientes.
    • Reducción del acoplamiento entre subsistemas.
    • No se deben declarar variables como instancias de clases concretas, se ajustan simplemente a la interfaz definida por una clase concreta.
    • Para crear instancias de clases concretas usamos los patrones de creación; estos ofrecen distintos modos de asociar una interfaz con su implementación de manera transparente, y aseguran que el sistema se codifique en términos de interfaces, no de implementación.

    Por último, pongamos a funcionar los mecanismos de reutilización:

    Herencia vs. Composición

    Son las 2 técnicas más comunes para reutilizar funcionalidad en sistemas OO.

    La composición requiere que los objs. tengan en cta. las interfaces de otros, lo cual requiere interfaces cuidadosamente diseñadas, que no impidan que un obj. sea utilizado por otros. Optar por la composición ayuda a mantener cada clase encapsulada y centrada en una sola tarea. En los patrones de diseño veremos esta técnica aplicada una y otra vez...otro principio fundamental: favorecer la composición de objetos frente a la herencia de clases.

    Pero qué es la composición?: método por el cual una nueva funcionalidad se obtiene mediante la creación de un objeto compuesto por otros objetos, ésta se logra delegando funcionalidad a uno de los objs. de la composición.

    Mientras que la Herencia es un método por el cual la nueva funcionalidad se obtiene mediante la extensión de la implementación de un objeto existente. La superclase (generalización) captura los métodos y atributos comunes, y las subclases (especializadas) extienden la implementación con métodos y atrib. adicionales. Es más sencilla de llevar a cabo que la composición, pero...

    Desventajas de la herencia:

    • Rompe la encapsulación, ya que expone la subclase a los detalles de implementación de su superclase
    • Reutilización de caja blanca, porque los detalles internos de la superclase son visibles a las subclases
    • Las subclases han de cambiar si la implementación de la superclase cambia

    Entonces que usamos?, según Coad, solo utilizar herencia cuando:

    • una subclase expresa "es un tipo de" y no "es un rol desempeñado por".
    • una instancia de una subclase nunca necesita convertirse en un obj. de otra clase
    • una subclase extiende las resp. de su superclase, no las redefine ni las anula.
    • para una clase del problema del dominio actual, la subclase especializa un rol ó una transacción.

    Por último utilicemos la Delegación cuando no existan relaciones estáticas entre clases, cuando la herencia no tenga sentido, por ej. para gestionar Roles.

    Bien, como vemos obtener un buen diseño es difícil; lo primero que deberíamos saber es : que es un buen diseño?, los conceptos que detallamos antes nos ayudan a dilucidar esta pregunta. Lo segundo será aplicar los principios de diseño de forma sistemática, una buena solución es copiar a los que saben: aplicar los patrones, donde puedan aplicarse.

    sábado, 8 de septiembre de 2007

    Siguiendo con nuestra charla sobre como los patrones pueden socorrernos en nuestros difíciles momentos de diseño, veamos como "encontrar los objs. apropiados para asignarles responsabilidades".
    Coincidamos en que lo más complicado del DOO es descomponer un sistema en objetos.
    Para lograr este objetivo, resumamos las tareas del análisis:
    • Partimos de encontrar los conceptos de nuestro dominio de problema y así efectuar un modelo conceptual donde identificamos las clases que surgen del negocio (nuestros objs. de negocio) y sus asociaciones.
    • Luego deberíamos obtener diag. de secuencia del sistema (basados en nuestros CU) donde determinemos los eventos y operaciones del sistema
    • En este punto sería importante obtener los "contratos" de los CU, donde se responderá: que hacen las operaciones del sistema?. Mediante la descripción de las postcondiciones de los contratos podemos describir cómo cambia el sistema tras cada operación; esta descripción se realiza en términos de : creación y destrucc. de objetos, asociac. formadas y canceladas y modificac. de atributos.
    Con toda esta documentación podremos comenzar nuestra tarea creativa más importante en el desarrollo de un sistema: el DISEÑO.
    Ahora asignemos responsabilidad a nuestros objetos, aunque aclaremos que existen 2 categorías de responsabilidades: de Conocer y de Hacer.

    Conocer

    • los datos privados encapsulados
    • los objetos relacionados
    • las cosas que puedan derivarse ó calcular

    Hacer

    • algo el mismo: crear un obj. ó hacer un cálculo
    • iniciar una acción en otros objs.
    • controlar y coordinar actividades en otros objs.

    Para asignar responsabilidad a nuestros objs. , hablemos de 3 patrones Grasp: Experto en información, Creador y Controlador. (es.wikipedia.org/wiki/Grasp)

    experto en informac.: asignar la resp. a la clase que tiene la informac. necesaria para realizarla. Esto debe hacerse sin generar nuevos acoplamientos, manteniendo la cohesión alta.

    creador: asignar a la clase B la resp. de crear un obj. de la clase A si se cumple que:

    • B agrega objs. de A
    • B contiene objs. de A
    • B registra objs. de A
    • B usa objs. de A cercanamente (directa)
    • B tiene los datos de inicialización que se pasan a un obj. A cuando es creado

    Debemos agregar que muy a menudo la creación de un obj. es de alta complejidad, por lo que sería aconsejable delegar la creación a clases auxiliares llamadas "Fábricas" (factorys)

    controlador: asignar la resp. de recibir ó gestionar un mensaje de evento del sistema a una clase que:

    • represente el sistema global ó subsistema (Fachada)
    • represente un escenario de CU en el que tiene lugar el evento (controladora de CU ó sesión)

    Tener en cuenta que un controlador debería delegar en otros objs. el trabajo que se necesita hacer, sólo coordina y controla la actividad (compuesta de varias tareas).

    Seguimos en el próximo....



    viernes, 7 de septiembre de 2007

    Principios de diseño - Como llegamos a los Design Patterns??



    En una charla con mis alumnos de último año, intenté describir el proceso de pensamiento que nos lleva a la aplicación de los patrones de diseño.


    Para empezar debemos recordar los conceptos básicos del diseño (no exclusivos del DOO), nuestro ying y yang : Acoplamiento y Cohesión, el 1ro. que determina el nivel de dependencia y el 2do. el nivel de unión interno (realizar una única función)

    OK, teniendo en mente aquello, intentemos comprender los términos: Responsabilidad e independencia, con un diagrama UML de paquetes.

    Por ej.:
    Un paquete X del cual dependen muchos paquetes debe ser muy estable. No debe cambiar porque es Responsable de los 3 paquetes que dependen de él.
    • X es Independiente, no depende de nadie.
    • Su Estabilidad = Responsabilidad + Independencia


    Existe alguna medida sencilla para saber que tan estable es un paquete?

    Factor de Inestabilidad (I) => I=(Ce / (Ca + Ce)). Si I[0,1]=0 será totalmernte estable.

    Donde : Ca (cuan responsable soy?) son clases fuera del paquete que dependen del él. Ce (cuan dependiente soy) son clases del paquete que dependen de clases externas a él.

    "La estabilidad de un paquete debe ser proporcional a su nivel de Abstracción" (R.Martin-1996); esto implica que los paquetes con máxima estabilidad deben ser abstractos; y los inestables concretos.

    Esto nos lleva a entender que aquellas decisiones de diseño y arquitectura de alto nivel de abstracción no suelen cambiar, así que los situaremos en paquetes estables. Aquí surge una pregunta interesante: como puede un paquete totalmente estable (I=0) ser lo suficientemente flexible como para soportar los cambios?. O sea, mejorarlo sin cambiarlo.
    Respuesta, otro principio : Abierto-Cerrado. Clases que puedan ser extendidas sin modificar lo ya existente: clases abstractas.

    Ahora bien, cuando intentamos seguir estos principios básicos del diseño, descubrimos que las estructuras que desarrollamos para cumplirlos, se repiten una y otra vez; esto es lo que conocemos como "Patrón de diseño". Estos deben ser soluciones probadas a los problemas de diseño más comunes, resolviéndonos los sig. puntos:

    1. Encontrar los obj. apropiados para asignarles responsabilidad.
    2. Determinar la granularidad (su nivel de abstracción) de los objetos.
    3. Especificar sus interfaces.
    4. Especificar las implementaciones que deben tener los objs. involucrados.
    5. Poner a funcionar los mecanismos de reutilización

    Ahora debemos diferenciar 2 viejas categorías de patrones de diseño: GRASP y GoF

    Los GRASP no implementan las soluciones, más bien nos llevan a pensar en el diseño, a nivel de principios generales (más principios de DOO...); mientras que los GoF nos dan una solución implementable con su propio diagrama de clases que nos muestra la forma en que debemos usarlos.

    En próximas notas iremos viendo los patrones relacionados con cada uno de los 5 puntos que nos resuelven los patrones (patterns).



    lunes, 28 de mayo de 2007

    Diseño en 3 capas? fisicas ó lógicas? es igual a patrón MVC?

    Diseñar en 3 capas...trata sobre no poner todo tu código en las interfaces de usuario de tu sistema (IU). Para subsanar esto, la idea es tener 3 niveles de funcionalidad bien definidos :



    • Capa de presentación, con nuestras IU (formularios windows, páginas HTML,..) y sus controles visuales (textBox, comboBox, dataGrids) junto con sus eventos (los click y etc.)

    • Capa de negocio (lógica del dominio), aqui ira todo el código que define las reglas de negocio (cálculos, validaciones). Surge de los procesos que hemos encontrado en el análisis.

    • Capa de acceso a datos, el código que permite acceder a las fuentes de datos. Esencialmente trata sobre 4 operaciones básicas, llamadas CRUD (por Create-Retrieve-Update y Delete), que se realizan sobre cualquier fuente de datos (normalmente alguna base de datos relacional).

    Debajo de esta última se encontrará la FUENTE de DATOS que permite la persistencia de los mismos en algún medio físico.

    Este diseño corresponde a las 3 capas lógicas (3 layers). No confundir con las capas físicas ó parte (3 tiers) que corresponden al lugar donde se instalan los componentes de software.

    En 3 tiers la ejecución está distribuida:



    • Front-End, donde se ejecutan las IU del cliente. Los Browsers.

    • MiddleWare, recibe solicitudes de las IU a través de la red. Estos son mensajes (XML, SOAP,...) que se envían mediante protocolos de transporte (HTTP,TCP,UDP,..). El Servidor Web.

    • BackEnd, nuestra base de datos ó algún proceso externo a nuestro software.

    Por último "Modelo-Vista-Controlador" es un patrón de diseño de arquitectura que está asociado a la idea de 3 capas (3 layers), aunque su objetivo es aún más fino. El mismo se centra en la secuencia de ejecución, desde que se produce un evento en la capa de presentación hasta que el mismo es atendido en forma completa.





    Las partes que lo componen son:



    • Vista: componente que recibe el estímulo y genera un evento, que puede involucrar a otros objetos de la IU. Corresponde a la capa de presentación, y al Front-End(en Web:Html, JavaScript,...), aunque suele haber parte en el MiddleWare (controles ASP,PHP,...)

    • Modelo: componente asociado a las entidades de negocio (cliente, factura, pago,...). En 3 capas incluye parte de la capa de negocio (entidades, pero no lógica de procesos) y toda la capa de acceso a datos. En 3 tiers se instala en el BackEnd (la BD) y parte en el MiddleWare (entidades de negocio y acceso a datos).

    • Controlador: componente asociado a la lógica de procesos del negocio. En 3 capas la parte que faltaba y en 3 tiers en el MiddleWare.