jueves, 18 de octubre de 2007
Modelos de datos, muchos
http://www.databaseanswers.org/data_models/index.htm
Nos vemos
Carlos Peix
viernes, 31 de agosto de 2007
Un proyecto interesante de un colega
Los invito a ver el proyecto de Caludio Meschini, un colega. Vean aquí la explicación que el mismo da de su bebé.
El dice que todavía le falta pulir cosas, pero les viene bien para entretenerse el sábado a la tarde.
Carlos Peix
jueves, 23 de agosto de 2007
Un caso de arquitectura (agil)
Me parece interesante la lectura este caso de aplicación web (basada en Ruby on rails) por su envergadura.
Carlos Peix
sábado, 18 de agosto de 2007
El principio de las cosas... Parte 2 de 2
Nos quedaron en el tintero, se esperaba que por pocos días, Inversión de dependencia y Segregación de interface.
d - Inversión de dependencia
Modelamos, sea en papel, en UML, en nuestra mente, como sea, lo hacemos. Creamos artefactos, clases por lo general, y relacionamos esos artefactos unos con otros.
Cuando hacemos esto, relacionar artefactos, establecemos dependencia entre ellos. Un artefacto deberá conocer a otro. El artefacto B requiere un artefacto del tipo C y otro del tipo D.
Vamos a implementar un pequeño modulo de registro de eventos para tener un ejemplo concreto de como nos afectan las dependencias en un modelo.
Nuestro módulo de registro incluirá unas pocas clases, veamos un diagrama:

Por supuesto siempre existe un contexto, ese contexto nos dará un marco para poder determinar problemas potenciales.
Si miramos el diagrama tenemos una violación potencial al principio Abierto / Cerrado.
Este modulo tiene como fin ser incluido en cualquier aplicación que desarrollemos y su objetivo es poder registrar información en algún dispositivo de salida.
Un ejemplo sería registrar errores en tiempo de ejecución, inicios de sesión por parte de los usuarios de un sistema, lo que creamos necesario.
Ese es mi contexto, puedo decir que mis mensajes serán muy uniformes, esos mensajes forman parte de mi dominio, son un concepto bien conocido, no existen grandes posibilidades de cambio en el corto plazo. Esto es una definición, no una estimación.
Por otra parte esa misma definición me habla de algún dispositivo de salida, allí la cosa es mas abierta, deberé de alguna manera estar preparado al cambio.
Volviendo al diagrama ahora puedo señalar algunas cuestiones:
- La clase LogHelper depende de Message
- La clase LogHelper depende de TextFile
El segundo caso es más complejo, mi definición habla de algún dispositivo de salida, mi primer dispositivo es TextFile, cambiar o agregar algún otro dispositivo de salida implicará cambios profundos en LogHelper.
Este último problema va más allá del acoplamiento, nuestro modelo esta acoplado y además es rígido.
El principio de Inversión de dependencia nos ayuda a eliminar o acotar este tipo de problemas, que nos dice el principio?
Los módulos de nivel superior no deben depender de módulos de bajo nivel.
Ambos deben depender de abstracciones.
Los detalles deben depender de abstracciones y no lo contrario.
Veamos ahora algunos cambios en el diagrama que reflejen la aplicación del principio.LogHelper ya no depende de TextFile, lo hace de OutPutProvider, la notación itálica nos indica que es una clase abstracta.
Quiero resaltar un concepto, en la definición del principio hablamos de Módulo de Nivel Superior.
Estos son menos propensos al cambio, son los que expresan nuestro negocio, representan el dominio del problema, su mención no es casual.
En cada Nivel atenderemos un Negocio determinado, aplicar Inversión de dependencia implica conocer los límites, el borde de cada nivel.
e - Segregación de interface
Existen situaciones en las que una misma clase será consumida por distintos clientes, agentes que solo necesitan conocer un conjunto acotado de responsabilidades de esa clase. Sin embargo esas clases siguen representando un concepto único en el modelo.Es una situación ambigua, la clase sigue siendo cohesiva y quienes la consumen manejan un concepto acotado de la misma en el dominio.
Supongamos una clase Cliente, nuestra clase es consumida por agentes que están interesados en distintos aspectos:

Estos atributos parecen estar directamente vinculados con las responsabilidades de Cliente, no hemos violado ningún principio, nuestra clase es cohesiva.
En estos términos veamos ahora como afecta esto a los artefactos consumidores de Cliente.
- Despacho
Solo necesita conocer el Domicilio - BuzonEletronico
Solo necesita cono cer la dirección electrónica.
Si vamos un poco mas allá nos damos cuenta también que estos artefactos que consumen la clase Cliente manejan conceptos que parciales respecto a la clase que consumen.
Un cambio en Cliente, implica cambios profundos nuevamente, la reutilización de Despacho y BuzonElectronico se ve seriamente limitada, y la lista continúa....
Algo entonces esta fuera de lugar, veamos que nos dice el principio de segregación de interface:
Los clientes no deben ser forzados a depender de interfaces que no utilizan.
Apliquemos el principio, creemos interfaces acotadas que serán consumidas por BuzonElectronico y por Despacho, Cliente ahora implementará esas interfaces.
Tenemos ahora un modelo mas elegante, mas cohesivo, poco acoplado.
Conclusiones:
Los principios de diseño nos permiten adelantarnos a los problemas, son conceptos que debemos manejar en forma natural, debemos integrarlos a nuestra forma de pensar al modelar o implementar aplicaciones orientadas a objeto.
La cuestión no termina aquí, es el comienzo, sobre estos principios se construyen muchos conceptos teóricos mas avanzados, se construyen patrones, etc.
Me despido ahora, nos vemos pronto.
lunes, 16 de julio de 2007
domingo, 24 de junio de 2007
El principio de las cosas... Parte 1 de 2
b - Principio Abierto / cerrado
c - Principio de Sustitución
d - Principio Inversión de dependencia
e - Segregación de interfaz
- Cambio mi motor de base de datos, de XXSql paso a NNSql.
Debo cambiar mi clase Cliente. - Cambio la forma de crear la salida HTML
Debo cambiar mi clase Cliente. - Agrego un reporte o modifico uno existente
Debo cambiar mi clase Cliente. - Cambio la política para calcular la presencia en el mercado
Debo cambiar mi clase Cliente.
Si vemos un poco mas allá de nuestras narices notaremos que además esto implicará cambios en aquellos artefactos que recurren a la clase Cliente para resolver alguna colaboración.
Bueno el problema es que nuestra clase Cliente tiene muchas responsabilidades, incluso algunas que exceden claramente sus responsabilidades naturales, me refiero a las responsabilidades de Cliente en su contexto de negocio.Posiblemente esa falta de cohesión nos lleve a otro problema, para mi es una regla que se cumple con rigor matemático, acoplamiento.

b - Abierto / cerrado
Una posible solución para lo relacionado con la persistencia podría ser la siguiente:

Propongamos un cambio en el requerimiento y veamos.
Problema planteado, que nos dice el principio Abierto/Cerrado?
La aplicación del principio a nuestro problema podría ser agregar una interface o una clase abstracta que sea bien conocida por Ventas, ClienteDB debería implementar la interface o heredar de la clase abstracta.

En el diagrama se puede apreciar la implementación para una cuestión más terrenal, mockobjects y test unitarios.
c - Sustitución
Vamos a aprovechar la capacidad de extensión que nos brindan los lenguajes OO, estamos frente a nuestra clase Cliente, con algunos cambios ya que los requerimientos del sistema han cambiado con el transcurso del tiempo y ahora un nuevo requerimiento nos exige considerar Clientes presenciales y Clientes virtuales.Hacemos OOP, Object Oriented Poragramming, contamos con los beneficios de la herencia, heredemos de Cliente.
La funcionalidad nueva esta relacionada con la obtención de la autorización de una transacción comercial.
El experto en autorización requiere que el cliente se identifique, pero el ClienteVirtual implementa el metodo Identificarse() disparando una Exception. Su lógica de negocio no provee un mecanismo de identificación.
El método Obtener entonces deberá tener un tratamiento especial para ClienteVirtual.Posiblemente el programador haga algo así:
if( typeof... )
//Tratamiento para ClienteVirtual
else
//Tratamiento para Cliente
El problema entonces es que CentroAutorización ya no puede tratar a ClienteVirtual como Cliente, debe conocer las características de la sub clase porque esta altera el comportamiento de la clase Cliente. ( Comportamiento, no implementación de comportamiento).
La solución en este caso es revisar eol diseño, posiblemente ClienteVirtual no este en la línea de herencia de Cliente, tal como pensamos en principio.
No atender estas cuestiones hace que nuestro diseño sea críptico, que los programadores no puedan confiar en la extensión de las clases y deban conocer el comportamiento de de cada una de ellas.
Bueno, para evitar esto debemos respetar el principio de sustitución. El mismo expresa:
La aplicación de este principio garantiza de alguna manera el éxito en la aplicación de los principios de Responsabilidad única y Abierto / cerrado.
En los próximos días completaré esta entrega con los principios restantes.
Espero que pese a lo básico este post les resulte de interés.
jueves, 21 de junio de 2007
Performance Bodyguard
El post es este:
http://ayende.com/Blog/archive/2007/06/20/Shocking-Rob.aspx
Para hacerlo funcionar es necesario:
- referencia a la DLL de log4net
- eliminar todos los using de Rhino.Commons
- Agregar un item en los Settings del proyecto con el nombre MaxNumberOfQueriesPerRequest, de tipo Int y valor 30 (por ejemplo...)
- Configurar log4net (Es importante configurar el Logger level de NHibernate.SQL a DEBUG)
Arquitectura multi-plataforma: Silverlight@Linux = Moonlight
Es notable el hecho de que tienen casi completa la implementación en 21 días. Creo que es un éxito del equipo, sin duda, pero también de la arquitectura de Silverlight.
Próximamente tendremos que empezar a discutir detalles importantes de arquitectura a tener en cuenta para producir aplicaciones para Silverlight. Hay mucha tela para cortar al respecto, desde separación de capas, patrones de comunicación, seguridad, paradigmas de UI, etc.
martes, 12 de junio de 2007
Reflection en ASPX, eh?
En algunos casos puede ser muy util ver que controles hay en una pagina que de mi aplicacion, por ejemplo puede servir para configurar permisos sobre controles como Toolbars o Grillas, editar informacion dinamicamente en base a WebParts de otras paginas, etc..
Cuando se crea un Toolbar en una pagina lo mas normal es cargar la informacion sobre que operaciones (botones) tiene en una base de datos manualmente, pero es aun mucho mejor si la pagina en la que se configuran esos permisos puede saber automaticamente que botones tiene cada pagina....
Lo primero que hay que hacer para obtener una pagina es crear un PageHandler, para eso lo unico necesario es la URL, por ejemplo "/Carpeta/Pagina1.aspx":
// Creo un Request Mock, realmente no se va a realizar ningun Request.
SimpleWorkerRequest request = new SimpleWorkerRequest("/Carpeta/Pagina1.aspx", string.Empty, TextWriter.Null);
HttpContext mockContext = new HttpContext(request);
// Obtengo el handler de la pagina en cuestion...
IHttpHandler handler = PageParser.GetCompiledPageInstance(virtualPath, fileName, mockContext);
// Si se quiere ya se puede leer el nombre de la clase de esa pagina :)
className = handler.GetType().BaseType.FullName;
Una vez que tenemos el HttpHandler que se encarga de procesar la pagina, lo que tenemos que hacer es procesarla. Pero primero creemos un delegado que nos va a servir para indicarle a la pagina que cree los controles que nosotros queremos dinamicamente.
Durante todo este ejemplo se obtienen controles Toolbar, que es hipoteticamente un control personalizado, pero podria ser cualquier otro tipo (incluso todos los controles).
delegate Toolbar BuildToolbarDelegate();
Ahora, el codigo que recorre todos los controles declarados y compara el tipo. Es importante notar que lo que en realidad se esta recorriendo no es la clase que nosotros creamos sino una clase que ASP.NET genera dinamicamente cuando se modifica un ASPX. Esa clase posee informacion sobre todos los controles y metodos necesitados por el runtime de .NET.
|
Esta tecnica simple permite hacer muchas cosas y extender la configuracion de la aplicacion usando bastante poco codigo. Incluso si se quiesiese se podria definir los tamaños de todos los controles en runtime, y para setearlos no seria tan complicado. Al menos no tanto como si no se usase esta tecnica.
De todas formas hay que tener cuidado porque cuando se procesan varias paginas puede empezar a ser lento para el usuario, pero eso se puede solucionar con Cache...
Suerte!
Smalltalk en la plataforma .NET?
Vista Smalltalk está profundamente basado en Windows Presentation Foundation y actualmente Peter está trabajando fuertemente en su implementación sobre Silverlight, que avanza permamentemente como puede seguirse en su blog.
Smalltalk es un lenguaje que -en mi opinión- coincide perfectamente con la arquitectura de soluciones con clientes del tipo WPF/Silverlight basados en ambientes distribuidos, y para todos los viejos que tuvimos nuestro romance con él, es bueno verlo volver en una plataforma moderna y cercana a nuestro trabajo cotidiano.
Home page de Vista Smalltalk.
lunes, 11 de junio de 2007
Testing de Repositorios
Cada vez que empiezo con un nuevo proyecto me pregunto como testear mejor los repositorios, o al menos de una formas mas sencilla. Esta vez hice 2 clases bases para eso:
- BaseMemoryRepository.cs: Es una clase abstracta que tiene 2 tipos genericos (
Si el TIdentity especificado es del tipo numerico (Int16, 32 ó 64) o GUID, la misma clase se encarga de la generacion automatica, pero si se quiere usar algo muy complicado la unica solucion es hacer un override del metodo object GetNextId().
De esta forma, un repositorio simple quedaria asi:
public class CustomerRepository : BaseMemoryRepository,
ICustomerRepository
{
protected override int GetEntityId(Customer ent)
{
return ent.Id;
}
protected override int GetEntityId(Customer ent)
{
return ent.Id;
}
protected override void SetEntityId(Customer ent, int ident)
{
ent.Id = ident;
}
}
- CustomerRepositoryTests.cs: Esta clase es un poco mas compleja de usar que la anterior. Provee la funcionalidad para realizar CRUD todo junto, si bien no es lo mejor que se puede hacer en TDD, normalmente testear las operaciones basicas es resuelto de la misma forma. Por ejemplo si se usa un ORM lo mas probable es que funciona todo o no funciona nada.
Es importante implementar 4 metodos en esta clase, estos se encargan de:
- Crear un objeto de Testing
- Devolver el Id de una entidad, necesario por el desconocimiento de cual es la propiedad Id de un objeto
- Validar si el id de un objeto es valido; una vez que se crea un objeto se espera que un nuevo Id se le asigne, por eso con validar solamente que sea mayor a 0 alcanza en la mayoria de los casos.
- El Test :) (que tiene que llamar a base.BasicOperationsTest())
Aca va un ejemplo:
Y listo, una vez que implementamos esas 2 clases por repositorio ya tenemos todos los test simples...
[TestFixture]
public class CustomerRepositoryTests : BaseRepositoryTests
{
public override void BuildTestEntity(out Customer e)
{
// Tengo que crear un nuevo Customer y configurar
// informacion de prueba
e = new Customer();
e.Name = "Name";
e.Gender = Gender.Male;
e.BornDate = DateTime.Now;
}
public override object GetEntityId(Customer ent)
{
return ent.Id;
}
public override bool IsValidEntityId(Customer entity)
{
// Una validacion simple
return entity.Id > 0;
}
[Test]
public override void BasicOperationsTest()
{
// Aca hago el trabajo real!
base.BasicOperationsTest();
}
}
El codigo completo con los 2 ejemplos de implementacion los pueden bajar de acá o de acá
viernes, 8 de junio de 2007
Add-In de PowerShell para Reflector
Disponible en el sitio de Add-Ins de Reflector.
Debugging Avanzado en .NET
http://blogs.msdn.com/latamarchitectnewsletter/archive/2007/06/08/debugging-avanzado-en-net.aspx
Puntapié inicial
El objetivo del logs intercambiar noticias, conceptos e ideas entre participantes del grupo de Arquitectura del MUG. Cualquier miembro del grupo que tenga matrial interesante para compartir puede solicitar su habilitación como autor en la lista.
Esperamos que el recurso sea un buen complemento a la actividad de debate tradicional de la lista de correos.