11.30.2008

Arquitecturas n-tier – Ventajas y Desventajas

Ahora que ya aclaramos las diferencias entre una arquitectura n-layer y una arquitectura n-tier en un post anterior, surgen dudas respecto a las ventajas y las desventajas de cada una de ellas.  Es precisamente respecto a ese tema lo que vamos a escribir en este post. Inicialmente nos vamos a enfocar en la arquitectura física ( n-tier ) y en post posteriores vamos a escribir acerca de las arquitecturas lógicas ( n-layer ).

Ventajas y Desventajas de las arquitecturas n-tier

Desde el punto de vista físico, la duda principal nace al decidir si utilizamos una arquitectura de 2 capas (2-tier) o una arquitectura de 3 capas(3-tier). Básicamente, una arquitectura 2 capas es una arquitectura donde el UI y los componentes de negocio o los componentes de negocio y el repositorio de datos residen en una misma capa física – Por ejemplo, aplicaciones web que tienen los componentes de negocio en el web server. Las aplicaciones 3 capas ( 3-tier ) dividen cada uno de estos componentes en ubicaciones físicas diferentes – Por ejemplo, cuando se utiliza un servidor de aplicaciones para hostear los componentes de negocio y otro servidor (web server) para hostear las páginas del sitio web.

Las desventajas principales de una arquitectura 3-tier sobre una arquitectura 2-tier son el costo y la complejidad. El costo aumenta por que se requiere un servidor adicional para hospedar los componentes desde donde se va a consumir toda la lógica de negocios, lo que trae consigo ítems adicionales que se deben tomar en cuenta tales como costo de licencias, costo mantenimiento de servidor, etc. La complejidad aumenta por que los componentes viven en su propio “ecosistema”, con lo cual se crea un punto extra de falla; es decir, tengo un servidor más que mantener y monitorear. Además, se va a crear un “brinco” adicional cada vez que se hace una llamada a los componentes de negocio que residen en este servidor de aplicaciones, lo que me lleva a tener una respuesta más lenta ( a diferencia de una arquitectura 2 capas donde los componentes residen en el mismo servidor donde reside la aplicacion ).

Las ventajas de una arquitectura 3 tier respecto a una arquitectura 2-tier son básicamente las siguientes:

Seguridad: Al agregarse un servidor de aplicaciones se agrega un nivel extra de seguridad, ya que existen procesos de autenticación y autorización en el servidor de aplicaciones que se agregan a los procesos ya existentes en los otros servidores, – base de datos y servidor Web -con lo que el hackear el servidor de aplicaciones, no da acceso de facto al servidor de base de datos.

Escalabilidad: Al utilizarse un servidor de aplicaciones se pueden crear pools de conexiones hacia la base de datos con lo cual se reutilizan las conexiones existentes para múltiples usuarios. Además, si mi aplicación es accedida por una cantidad de usuarios superior a la esperada y su rendimiento espera a bajar, podemos crear balanceo en el servidor de aplicaciones para que el tiempo de atención y respuesta sea más rápido.

11.23.2008

Linq – Join sobre Múltiples Listas Genéricas de Objetos

En el post anterior, hicimos una consulta a una lista de productos utilizando Linq – Linq2Objects. Sin embargo, es normal buscar objetos desde múltiples fuentes de datos. En Linq tenemos la clausula join que nos permite unir múltiples fuentes de datos y no solamente desde base de datos.

Supongamos que tenemos una lista de clientes y un plan de millas de una aerolínea y tenemos que buscar todos los clientes que pertenecen a un plan específico definido por la aerolínea.

El primer paso, es crear la clase cliente y la clase plan de millas. El código de ambas clases se presenta a continuación.

public class Cliente
{
public int Id { get; set; }
public string Nombre { get; set; }
public string PaisResidencia { get; set; }
public int IdPlanDeMillas { get; set; }
}


public class PlanDeMillas
{
public int Id { get; set; }
public string Plan { get; set; }
public bool VencenMillas { get; set; }
}


Como podemos ver, el plan de millas esta asociado con el cliente a través del Id del plan de millas dentro de la clase cliente. Seguidamente mostramos dos métodos en donde se inicializan dos listas, una de clientes y otras de millas. En la lista de clientes se indica a cual plan de millas pertenece el cliente.



private static List<Cliente> GetListaClientes( )
{
return new List<Cliente>( )
{
new Cliente ()
{
Id = 0,
IdPlanDeMillas = 0,
Nombre = "Juan Romero",
PaisResidencia = "Guatemala"
},
new Cliente ()
{
Id = 1,
IdPlanDeMillas = 1,
Nombre = "Carlos Jimenez",
PaisResidencia = "Uruguay"
},
new Cliente ()
{
Id = 2,
IdPlanDeMillas = 2,
Nombre = "Elisa Perez",
PaisResidencia = "Guatemala"
},
new Cliente ()
{
Id = 3,
IdPlanDeMillas = 2,
Nombre = "Sebastian Ortuño",
PaisResidencia = "Uruguay"
},
new Cliente ()
{
Id = 4,
IdPlanDeMillas = 0,
Nombre = "Luis Barquero",
PaisResidencia = "Costa Rica"
},
new Cliente ()
{
Id = 5,
IdPlanDeMillas = 1,
Nombre = "Ana Rodriguez",
PaisResidencia = "Costa Rica"
},
};
}



private static List<PlanDeMillas> GetListaPlanes( )
{
return new List<PlanDeMillas>( )
{
new PlanDeMillas ()
{
Id = 0,
Plan = "Estándar",
VencenMillas = true
},
new PlanDeMillas ()
{
Id = 1,
Plan = "Oro",
VencenMillas = false
},
new PlanDeMillas ()
{
Id = 2,
Plan = "Platino",
VencenMillas = false
}
};
}


Por último, creamos la sentencia Linq para hacer un join de ambas colecciones a través del Id del Plan de Millas. El código completo con la llamada a la inicialización de las listas, la consulta Linq, y su despliegue en la consola se muestra a continuación.



 



List<Cliente> listaClientes = GetListaClientes( );
List<PlanDeMillas> listaPlanes = GetListaPlanes( );

var resultado = from cliente in listaClientes
join plan in listaPlanes
on
cliente.IdPlanDeMillas equals plan.Id
select new
{
cliente.Nombre,
cliente.PaisResidencia,
plan.Plan,
plan.VencenMillas
};

Console.WriteLine("--------------------------------------");
Console.WriteLine("Reporte de plan de millas por usuario");
Console.WriteLine("--------------------------------------");
foreach (var clientePlan in resultado)
{
Console.WriteLine("Cliente: {0}", clientePlan.Nombre);
Console.WriteLine("Tipo de Plan: {0}", clientePlan.Plan);
Console.WriteLine("Vencen las millas: {0}", clientePlan.VencenMillas);
Console.WriteLine("--------------------------------------");
}



Al analizar la consulta linq en el código anterior, podemos identificar las siguientes características de la consulta:





  1. El uso del join para hacer la consulta. En este caso, estamos llevando a cabo esta operación en base al Id del plan de millas en la clase PlanDeMillas y el Id del plan incluido en el cliente.




  2. La selección de un objeto customizado como parte de la consulta. En este caso, deseamos una lista de objetos de un tipo que no tenemos definido, por lo tanto, al crear el nuevo objeto que se va a agregar a la lista de forma iterativa no indicamos el tipo del objeto que vamos a almacenar en la lista, si no que simplemente inicializamos un tipo anónimo. En este caso, el compilador genera un nombre único para el nuevo tipo.




  3. El uso del tipo var. Dado que la clausula select retorna un tipo anónimo, no se puede definir un tipo explícito tal como IEnumerable<T> para contener el resultado de la consulta en la lista. En este caso el compilador infiere el tipo de la variable a partir de su inicialización, y declara la lista en base a este. Esta característica en C# 3.0 y superior se conoce como variables locales tipadas implícitamente.




El resultado al ejecutar la consulta anterior se muestra en la siguiente pantalla.



image

11.20.2008

Usando Linq para Hacer Búsquedas de Objetos en Listas Genéricas

En post pasados, vimos como realizar búsquedas de objetos en una lista genérica utilizando distintos métodos de la clase List. En este post, vamos a utilizar Linq para buscar objetos dentro de una lista genérica.

En primera instancia, vamos a utilizar la clase producto que hemos venido utilizando en post anteriores. Vamos a inicializar una lista de productos de la misma manera que lo hicimos en el post anterior:

List<Producto> listaProductos = new List<Producto>( )
{
new Producto ()
{
Id = 09,
Nombre = "Impresora Canon MP140",
PaisDeOrigen = "Japón",
Precio = 50
},
new Producto ()
{
Id = 15,
Nombre = "Age of Empires III",
PaisDeOrigen = "USA",
Precio = 29.99
},
new Producto ()
{
Id = 12,
Nombre = "Laptop Dell Vostro",
PaisDeOrigen = "USA",
Precio = 999
},
new Producto ()
{
Id = 33,
Nombre = "IPod Nano 2",
PaisDeOrigen = "USA",
Precio = 199.99
},
new Producto ()
{
Id = 26,
Nombre = "Audífonos JVC",
PaisDeOrigen = "Holanda",
Precio = 39.99
}
};



Seguidamente, vamos a crear una consulta utilizando LinqToObjects para buscar todos los objetos que tienen su país de origen igual a “USA”. El siguiente código nos muestra como hacerlo.



IEnumerable<Producto> resultado =
from producto in listaProductos
where producto.PaisDeOrigen ==
"USA"
select producto;


Console.WriteLine("----------------------------");
Console.WriteLine("Productos Originarios de USA");
foreach (Producto producto in resultado)
{
Console.WriteLine("----------------------------");
Console.WriteLine("Nombre: {0}\nPrecio: {1}",
producto.Nombre, producto.Precio);
}


Como podemos ver en el código anterior, Linq tiene una sintaxis muy similar a la de SQL Server, solamente que Linq además de poder ser utilizado en SQLServer (aunque parece que se va a descontinuar), es aplicable a Objetos, Xml, DataSet, EF y a los Data Services.



En este ejemplo, para retornar la lista de productos que tienen su país de origen como “USA”, se debe de asignar el resultado de la consulta a una lista genérica de productos, esta lista esta definida por IEnumerable<Producto>. A través de la claúsula from, estamos definiendo el origen de los datos, permitiendole a Linq iterar sobre cada producto para identificar las variables que cumplen con el criterio de selección a través de la palabra reservada from. Por último, se indica que se quiere proyectar ( seleccionar ) de la consulta realizada. En este caso escojimos seleccionar el producto como tal, pero como veremos en post posteriores, podemos utilizar tipos anónimos para seleccionar campos de un objeto, o de varios objetos utilizados como repositorio de datos.



El resultado al ejecutar la consulta anterior se puede ver en la siguiente imagen.



image

11.15.2008

Inicializando Colecciones con la Inicialización Automática de Objetos en C# 3

En el post anterior vimos como inicializar objetos utilizando sus propiedades y no el constructor del objeto. En este post vamos a continuar con este tema, mostrando como se inicializa una lista genérica de objetos a través de sus propiedades.

Igualmente, vamos a utilizar la clase producto que utilizamos en el post anterior. En este caso, no vamos a crear instancias de producto y luego las vamos a agregar a la lista, si no que vamos a inicializar los objetos y la lista utilizando la inicialización automática a través de propiedades en C#. En el siguiente bloque de código se muestra como llevar a cabo esta inicialización.

List<Producto> listaProductos = new List<Producto>( )
{
new Producto ()
{
Id = 0,
Nombre = "Impresora Canon MP140",
PaisDeOrigen = "Japón",
Precio = 50
},
new Producto ()
{
Id = 1,
Nombre = "Age of Empires III",
PaisDeOrigen = "USA",
Precio = 29.99
},
new Producto ()
{
Id = 2,
Nombre = "Laptop Dell Vostro",
PaisDeOrigen = "USA",
Precio = 999
}
};


Como podemos ver en el código anterior, podemos inicializar la lista con instancias de objetos que se inicializan automáticamente con sus propiedades a la hora de agregarse a la lista. Ahora podemos recorrer la lista y visualizar su contenido como lo haríamos con cualquier otra lista genérica.



 



foreach (Producto producto in listaProductos)
{
Console.WriteLine("-------------------------");
Console.WriteLine("Id Producto: {0}", producto.Id);
Console.WriteLine("Nombre Producto: {0}", producto.Nombre);
Console.WriteLine("País Producto: {0}", producto.PaisDeOrigen);
Console.WriteLine("Precio Producto: {0}", producto.Precio);
}


El resultado al ejecutar el código anterior desde una aplicación de consola es el siguiente:



image

11.12.2008

Inicializadores de Objetos en C# 3.0

Una de las nuevas caracterísiticas en C# 3.0 es la inicialización de objetos. En versiones anteriores del lenguaje C#, para inicializar un objeto a la hora de su construcción, se debían crear constructores con los parámetros requeridos, los cuales llevaban a cabo la inicialización del objeto que esta siendo instanciado. A partir de la versión 3.0 de C#, se pueden inicializar objetos tanto a través de constructores, como a través de inicializadores automáticos.

¿En que consisten estos inicializadores? Los inicializadores, son una manera simple de inicializar objetos a través de sus propiedades. Para comprender mejor esta característica veamos el siguiente ejemplo.

Vamos a trabajar con la clase producto definida en el post pasado. Vamos a crear una instancia de esta clase utilizando los inicializadores de objetos presentes en C# 3.0 o superior.

Como podemos ver en la siguiente imagen, cuando estamos inicializando la instancia de la clase, VS 2008 nos permite ver las propiedades existentes dentro de la clase para llevar a cabo la inicialización a través del intellisense.

image

El código completo para inicializar la instancia de prod es el siguiente.

static void Main( string[] args )
{
Producto prod = new Producto( )
{
Id = 0,
Nombre = "Impresora Canon MP140",
PaisDeOrigen = "Japón",
Precio = 50
};
Console.WriteLine("Producto: {0}", prod.Nombre);
}


El resultado de la ejecución del código anterior es el siguiente



image



Igualmente, podemos inicializar objetos dentro de otros objetos de la misma manera que hicimos la inicialización anterior.



Supongamos que existe una clase DetalleDeFactura que contiene un producto asociado y la cantidad del producto que se agregó al detalle. El código de esta clase es el que se ve a continuación:



public class DetalleDeFactura
{
public int Id { get; set; }
public int CantidadDeProducto { get; set; }
public Producto ProductoSeleccionado { get; set; }
}



Para inicializar la clase DetalleFactura utilizamos el código siguiente:



 



static void Main( string[] args )
{
DetalleDeFactura detalle = new DetalleDeFactura( )
{
Id = 1,
CantidadDeProducto = 3,
ProductoSeleccionado = new Producto( )
{
Id = 0,
Nombre = "Impresora Canon MP140",
PaisDeOrigen = "Japón",
Precio = 50
}
};

Console.WriteLine("Detalle: {0}", detalle.Id);
Console.WriteLine("Producto: {0}", detalle.ProductoSeleccionado.Nombre);
Console.WriteLine("Cantidad: {0}", detalle.CantidadDeProducto);
}



El resultado al ejecutar esta consulta es:



image



Como podemos ver, esta forma de inicializar objetos es muy intuitiva y “limpia” a la hora de digitar el código requerido para iniciar el objeto requerido. Además, esto nos permite utilizar expresiones Lambda en Linq como veremos en posts posteriores.

11.08.2008

Propiedades Automáticas en C# 3

Una de las nuevas características en C# 3 son las propiedades automáticas. Esta característica consiste simplemente en tener la posibilidad de declarar las propiedades requeridas, con el get y el set vacíos. El compilador se encarga de generar en código intermedio (MSIL) los atributos requeridos para cada una de las propiedades automáticas. Para entender mejor esta característica, veamos un ejemplo.

Supongamos que deseamos tener una clase Producto con una serie de atributos como el Id, el nombre, el precio y el país de origen. Anteriormente, para llevar a cabo esta tarea, debiamos definir los atributos y seguidamente crear las propiedades de estos atributos. Con esta nueva característica, simplemente tenemos que crear las propiedades vacías tal y como se ve en la siguiente definición de la clase.

public class Producto
{
public int Id { get; set; }
public string Nombre { get; set; }
public double Precio { get; set; }
public string PaisDeOrigen { get; set; }

public override string ToString( )
{
return string.Format("Id: {0}, Producto: {1}, Precio: {2}, Pais: {3}", Id, Nombre, Precio.ToString( ), PaisDeOrigen);
}
}



Para utilizar la clase anterior, simplemente se crea una instancia de la clase producto, y se acceden sus propiedades de la manera que normalmente lo haríamos si los atributos de la clase hubieran sido definidos manualmente.



static void Main( string[] args )
{

Producto miProducto = new Producto ();
miProducto.Id = 0;
miProducto.Nombre = "Audífonos JVC Super bass";
miProducto.PaisDeOrigen = "Holanda";
miProducto.Precio = 49.99;
Console.WriteLine(miProducto);
}



El resultado al ejecutar este código se ve en la siguiente figura:



image



En este caso, para imprimir la información del producto, cuando se llama al método estático WriteLine de la clase Console, se esta llamando al método que acabamos de sobre escribir ToString de la clases Producto. Este es un comportamiento que se da por defecto cuando se manda a escribir algún objeto.



Ahora, ¿qué obtenemos al utilizar las propiedades dinámicas? Básicamente nos liberamos de la necesidad de declarar variables privadas y su accesor get y set, osea la propiedad. Aunque podemos usar alguna herramienta de refactoring para encapsular los campos, si no se requieren reglas de validación de negocio dentro de las propiedades, el código es más legible utilizando propiedades automáticas.

11.06.2008

¿Esta Linq To SQL Muerto?

En muchas ocasiones, surge la pregunta casi obligada por parte de la gente acerca de si Linq To SQL es una buena opción a utilizar en el desarrollo de aplicaciones. Se ha escrito mucho acerca de cuál es el rol del LinqToSQL y si realmente es un ORM o no lo es. Igualmente, existen muchos debates acerca de cual es la mejor opción para utilizar LinqToSQL en una arquitectura n capas.

Seguidamente, con la aparición del entity framework se generó más confusión, dado que el entity framework si es un ORM como tal; dejando entonces la pregunta: ¿ Qué rol juega LinqToSQL en el desarrollo de aplicaciones ? ¿ Podrán los dos convivir ?

Todo esto por supuesto, tomando en cuenta que Linq no es solamente LinqToSQL si no más bien un lenguaje que en este momento cuenta con un conjunto de fuentes de datos en donde se puede utilizar. Además de LinqToSQL se incluyen LinqToXML, LinqToObjects, LinqToDataSet, LinqToDataServices y LinqToEntities( EntityFramework )

En días reciente, el grupo de ADO.NET hizo un anuncio que parece va a aclarar un poco más las cosas. Al parecer, la idea del grupo que desarrolla Linq es favorecer  y mejorar el entity framework y empezar a matar Linq to SQL. David Hayen es un poco más directo en sus apreciaciones sobre el futuro de LinqToSQL. Saquen sus conclusiones.

11.02.2008

Buscando un Objeto en una Lista Genérica Utilizando el Método Contains

Una de las tareas más comúnes cuando estamos desarrollando una aplicación que utiliza una lista de tipo Generic, es el identificar si en la lista existe un objeto determinado. Para llevar a cabo esta labor, existe un método en la clase List<T> llamado Contains que hace precisamente esto. Este método determina si los objetos son iguales utilizando el comparador de igualdad EqualityComparer.Default para el tipo T, el tipo de los elementos en la lista. Este método lleva a cabo una búsqueda lineal, por lo que esta es una operación O(n), donde n = todal de elementos en la lista.

Este comparador determina a través de su propiedad Default si el tipo T implementa la interface genérica System.IEquatable; si es así, retorna un EqualityComparer que utiliza esa implementación. Si no lo implementa, retorna el EqualityComparer que utiliza Object.Equals y Object.GetHasCode de T. En otras palabras, si tenemos implementado un método para comparar dentro de nuestra clase T, se utiliza este método, de lo contrario, se utiliza el método por defecto Object.Equals. El siguiente ejemplo muestra como se implementa este método, y como se busca un objeto en una lista genérica utilizando el método Contains.

Primeramente, vamos a utilizar la clase persona utilizada en ejemplos anteriores, pero en esta oportunidad le vamos a agregar la implementación de IEquatable.

public class Persona : IEquatable<Persona>
{
private int m_Id;
private string m_Nombre;
private string m_Apellido1;
private string m_Apellido2;
private string m_Pais;


Seguidamente vamos a implementar el método Equals de la interfase IEquatable. En este método debemos definir como vamos a llevar a cabo la comparación entre la instancia actual, y la que viene por parámetro. En nuestro ejemplo, vamos a decir que un objeto es igual a otro si el nombre de la persona de ambos objetos es el mismo, y si el Id de los objetos es el mismo. La implementación de este método es la siguiente:



#region IEquatable<Persona> Members

public bool Equals( Persona other )
{
if (this.Nombre == other.Nombre
&& this.Id == other.Id)
return true;
return false;
}

#endregion



Para probar nuestro método de comparación, vamos a crear una lista genérica con 6 personas, tal y como lo hicimos en los ejemplos anteriores.



List<Persona> listaPersonas = new List<Persona>( );
Persona p1 = new Persona(1, "Manuel", "Perez", "Ruiz", "Mexico");
Persona p2 = new Persona(2, "Arnoldo", "Rojas", "Gomez", "Panama");
Persona p3 = new Persona(3, "Juan", "Ramos", "De la O", "España");
Persona p4 = new Persona(4, "Miguel", "Cortez", "Valerio", "Costa Rica");
Persona p5 = new Persona(5, "Andres", "Perez", "Fonseca", "Mexico");
Persona p6 = new Persona(6, "Antonio", "Aleman", "Rodriguez", "Mexico");
listaPersonas.Add(p1);
listaPersonas.Add(p2);
listaPersonas.Add(p3);
listaPersonas.Add(p4);
listaPersonas.Add(p5);
listaPersonas.Add(p6);



Por último, vamos a crear una instancia de persona y la vamos a incializar con los datos de la persona p2, y vamos a buscar en la lista si esta nueva instancia que llamaremos personaABuscar contiene los datos de una persona que si existe dentro de la lista que acabamos de crear - listaPersonas. Esta búsqueda la haremos utilizando el método Contains, el cual como mencionamos anteriormente, utiliza el método Equals implementado en la clase Persona.



Persona personaABuscar = new Persona(2, "Arnoldo", "Rojas", "Gomez", "Panama");
if (listaPersonas.Contains(personaABuscar))
Console.WriteLine("{0} {1} existe en la lista",
personaABuscar.Nombre, personaABuscar.Apellido1);
else
Console.WriteLine("{0} {1} existe NO en la lista",
personaABuscar.Nombre, personaABuscar.Apellido1);



El resultado al ejecutar el código anterior – este proyecto al igual que los anteriores es un proyecto de consola – se ve en la siguiente imagen.



image