lunes, julio 17, 2006

Net Framework 3

Al parecer ya está esto más listo, al menos a un nivel tan estable como para empezar a hacer nuestros primeros pininos en está nueva tecnología...

Esperamos que en próximos proyectos podamos empezar a usar algo de esto.

Pueden ver más info de lo que se incluye en un post de Christian Strevel.

Integración Continua

La integración continua es una práctica muy útil en el desarrollo de software (lastima que no la usamos, bueno no al 100%).
Recientemente escuche algo de un servidor de integración y me llamo la atención. Pense, en que podrá servirnos a nosotros, recuerdo haber visto algo de esto en internet, de pronto recorde que ya teníamos uno, que se empezo a utilizar en tres proyectos, uno de los cuales se cancelo y se quedo en un proof of concept, otro fue tan sencillo que nunca realmente se notaron los beneficios que CI (Continuous Integration) pudo haber brindado y en este último que nos hubiera servido muchísimo en algún momento se desconfiguro el Build Server y se dejo de utilizar.

Bueno en resumen, teníamos el servidor, pero no la práctica de integración continua. CI es de esas cosas como control de versión y administración de proyectos que por más que tengas CVS o MS Project (o algo mejor), si tu equipo no tiene buenas prácticas de Administración de la Configuración o Planeación de Proyecto de poco sirve. Lo mismo nos ocurre ahora...

Bueno volviendo al tema. Martin Fowler reescribió sobre CI, si quieren conocer un poco más de esto se los recomiendo.

Por último, aunque Team Foundation Server aún le falta madurar un poco en algunas de sus áreas (al igual que otras de VSTS), trae ya un servidor de Integración con el que Christian y yo estuvimos jugando.

Como funciona, simplemente creas un nuevo build, le dices que proyectos de Visual Studio o que soluciones quieres compilar, cuales dependen de cuales y que pruebas quieres correr sobre el build. Una vez que haces esto y programas la frecuencia (minímo diario), todo funciona en automático. El build server tomara del repositorio los archivos que necesita, compilara lo que le indicaste, correrá las pruebas y te deja todo el output (dlls, archivos de pruebas, exes, etc) en un dropbox (un folder compartido en red). La mejor parte es que todo esto se integra con los reportes de Sharepoint que tiene el Team Foundation, por lo que podemos ver estadísticas como las siguientes:
Pruebas fallando con bugs activos y con bugs activos,
Regresiones: pruebas que ya pasaban y ahora no.
Otros indicadores de calidad,
% de pruebas que pasan.
% de codigo cubierto por pruebas (Code Coverage).

También se pueden hacer otro tipo de revisiones aparte de las pruebas automatizadas, como para poder hacer el deployment o release de un build en partícular.

La verdad es que nosotros estamos medio güeyes, la regamos, pensamos que los builds eran para tenerlos. Como? Si pensabamos que para tenerlos y poder obtener de una fecha en partícular los ejecutables y librerías necesarias para de ahí poder hacer un release. La verdad es que esto de los builds tiene mucho mayor sentido que eso: Continuous Integration. Esto nos va a permitir saber como vamos, que tal trabajamos juntos, si vamos mejorando o empeorando, detectar rápidamente como nos pegan los cambios de otros y arreglarlos rápidamente y más que nada, tal como dice martin fowler "treat integration as a non-event", "trata la integración como si no fuera un evento", es decir, no vamos a estar al final del proyecto integrando todos los modulos.

Cómo usar ActiveSync Remote Display con Windows Mobile 5.0.

Remote Display es una herramienta bastante útil. Para hacerla funcionar con Windows Mobiles, sólo hay que copiar los archivos de "C:\Program Files\Windows Mobile Developer Power Toys\ActiveSync_Remote_Display\devices\wce400\armv4t" a "\Windows" en el dispositivo y listo.

En el link les da un poco más de rollo.

viernes, julio 14, 2006

Lazy Load usando delegates


Hace mucho un par de meses, nos vimos en la necesidad de implementar nuestro Lazy Loading a mano.
Hay diferentes formas de hacerlo, la mejor explicación que he leído es la de fowler. En su libro Patterns of Enterprise Application Architecture viene más detallado.

Bueno lazy load tiene 4 formas de ser implementado, Virtual Proxy, Ghost, Lazy Initialization y Value Holder. Frameworks de ORM como NHibernate lo manejan muy bien y de una manera casi transparente, pero en este caso no pudimos usar ningún framework de esos, por lo que tuvimos que usar muchos de los patrones que fowler describe en su libro.

Hizimos una combinación de Lazy Initialization con Virtual Proxy.

La diferencia principal con los ejemplos que da fowler, es que nosotros desde el business object, en este caso un cliente, no teníamos acceso a la capa de acceso a datos, ni siquiera a una interfaz, por lo que todo el truco fue usar un delegado. Esto último nos permitio también la posibilidad de reutilizar este mismo VirtualProxy para otras plataformas, la primera va y saca la información de una base de datos local y la otra va a sacarla de un servidor que tiene un esquema distinto, pero ambos mapean las columnas a las propiedades del business object de la misma forma.

Bueno resumidamente el diseño quedo así:
Tenemos un ClienteCoporativo que es una lista de clientes y al igual que las otras dos clases, tambien implementa ICliente, aparte de permitirnos iterar sobre la colección de clientes, tiene propiedades que nos regresan los acumulados, por ejemplo saldos.
ICliente define las propiedades y metodos que debe tener la clase.
Cliente es nuestro business entity.
ClienteLazy es nuestro Virtual Proxy y ahí está la parte interesante.

Ahora, para que es útil hacer un Lazy Loading. Bueno cuando cargamos de la base de datos información de una colección de clientes, nos interesa tener al menos el nombre y la descripción, lo cual podemos hacer directamente.

Ahora se presentan diferentes escenarios:
1. Con la lista de cliente simplemente mostramos estos al usuario quien podra seleccionar alguno de la lista y trabajar sobre uno en partícular, por lo que hasta aquí no existe la necesidad de crear completo todos los demas objetos cliente de la lista, simplemente hasta el momento en que se seleccione alguno nos terminamos de traer su información completa.
2. Seleccionaron algo como ver todos, por lo que hasta este momento es cuando necesitamos cargar toda la información en todos los objetos.
3. Simplemente resulta información suficiente el nombre y descripción, por lo que esto términa la interacción con el usuario.

El cargar un entity de este tipo se puede volvier pesado, si se considera que hay muchos objetos relacionados con este, como saldos, pudiera haber facturas, consignatarios, etc y no queremos traernos toda una gráfica compleja de objetos sino hasta el momento en que se necesite. Por otro lado no queremos que el usuario del business entity tenga que estar al pendiente de si se cargo o no ya el objeto, por ejemplo:
if(cliente.Facturas==null)
cliente.Facturas = FacturasDataAccess.GetFacturas(cliente.Clave);
cliente.Facturas.DoSomething()

Ok es enfadoso tener que estar haciendo esas validaciones, pero lo de menos es que sea enfadoso, lo malo es que es propenso a tener errores en tiempo de ejecución cuando se nos llega a olvidar (NullReferenceExcepction). Por otro lado, pudieramos no tener disponible FacturasDataAccess en todo momento. Si tenemos que hacer este tipo de validaciones pierde completamente el sentido de que el cliente tenga una propiedad Facturas si siempre que se vaya a usar debemos estar al tanto de como podríamos obtenerla de ser necesario.

Ok, así es que se vuelve impractico el querer cargar todo a la primera y se vuelve enfadoso el tener que validar y cargar las propiedades en el momento que las queramos usar.

Nuestro ClienteLazy es simplemente un wrapper para un Cliente.
De tal forma que podemos cargar nuestra colección con puros IClientes (que son más ligeros y rápidos de cargar) y cuando a un ICliente le piden algo como
Corporativos[0].Saldo
El ICliente verifica si ya tiene creado un objeto cliente con información real y de no tenerlo va y lo busca, lo crea y luego delega en el cliente para regresar la información. Los accesos subsecuentes ya no requieren ir a traerse nuevamente el cliente.

Ok, así es como lo define Fowler, como hicimos nosotros?

Como ClienteLazy y en general toda la capa de Business Objects y Business Entities no tenía acceso a la(s) capa(s) de DataAccess, tuvieron que usar un delegate para que este supiera como obener el cliente.

Este es parte del código de ClienteLazy

private Cliente c;
private GetCliente Get;
public ClienteLazy(GetCliente delegado, string clave, string nombre)
{
this.clave = clave;
this.nombre = nombre;
this.Get = delegado;
}
private void Check()
{
if (c == null)
c = Get(clave);
}


public string FormaDePago
{
get
{
Check();
return c.FormaDePago;
}


public string Nombre
{
get
{
return this.nombre;
}
}


Esta es la definicion del delegado, que marca la firma para el metodo.
public delegate Cliente GetCliente(string clave);

Si se fijan, al momento de acceder a forma de pago, vamos y nos aseguramos de tener al cliente listo y luego accedemos a su propiedad, pero al momento de regresar el nombre simplemente usamos nuestra variable local. La parte mas interesante esta en que el metodo Check usa el delegado para obtener al cliente.

Asi que los pasos son los siguientes.
Tenemos una clase (Virtual Proxy) que recibe en el constructor, la clave, nombre y otras propiedades que ustedes quieran dejar accesibles sin necesidad de ir a traerse el cliente completo. Tienen un delegado (la parte mas importante) que sabe que como crear un cliente, y por ultimo implementamos una interfaz común para hacer lucir al Virtual Proxy como el objeto real y al implementarla simplemente encapsulamos las propiedades del objeto real verificando en cada acceso que ya lo tengamos listo.

jueves, julio 13, 2006

Los sapitos


Ahora cambiando un poco del tema habitual de mi blog, les comento de un divertido y medio adictivo juego. Los sapos saltarines.

Lastima que me duro poco la adiccion porque estaba empzando a gustarme....


Para los que el juego no ha llegado a su inbox, mandenme un mail y se los paso.

miércoles, julio 12, 2006

Descubri el RSS de Blogger.com

Ayer escribí decepcionado de blogger, porque ofrecía RSS. Pero acabo de descubrir que si, sólo que no lo muestran explicítamente por alguna extraña razón.

Bueno el chiste es que aquí les paso el link para mi RSS, para los que tengan RSS Readers se pueden suscribir a miguelmadero.com/atom.xml, para los que no, les recomiendo www.SharpReader.com Para los que esten en blogger.com y quieran publicar su RSS a quien sea que los lea, pongan un link a http://sunombre.com/atom.xml

Más de delegados anónimos

Hoy necesitabamos tener toda una lista de partidas que están dentro de una compra.
Una compra es una lista de pedidos y un pedido es un diccionario de partidas, así que como sacarlo de manera sencilla.


public List Partidas
{
get
{
List partidas = new List();
ForEach(delegate(Pedido pedido) { partidas.AddRange(pedido); });
return partidas;
}
}

No sólo esto simplifico nuestro código, sino que lo hizo más seguro, encapsulando variables que no necesitaban ser de instancia.
Había otras soluciones, pero la más obvia era hacer algo como lo siguiente

List partidas; // Ahora es variable de instancia para que el delegate lo pueda usar.
public List Partidas
{
get
{
partidas = new List();
ForEach(new Action(AddPartidas)); // Ahora usamos un metodo como delegado
return partidas;
}
}

public void AddPartidas(Pedido pedido)
{
partidas.AddRange(pedido);
}

No solo el código es más largo, creamos un metodo extra muy sencillo que sólo se usa desde un lugar, sino que aparte y lo peor de todo, es que ahora cualquier metodo o propiedad de la clase puede usar la variable partidas, pensando que sirve para algo más que para regresarla a algún cliente de este objeto desde la propiedad Partidas.

RSS Readers

Ayer baje el http://www.sharpreader.net/ le configure algunos blogs y ya esta mas saturado que me Outlook, pero con información que yo seleccione como interesante.

Un RSS reader, baja todo el contenido de cierto sitio web y lo deja listo en tu máquina para que puedas leerlo offline, funciona algo similar a un cliente de correo. Si leen mucho en blogs y a veces batallan para tenerlo organizado y saber que ya leyeron o si hay algo nuevo, etc, bueno un RSS Reader seguramente será su solución, excepto para mi blog ni algún otro de blogger, que no ofrecen el contenido en formato RSS. Esto es razón suficiente para cambiarme.....

Bueno ya una vez que bajen el software, les sugiero agreguen los siguientes links:
http://www.netfx3.com/blogs/MainFeed.aspx?GroupID=-1&Type=MirrorBlogsOnly Habla de .NET 3.0 (W*F)
http://martinfowler.com/bliki/bliki.rss Martin Fowlers bliki
http://blogs.msdn.com/rjacobs/rss.xml Ron Jacobs blog
http://team.intellekt.ws/blogs/chris/rss.aspx Blog de Chrisitan Strevel
http://www.intellectualhedonism.com/SyndicationService.asmx/GetRssCategory?categoryName=dnr El RSS de DotNetRocks Audio Show.
http://channel9.msdn.com/rss.aspx?ShowID=5&format=mp3 Los audios de Channel9 en XML/Mp3

Bueno tienen ahí buen contenido para rato.

martes, julio 11, 2006

ScrumForTeamSystem

A poco no estan padres las páginas que dicen algo así como, seccionamarilla.com o integradorestecnologicos.com o computers.com, páginas que dicen exáctamente lo que estás buscando.

Hay una que me gusta mucho roller.com.mx, es una tienda de patines y es de méxico, así que que mejor dirección de roller.com.mx, patines.com.mx hubiera sido buena, pero bueno saben la idea.

Siempre que me preguntan algo como, oye donde puedo ver los resultados del prep digo bromeando, entra a resultadosdelprep.com. No sería bueno que fueran las cosas tan sencillas con los nombres de dominio?

Bueno, ahora si quieren bajarse unos templates para VSTS y dejar de manejar esos procesos de MSF, que sólo Microsoft entiende, si les gustan las metodologías ágiles y sobre todo si programas en .NET, usas Team System y Scrum es el proceso de trabajo utilizado por tu equipo... bueno entra a scrumforteamsystem.com

Hasta ahorita he estado leyendo un poco de esto y de aquello, viendo templates, etc... despues de conocerlo más (uno dos meses probalemente) les escribire más al respecto, pero si no quieren esperar tanto, vayan bajenlo, instalen los templates, usenlo en un spritn (una iteración de Scrum) y me platican.

domingo, julio 09, 2006

Software Factories

Sin duda el concepto de fabricas de Software se está convirtiendo en el nuevo parádigma de Software y a muchos nos tocara pasar la transición entre OO y SF, no se como sea esto, pero ya me estoy imaginando que será un gran cambio en nuestra industria. No me toco vivir la transición anterior (estructurado/OO), pero aquellos con más experiencia seguramente la recordaran bien.

Aunque aún falta tiempo para que estemos trabajando completamente bajo este nuevo concepto
al día de hoy existen ya varias "Fabricas de Software", algunas de ellas como HL7 no son muy relevantes para nosotros, pero existen otras tres que seguramente serán de mayor interés popular y estás dependen del tipo de aplicaciones que esten desarrollando:
Web Services
Windows Forms
Mobile

La tendencia está en que cada vez se desarrollen Software Factories más específicas, buscando atacar diferentes nichos de negocio o mercados más vertícales o aplicaciones en lugar de pensar en algo tan genérico como Windows Forms, tal vez pensar en aplicaciones Bancarias o Médicas o aún más específico, para consumir y proveer Servicios en el área médica (tal como es el caso de HL7 SF).

Bueno aquellos que programan en ASP.NEt seguramente estaran interesados en saber porque no puse un link para estas, sin embargo aunque no está realmente lejos de ser un SF el proyecto de Atlas es algo muy prometedor que seguramente cambiara la manera en que hacemos aplicaciones Web. Para los que no programan en .NET, hay otras soluciones de Ajax para plataformas como J2ee y me imagino que habrá algo para PHP.

La razón por la cual microsoft le dio prioridad a los SFs de WS, Mobile y Windows es porque creen que ASP.NET estaba más completo, tenía más herramientas, mayor soporte y una arquitectura mejor definida que las de las otras tecnologías, lo cual es un tanto cierto, sin embargo, una vez que trabajamos con un SF, vemos que no caería nada mal tener algo similar para ASP.NET. Hasta donde se aún no hay planes oficiales de hacer algo, pero seguramente una vez terminado el proyecto de Atlas, pensaran en integrar todo como un Software Factory.

El potencial real de una Fabrica de Software, está cuando empezamos a utilizarla desde que comenzamos a definir la arquitectura base de nuestra aplicación de tal forma que podamos proveer una gran punto de partida y apoyos a los desarrolladores para que tengan claro como hacer las cosas. Ya no basta con naming conventions, con plantillas de documentos como ERS, etc, ahora se vuelve importante el tener definido que patrones de diseño y de arquitectura usar en cada caso y proveer la guía para como usarlos, proveer frameworks para fácilitar ciertas tareas y darles herramientas generadoras de código que puedan automatizar ciertas partes de la aplicación.

Más adelante publicare un glosario de términos de SF y les hablare en general de los principios que propone para despues podeer entrar más a detalle a hablar del Mobile SF

viernes, julio 07, 2006

Probar un WebService desde una maquina remota.

Encontre un post muy breve e interesante respecto a como hacer esto.

Cuando entras a un WebService de IIS o del WebServer de VS te aparecen campos para que puedas pasarle parametros a los WSs sencillos para invocarlos y probarlos directamente desde web. Bueno está funcionalidad está deshabilitada cuando necesitas hacer las pruebas de manera remota.

Para arreglarlo simplemente escribe los siguiente en el web.config dentro de system.web

<system.web>
    <webservices> 
        <protocols>   
            <add name="HttpPost">   
            <add name="HttpGet"> 
        </protocols>
    </webservices>
</SYSTEM.WEB>

jueves, julio 06, 2006

Anonymous Delegates

VS 2005 viene con 400 nuevas caracteristicas, según nos presume Microsoft. Esto es para el puro IDE, aparte de los cambios en la arquitectura del framework y sus nuevas clases

Bueno entre algunas de las mejores novedades hemos encontrado obviamente Team System, todo lo relacionado con pruebas, diagramas de clases, intellisense en la ventana del Watch del depurador, code snippets.

El framework trae un monton de novedades como generics, del que ya he escrito anteriormente (DataAccess), bueno el chiste es que aunque ya la conocíamos nunca nos había parecido util el usar delegados anónimos y hoy descubrimos lo simple y prácico que es no tener que hacer todo un metódo que estorba en tu código que contiene una línea sencilla y sólo se manda llamar desde un lugar.

Por ejemplo tenemos una lista de Threads que queremos poner a todos a correr y luego esperar a que todos terminen.

threads.ForEach(delegate(Thread thread) { thread.Start(); });
threads.ForEach(delegate(Thread thread) { thread.Join(); });

Wow!!!! antes hubieramos necesita crear dos metodos aparte nada más para hacer un thread.Start y un thread.Join para el predicate del foreach de la lista.

Bueno espero y les sea útil.

A nosotros nos hubiera ayudado mucho si se nos hubiera ocurrido usar esto para unos controles EditableGrids y EditableList que usamos para pocket pcs, que usan intensamente delegados y en la mayoría de los casos hacen cosas tan sencillas como asiganarle un valor a un textbox o realizar alguna validación sencilla.

miércoles, julio 05, 2006

Team System desde fuera de la oficina.

Es triste saber que Team System, aun y que esta basado en WebServices y supondríamos que se podría trabajar directamente desde Internet, este aún tiene problemas para hacerlo de manera optima, por lo que nuestra solución estos días fue el montar una VPN y conectarnos de está manera.


Esperamos en próximas versiones ya se pueda hacer la conección direccto por internet.

:`(

Al parecer esto es por los metodos de autentificacion que por default debe usar el IIS para trabajar con los WSs del TFS.

sábado, junio 10, 2006

MoProSoft

Ya oficialmente arrancamos la definción de procesos de MoProSoft, por lo que tendremos mucho trabajo sobre esto durante los próximos 10 meses.
Innevo nos va a estar ayudando con la consultoría y fácilitaran un poco las cosas.

Tuvimos una evaluación inicial y al parecer nos fue muy bien, algunas buenas prácticas que nos ayudaran a hacer más rápido todo y por otro lado Team System será de gran ayuda y esperamos poder automatizar los procesos de desarrollo desde está herramienta para que queden alineados a lo que definamos de MoProSoft.

De aquí en adelante bastantes de mis posts estarán relacionados con este tema. Espero poder abrir alguna categoría aparte para ir clasificando por temas.

Team System Source Control

Hay dos opciones muy buenas que trae el Source Control de Team System. Shelving y Branching, ya las habíamos visto. Ya habíamos tenido la necesidad de usar Branching, pero realmente no nos fue útil.
En un proyecto nos dimos cuenta de que estabamos por hacer grandes cambios, borrar muchos archivos de código, cambiar otros, así que decídimos usar Branching, para poder volver después al punto estable en caso de que nuestros cambios hecharan a perder lo que ya funcionaba.
Bueno en ese caso pudímos haber usado un label, del tal forma que si quisieramos regresabamos al punto anterior o podíamos usar ese para generar un entregable. Finalmente nunca necesitamos hacer un merge (ahorita les explico para que funciona).

Bueno lo útil del Branching es realmente el merging, el proceso es el siguiente y lo explico con un ejemplo, aunque pueden ver dibujitos en el link que les dejo.
Queremos probar diferentes ideas que nos permitiran mejorar el performance de una aplicación, todo está funcionando bien, es sólo el performance lo que queremos comprobar, por lo que necesitamos crear diferentes ramificación (branches) para hacer varias pruebas distintas, las que mejoren considerablemente el performance se integraran a la línea original y las que no, simplemente quedarán fuera y borraremos dicho branch. Así que la ventaja real de esto viene hasta el punto en que hacemos el merge.

Por otro lado, también nos permite usar las diferentes versiones de la aplicación para poder hacer comparaciones entre una y otra y medir cual es más rápida.

Espero nos de resultados y ojala y todas las ideas que traemos ahorita mejoren en algo el performance y finalmente integremos los cuatro branches a la línea original.

Otra ventaja que tienes es que mientras algunos de los desarrolladores tratamos de mejorar el performance, otros pueden seguir con otro tipo de cambios a los que después nos integraremos.


Bueno cambiando de tema, Shelving es otra opción, que aunque no la hemos utilizado, vemos que nos va a resultar útil. Hay muchas ocasiones en las que dos desarrolladores necesitan trabajar sobre una misma parte de código desde diferente computadoras y estar haciendo check ins rompería el build y afectaría al resto del grupo, sin embargo, ellos necesitan compartir ese código, esto resula útil también para alguna revisión de código o cuando el mismo desarrollador se cambia de una maquina a otra, así que en lugar de dar check in y luego get latest version, hacen un shelve y luego un unshelve, una vez que hacen el shelve ya no les apareceran los pending changes y una vez que hagan unshelve nuevamente tendráne esos archivos como pending changes.

Espero y esto le sea útil a alguien más y aprovechen las ventajas que nos da el uso de estás herramientas.

jueves, mayo 25, 2006

MiguelMadero.com

Estrenando nueva direccion para el blog: miguelmadero.com esta ya disponible.
Un pequeño capricho para mi ego por sólo $9.90 dlls anuales. Dije si Martin Fowler y Ron Jacobs tienen lo propio tal como muchos otros, dije, bueno y porque no? Aprovechar antes de que algún homónimo me lo ganara.

Así que mi sugerencia para ustedes, si todavía no hay jaimevelazquez.com tomenlo antes de que les paso lo que a christianperez.com

jueves, mayo 11, 2006

Atributos para Tiempo de Diseño para Dispositivos Móviles

Está es la breve historia de cómo batallamos por la siguiente línea de código:
smartPartPlaceHolder.SmartPart = null;
Sin duda el diseñador de VS es una herramienta súper útil, pero en más de una ocasión (deberás no exagero, pero ahora sólo recuerdo esta), suele hacer cosas extrañas. Muchas veces no es por culpa de VS sino de quien programa los controles, pero al parecer en este caso fue un poco más allá y todo resulto ser problema de un
known bug que será atendido en el SP1 que será liberado el tercer cuarto de este año. En este caso el diseñador escribía la línea anterior cada vez que modificábamos la vista desde VS, por lo que dejaba de funcionar ya que esa propiedad no debía ser null.
Empecemos por quien diseña los controles. Con los atributos en tiempo de diseño tienes realmente mucha flexibilidad, le puedes especificar a una propiedad su valor de default, si quieres que se muestra en la lista de IntelliSense (no veo porque querríamos deshabilitarlo, pero está disponible) y lo más importante (al menos en este caso), le podemos decir si alguna propiedad deberá ser manejada por el diseñador y si no es una propiedad muy simple (por ejemplo un objeto, una Colección de Columnas e.g. DataGrid.Colums) muy seguramente querremos un diseñador personalizado.
El único detalle es que en Mobile no podemos usarlo, o al menos no todos. El CF (compact framework) no los incluye y no lo podemos compilar usando alguna clase del framework normal, sin embargo, VS si podría tomar Assemblys de ambos.
La solución más obvia, aunque no tan sencilla, era la que teníamos en 2003,
compilar un dll similar para el tiempo de diseño. Realmente no era tan sencillo, se resume en seis pasos:
Crear un proyecto de C# de Class Library (no de CF, para escritorio).
Agregamos como links todos los archivos del proyecto de Controles.
Agregamos un atributo de compilación al proyecto creado en el paso 1.
Ponemos en condionantes de compilación los atributos
#If NETDESIGNTIM
[System.ComponentModel.Browsable(false)
#endif
public object SmartPart
{
///
}
Este es un punto clave y no tan sencillo, necesitas agregar el siguiente atributo al AssemblyInfo.cs
#if NETCFDESIGNTIME
[assembly: System.CF.Design.RuntimeAssembly("ElDllQueTieneTodoEnRuntime ")]
#endif
Lo agregamos al GAC para que VS pueda reverenciarlo.

El atributo en el paso 5 le dice que es lo que deberá de usar en tiempo de ejecución, sin embargo, este dll de C# es lo que agregamos a la barra de herramientas y es con el que trabajaremos en VS.

Ok, es medio sencillo como para haber batallado tanto.
Ahora el nuevo modelo es más prometedor (Debería ser así de sencillo como en
este ejemplo). Que es lo que necesitamos otro dll, pero ahora se generará automáticamente por genasm.exe usando los atributos que se especifiquen en el archivo XML. Aunque XML es muy sencillo, su poder reside cuando no lo tenemos que escribir nosotros, es ahí donde entran los diagramas de clases. Desde el diagrama de clases le especificamos los atributos a cada propiedad y este genera el archivo que después es compilado por genasm.exe. Ver el ejemplo para más detalle.
Ok, pareció aún más sencillo, pero no termina aquí, genasm.exe tiene un
know bug aunque nos dan una solución de cómo darle la vuelta mientras lo corrigen, realmente está muy lejos de ser lo que queríamos. El proyecto sobre el cual lo apliques no puede usar Generics, así que tienes que mover tus clases a otros proyectos, heredar de clases generics para hacerlas específicas y usar estás en lugar de las generics y listo (esto último puede ser lo más difícil), esa es la solución que nos da Microsoft.
En este caso no podíamos hacer eso ya que todo el proyecto dependía muchísimo de generics, lo que tuvimos que hacer fue crear otro nuevo proyecto que contuviera exclusivamente lo que requeríamos, remover los pocos generics que quedaron dentro de esa clase y luego simplemente compilar. El único lugar donde el SmartPartPlaceHolder usaba generics era en el EventHandler<>, así que tuvimos que crear el delegado específico y usar ese en lugar del EventHandler genérico.
public delegate void SmartPartShownEventHandler(object o, SmartPartPlaceHolderEventArgs e);
public event SmartPartShownEventHandler SmartPartShown;
en lugar de
public event EventHandler SmartPartShown;
Hablo más sobre generics en
otro post.
Ok, ok, no queríamos tener otra clase con el mismo nombre (SmartPartPlaceHolder) que estuviera en otro nombre y luego cambiarla cuando corrigieran el problema, esto era precisamente lo que
sugería microsoft, aparte todos los EventHandlers tendrían que cambiar. Encontramos una maña:
Simplemente renombramos el dll generado:
Microsoft.Practices.Mobile.CompositeUI.WinForms.SmartPartPlaceHolder.PocketPC.asmmeta.dll
a:
Microsoft.Practices.Mobile.CompositeUI.WinForms.PocketPC.asmmeta.dll
Y copiamos esto al mismo folder donde se encuentra Microsoft.Practices.Mobile.CompositeUI.WinForms.dll
Para hacer automático todo agregamos el siguiente PostBuildEvent
copy /Y /B /V SmartPartPlaceHolder.PocketPC.asmmeta.dll

..\Microsoft.Practices.Mobile.CompositeUI.WinForms.PocketPC.asmmeta.dll

Fue todo, muy simple al final, pero batallamos mientras lo encontramos al igual que más gente que ha tenido el
mismo problema.

miércoles, mayo 10, 2006

Ineta Latam

Es para mí un honor que hayan publicado mi blog en la sección de “Nuestros Blogs” del Ineta Latam junto a otros blogs muy interesantes como el de Vicente y Enrique respecto a DSL Tools. No he tenido mucha oportunidad de revisar los demás blogs, pero les sugiero revisen la lista, está puede ser un muy buen punto de partida para encontrar información interesante en su idioma.

Para los que no sepan que es la Ineta, la describo, como siempre hago con todo, brevemente, ya que pueden ver “¿Que es Ineta?”. Es un grupo de grupos, bueno una asociación de comunidades .NET. Seguramente encontraran algún grupo cerca de ustedes. A propósito del tema de comunidades .NET, les comento que estamos por iniciar la comunidad en Torreón, espero tengamos buenos resultados.

Ya tocando el tema de comunidades y blogs, les paso el link del de un buen amigo Christian Strevel.

lunes, mayo 01, 2006

public abstract class DataAccess


Los Genercis son una funcionalidad nueva de .NET 2005 y por ahí trae algo similar Java en su nueva versión (no sé si ya lo hayan liberado).

Para los que han programado en C++ es algo similar a las clases parametrizadas o las TemplateCollections, no recuerdo bien como llamaban, pero seguramente recuerdan algo como:

List<Albums> list = new List<Albums>(); // Tipico de ejemplos en C++

Bueno en C# es muy similar la sintaxis y ahora estamos explotando mucho eso.

Cuando alguien piensa en generics, se le viene a la mente Collecciones.

Antes haríamos algo como:

AlbumCollection : ICollection

{

// Aquí teníamos un montón de métodos para implementar ICollection (bueno no son tantos), pero era puro código repetitivo.

}

Lo enfadoso de esto es que seguramente íbamos a necesitar más de una colección con tipo, probablemente más de 10 o 30 y no sólo para nuestros BusinessEntities. Este tipo de colecciones aún se usan y pueden verlo cuando escriban datagrid1.Rows. Ahora podríamos simplemente decir.

List<Album> list = new List<Album>();

Mmm se parece a C++?

Ok, ok, las colecciones son la parte sencilla seguramente quieren ver algo más interesante. Bueno el nuevo generis EventHandler es un buen ejemplo. Para los que han tenido que crear eventos específicos y para poder cumplir con los guidelines de Microsoft, necesitamos algo como:

public class prueba

{

Prueba()

{

// Do something cool

}

public event DelegadoEspecifico evento;

}

Por lo que necesitaban crear un delegado específico:

public delegate void DelegadoEspecifico(object o, AlgoHeredandoDeEventArgs e);

Y necesitaban tener su clase AlgoHeredandoDeEventArgs

public class AlgoHeredandoDeEventArgs : EventArgs

{

AlgoHeredandoDeEventArgs(string x, string y)

{

// Do something cooler

}

// Write some useful properties here.

}

Ok, ok, es algo sencillo, pero se puede hacer más simple sin la necesidad de tener un montón de delegados.

Digamos que necesitas otro evento, pero que ahora reciba otros EventArgs distintos, porque, porque es lo único que cambia, así que ahora es:

public event DelegadoEspecifico2 evento;

y crear otra clase public class AlgoHeredandoDeEventArgs : EventArgs {}

Bueno luego usarla: public event DelegadoEspecifico2 evento2;

Bueno los genéricos nos permiten crear delegados específicos:

public event EventHandler<AlgoHeredandoDeEventArgs> evento;

public event EventHandler<AlgoHeredandoDeEventArgs2> evento;

Realmente lo único que nos ahorramos es la declaración de los delegados, pero ya es algo.

No es el único uso. Object Builder utiliza una de las formas más interesantes de aplicar Generics. Es muy complejo para describirlo aquí, pero la parte simple la pueden ver en Enterprise Library and Object Builder.

Recientemente hemos trabajando en un DataAccessLayer/DataMappingLayer (ver Table Data GateWay y Fowler’s EAA patterns) para Windows Mobile 5.0 y el uso de generics combinado con la herencia y polimorfismo fácilitaron enormemente las cosas. De manera resumida está es la arquitectura:

(Ver diagrama).

Tenemos nuestra clase base (abstracta) DataAccess, que implemente la interfaz principal IDataAccess (en caso de que necesitemos cambiar la implementación, por ejemplo para usar otra base de datos)

Todo se vuelve bastante sencillo con Generics. Usando template methods podemos ir encapsulando la funcionalidad genérica en las tablas de más arriba en la cadena de herencia, por ejemplo DataAccess es el único lugar donde se construyen los querys para la base de datos y se ejecutan los Comandos, etc. Aparte como lo tenemos todo bien encapsulado podemos destinar más tiempo a optimizar esa parte y hacerlo muy bien una sola vez. Realmente nadie quiere escribir el mismo código muchas veces (Abrir conección, execute reader, etc). Como en este caso muchas de las tablas usan Clave y descripción del mismo tipo, tenemos una segunda Clase Abstracta que se encarga de establer dichos valores y delegar el trabajo a un nuevo Template Method (el Donet en las clases concretas). De está forma cada DataAccess como VendedoresDataAccess y Lineas DataAccess son las únicas que conocen el nombre u orden de las columnas en la base de datos y saben como establecer las propiedades al Business Entitie que queremos crear.

Claro, está sólo una forma muy simple de hacer el Mapeo de Relacional a Objetos. Es algo similar a como lo explica Martin Fowler en su libro Patterns of Enterprise Applications Architecture la diferencia es que en la implementación de Fowler los metodos regresaban clases Padres, por ejemplo una clase del tipo DomainObject en lugar de una clase del tipo Persona.

Este es el código de Fowler (Java):

Class AbstractMapper{

Protected DomainObject GetDomainObject(ResultSet rs, long id){

// Do common stuff

DomainObject result = doLoad(id,rs);

// Do some other common stuff

return result;

}

}

abstract protected DomainObject doLoad(Long id, ResultSet rs);

class PersonMapper:AbstractMapper

{

protected DomainObject doLoad(Long id, ResultSet rs){

String lastNameArg = rs.getString(2);

// get other properties

return new Person(id,lastNameArg,etc);

}

}

Los usuarios de esas clases tendrán que hacer algo como:

Person p = (Person)personMapper.GetDomainObject(1);

Los dos graves problemas son:

  1. Corremos el riesgo de equivocarnos de tipo de objeto y detectarlo hasta el tiempo de ejecución en lugar de en tiempo de compilación.
  2. Es ineficiente estar haciendo tanto boxing (cuando regreso el objeto person como DomainObject) y unboxing (cuando hacemos el cast de DomainObject a Person).

Aparte algún error en el tipo de datos podría venir desde PersonMapper no sólo por el cliente.

En código (C#) y usando generics se puede hacer algo como lo siguiente:

Class AbstractMapper<TBO>

where TBO: DomainObject,new()

{

Protected TBO GetDomainObject(ResultSet rs, long id){

// Do common stuff

TBO result = doLoad(id,rs);

// Do some other common stuff

return result;

}

abstract protected TBO doLoad(Long id, ResultSet rs);

}

class PersonMapper: AbstractMapper<Person>

protected Person doLoad(Long id, ResultSet rs){

String lastNameArg = rs.getString(2);

// get other properties

return new Person(id,lastNameArg,etc);

}

Y ahora los clientes pueden usarlo de la siguiente forma:

Person p = personMapper.GetDomainObject(1);

No es necesario el cast ni el boxing, ya que siempre la clase AbstracMapper estará trabajando con el tipo de Objecto concreto en lugar de con DomainObject. Por otro lado el template method de PersonMapper (doLoad) para implementar la clase abstracta necesita forzosamente regresar un objeto del tipo Person.

Algo similar aplica también con Interfaces e inclusive es mucho muy útil ya que podemos tener ciertas Interfaces Genéricas y después implementarlas desde Interfaces específicas y obligar a las clases que deseen implementar a estás últimas a que cumplan con todos los metodos.

interface IGenericMapper<TBO>{

TBO Get();

}

interface IPersonMapper:IGenericMapper<Person>{}

public class PersonMapper:IPersonMapper{

// Must implement:

Person Get(){

// Do something

}

}

Claro que ahora como parte del framework que tenemos, ya está funcionalidad quedará en el DataAccessGenérico y será suficiente con que PersonMapper tenga lo siguiente:

public class PersonMapper:DataAcccess<Person>,IPersonMapper{

// Person Get() //Ya está implementada para la clase abstracta DataAccess.

// Ahora solo debemos implementer el metodo abstracto

protected Person DoFill(Person p, reader r)

{

p.Name = r[“Name”].ToString();

return p;

}

}

Pudiera parecer medio inutil el tener la interfaz IPersonMapper, pero es que en está queremos ahora dar de alta ciertos métodos específicos como GetByName, GetByLastName(string lastName), etc.

jueves, abril 27, 2006

CAB - Composite Application Block

Como explicar CAB?

La verdad es que es un tema difícil, mejor les voy a decir para que sirve y en algún otro momento posteare algo respecto al funcionamiento interno de este y el object builder.

De manera resumida, CAB sirve para poder crear vistas y workitems. Que son vistas? bueno pueden ser Formas o UserControls y que son WorkItems, viene siendo un caso de uso, como agregar cliente o generar pedido.

¿Que hacemos con estas vistas y WorkItems?
Simple, metemos presenters y/o controllers (dependiendo del patron que queramos usar) para interactuar con ellas. El workitem puede tener muchos presenters, quienes a su vez tienen una vista que muestran.

Otra ventaja de tener los WorkItems es que podemos ir agregando servicios a estos, de tal forma que podamo usar estos objetos (servicios) desde otros objetos contenidos en el workitem como presenters, vistas, otros servicios o ítems.

Una de las ventajas principales y probablemente CAB no estaría completo sin una forma sencilla de implementar patrones como Publisher/Subscriber y Commad, para desacoplar los eventos de sus EventHandlers. Si suena complicado? bueno está parte creo que es la más sencilla, simplemente se usan atributos y uris para ligar un evento con otro.

Espero haberlos confundido un poco más de lo que ya estaban. La verdad es que CAB es bastante confuso al principio.

Para hacerlos aún más bolas, les dejo un pequeño glosario que hice cuando estaba enredado entre tanto termino nuevo.

Glosario
WorkItem: Use Case. Tiene uno o más workspaces. Es un contenedor de componentes como controles, smartparts, services and child workitems.

SmartParts: Views

Services: Model (Data o Servicios). Los servicios se pueden agregar desde configuración (aún no disponible en mobile), programáticamente con un Add(); o declarativamente con el uso de atributos, se puede usar LazyLoading: [Service(typeof(IMyService), AddOnDemand=true)]

UIExtensionSite: sirve para registrar menús comunes.

RootWorkItem.UIExtensionSites.RegisterSite("MainMenu", Shell.MainMenuStrip);

Commands: Eventos.

Event Broker: se encarga de ligar un Event Subscription con el EventPublication correspondiente de acuerdo al URI indicado en el atributo.

Workspaces: lugares a los cuales puedo agregar SmartParts, por ejemplo un
SmartPartPlaceHolder, TabbedWorkSpace, ZoneWorkspace o DeckWorkspace.

Shell: el shell es el punto de entrada de la aplicación. Simplemente se hereda de FormShellApplication y en el Main se manda llamar el metodo Run de una instancia de tu clase que herede de FormShellApplication.

Module: es una forma de encapsular ciertas partes de una aplicación (diferentes WorkItems), por ejemplo OrdersModule. Estos se pueden cargar en tiempo de ejecución dependiendo de los parámetros de configuración. Para esto se usa un archivo "ProfileCatalog.xml" donde se indica que dlls cargar.



Por cierto, espero publicar dentro de poco un glosario de Software Factories, porque muy seguramente muchos posts de aquí en adelante hablaran de viewpoints, esquemas, líneas de producto, familias, assets, dsl, etc.