jueves, 21 de octubre de 2010

Cuidado! Un copo de nieve

Así como un simple copo de nieve puede convertirse en una bola de nieve incontrolable, a menudo en los sistemas ocurren situaciones similares.

Algo aparentemente tan inofensivo como no cambiar a tiempo el nombre de una tabla/campo de la base de datos o no renombrar una clase o método de la aplicación para que sea más representativo y coherente, puede originar una serie de pequeños inconvenientes y confusiones hasta convertirse en poco tiempo en un problema grave de mantenimiento.

Muchas veces me he encontrado con pequeñas y medianas empresas y organismos públicos que vienen trabajando con una o más soluciones de software desde hace varios años y han llegado a un punto donde el mantenimiento se ha vuelto tan costoso que dan ganas de tirar todo y empezar de nuevo, lo cual generalmente es inaceptable (aunque muchas veces no quedan muchas alternativas).

En estos sistemas, tareas habituales como solucionar un bug, agregar una nueva feature o una simple mejora pueden volverse tan complejas que muchas veces se prefiere no hacerlas o (lo que es peor) tratar de resolverlas con alguna artimaña rebuscada, con algún truco o parche. Lo que redunda una vez más en una mayor complejidad aumentando los costos de mantenimiento del sistema.

Todo es difícil

En estos sistemas todo se ha vuelto difícil.

La estimación de tareas es difícil. Una tarea que debería ser simple y fácil, se convierte en compleja y difícil y lleva mucho más tiempo del estimado.

No hay tiempo para análisis. Se necesita tiempo para analizar el impacto de agregar o cambiar cierta funcionalidad, pero no hay mucho tiempo porque estamos atrasados. Entonces, programemos y listo.

La programación diaria es frustrante. Lidiar todos los días con código difícil de leer, seguir y depurar se convierte en una tarea frustrante.

No hay tiempo para testing. Apenas alcanza el tiempo para desarrollar. Con suerte, el desarrollador alcanza a realizar un testeo superficial, una prueba de humo (Smoke Test) y el producto está listo para producción (Menos mal que no fabricamos autos o aviones).

La reutilización de componentes es un chiste. La complejidad de todo el sistema hace muy difícil crear funciones o componentes reutilizables. Recordemos que tampoco hay mucho tiempo para analizar. Como resultado se crean piezas de software muy similares una y otra vez, extendiendo los tiempos de desarrollo y aumentando aún más la complejidad.

La incorporación de nuevos desarrolladores es costosa. La productividad de los nuevos desarrolladores es muy reducida durante un largo tiempo, pues necesitan mucho más tiempo para entender el código pre-existente y poder hacer algo útil. Un desarrollador Senior se convierte en Junior. Y un desarrollador Junior cambia su color de pelo y religión.

Un salvador por aquí

En medio de todo el caos, aparece el desarrollador imprescindible. El más experimentado de los desarrolladores suele convertirse en el salvador de la empresa o del producto. Es el único capaz de entender la solución actual. Él sabe que se puede “tocar” y que no, cuándo tocar y cuando no. Él entiende el porqué de las cosas (no siempre). Sin saberlo, esto le genera una alta presión y exigencia, que se transforma en Stress y cuando Él se enferma, la empresa se “enferma”. Si Él se va de vacaciones, la empresa se “sufre”. Y si Él renuncia, la empresa empieza a “agonizar”. Esta situación es muy perjudicial para una empresa.

¿Cómo se llega a esta situación?

Como lo decía Pablo en la TV: “Una seguidilla de hechos bochornosos”. Generalmente, el problema principal suele ser una carencia total de arquitectura empresarial. Por diferentes motivos se ha subestimado el valor de construir sistemas basados en una arquitectura sólida. A esto se le suma una serie interminable de vicios: desde el simple desconocimiento de mejores prácticas de programación, al código heredado de diferentes programadores o equipos de programación, y también se puede sumar tecnologías y lenguajes de programación obsoletos.

Incluso una arquitectura sobredimensionada o exceso de patrones de arquitectura (patronitis aguda) pueden terminar con una solución inmanejable. Aunque esta última “enfermedad” no es muy común, lo más habitual es encontrar “antipatronitis crónica”.

¿Qué se puede hacer?

Cuando se llega a esta situación, el costo de intentar arreglar la solución actual puede ser más costosa que empezar de nuevo. Y cuando la tecnología en la cual está basada el sistema ha quedado obsoleta, ya no tiene mucho sentido arreglarlo.

Asumiendo que la tecnología del sistema no es obsoleta, hay que analizar cada caso en forma particular para determinar si todavía existen chances de cambiar la situación actual (cuando no se trata de una situación irreversible).

Alguien podrá decir: “Los sistemas siempre se pueden corregir”. Si, es verdad, el punto es que en ciertas situaciones el costo de “corregir” puede superar ampliamente el valor del sistema. En estos casos se opta por seguir lidiando con los problemas o empezar de nuevo.

¿Se puede evitar esta situación?

Absolutamente. Solo es cuestión de tener algunas cosas básicas:

  1. Un equipo de trabajo
  2. Una metodología de trabajo
  3. Una arquitectura de software clara y consistente.
  4. Un diseño de base de datos coherente
  5. Mejores prácticas de desarrollo

Pero por sobre todas las cosas hay una que quizás es la más importante: Ganas de mejorar desde el primer día. Esto no incluye solo al equipo de sistemas, sino a toda la empresa.

Saludos, Gus

Todo el problema no está en la programación

Trabajando en muchos proyectos para organismos privados y públicos he visto una y otra vez cómo los sistemas llegan a un punto extremo donde los problemas abundan y las soluciones escasean.

Desafortunadamente, muchos piensan que el problema de los sistemas inestables y costosos de mantener es solo un tema de programación.

La realidad es que el problema casi siempre viene originado por una mala arquitectura, malas prácticas de programación y malos diseños de bases de datos.

Enfocándome en el diseño de bases de datos, un mal diseño complejiza enormemente todo el sistema. No soy experto en bases de datos, pero como desarrollador de sistemas empresariales, el diseño de bases de datos relacionales debe ser un conocimiento básico y fundamental.

Me sorprende encontrar continuamente bases de datos con graves problemas de normalización, graves problemas de inconsistencia de datos, nombres de tablas y columnas incomprensibles o totalmente confusas, etc. Ni hablar del mal uso de los tipos de datos o la ausencia de los índices mínimos para acelerar las principales búsquedas. Posiblemente tampoco exista un plan de backup y mucho menos un plan de restauración testeado. ¿Y la seguridad? Nosé, hay un guardia en la entrada del edificio.

Una situación común es que se crea una tabla o campo con cierto nombre, luego se utiliza en diferentes partes del código. Pasa el tiempo y se le agregan nuevos campos para cubrir nuevos requerimientos. Tiempo después, el equipo se da cuenta que el nombre ya no es representativo. La tabla que se llamaba Ventas, ahora también almacena las Compras, y se prevé que posiblemente también almacene otros comprobantes como Remitos, Notas de crédito, etc.

Un nombre más representativo debería ser Comprobantes, incluyendo un campo discriminador que determine el Tipo de comprobante. Pero el equipo se resiste a cambiar de nombre o crear una nueva tabla, argumentando que también debería actualizar el código de la aplicación, las vistas y los procedimientos almacenados  dependientes, y eso es una tarea muy compleja.

Es cierto, es una tarea compleja. Es un cambio que puede “romper” muchas cosas. Pero es un cambio importante para mantener la salud del sistema. Si no lo hacemos, estamos ampliando los problemas futuros de mantenimiento. Empezamos a complicar las cosas. Creamos la primer bola de nieve que irá creciendo.

Alguien preguntará:

“¿Qué hago con los sistemas externos que dependen de esa base de datos?”

En primer lugar no debería tener sistemas externos que dependen directamente del esquema de la base de datos. ¿Donde quedaron los web services y la interoperabilidad? Si este es el caso, quizás las vistas o sinónimos de bases de datos puedan ayudar a disminuir el alto acoplamiento.

Conclusión:

Se necesita coraje y una visión de sistema saludable a largo plazo para saber que ciertos cambios son posibles y necesarios en el momento oportuno y si no se atienden, se convierten en una enfermedad que nosotros mismos creamos.

También hay que saber que existe mucha bibliografía, documentación, blogs y varias herramientas para refactoring de bases de datos. Es cuestión de conocerlas y saber usarlas cuando se necesitan.

Incluyo aquí algunos links interesantes sobre refactoring y deployment de bases de datos:

En futuros posts intentaré dedicar tiempo a los proyectos de bases de datos para Visual Studio.

Saludos, Gus.

lunes, 18 de octubre de 2010

Microsoft Sync Framework: 'min_active_rowversion' no es un nombre de función integrada reconocido

Me he encontrado con este mensaje de error al intentar sincronizar 2 bases de datos: SQL Server 2005 y SQL Server 2005 Express en una virtual PC con Windows XP.

Al buscar un poco en la red, encuentro que la función min_active_rowversion está disponible con el Service Pack 2 de SQL Server 2005.

Inmediatamente verifico si lo tengo instalado ejecutando el comando:

select @@version

Microsoft SQL Server 2005 - 9.00.1399.06 (Intel X86)   Oct 14 2005 00:33:37   Copyright (c) 1988-2005 Microsoft Corporation  Standard Edition on Windows NT 5.1 (Build 2600: Service Pack 3)

Una rápida lectura permite ver que tengo instalado el Service Pack 3. Entonces intento ejecutar el comando:

select min_active_rowversion()

y obtengo el mismo mensaje de error inicial.

Vuelvo a buscar en la documentacion oficial, los foros, blogs, etc. y encuentro una y otra vez que tal función está disponible con el SP2 de SQL Server 2005.

Empiezo a pensar que el SP3 que tengo instalado no incluye al SP2, lo cual me parece raro porque el SP3 es generalmente acumulativo. Empiezo a generar diferentes especulaciones y dudas, sigo buscando en la red, hasta que se me ocurre volver a leer el mensaje de select @@version:

Microsoft SQL Server 2005 - 9.00.1399.06 (Intel X86)   Oct 14 2005 00:33:37   Copyright (c) 1988-2005 Microsoft Corporation  Standard Edition on Windows NT 5.1 (Build 2600: Service Pack 3)

Bingo! El service pack 3 que tengo instalado no es de SQL Server sino de Windows XP.

Así que decido descargar e instalar el SP3 de SQLServer 2005 y también el SP3 de SQL Server 2005 Express.

Después de instalar el SP3 (tarda un rato) vuelvo a ejecutar el comando select @@version obtengo el siguiente mensaje:

Microsoft SQL Server 2005 - 9.00.4035.00 (Intel X86)   Nov 24 2008 13:01:59   Copyright (c) 1988-2005 Microsoft Corporation  Standard Edition on Windows NT 5.1 (Build 2600: Service Pack 3)

Ahora veo que tengo una versión mayor y el comando select min_active_rowversion() ya no muestra un error.

Finalmente, pruebo mi aplicación de sincronización y todo funciona correctamente. Los registros de base de datos se sincronizan sin problemas.

Conclusión:

Yo debo leer mas detenidamente los mensajes. Pero el equipo de SQL Server podría reconocer que es un poco confuso agregar el service pack instalado de Windows al consultar la versión de SQL Server.

Espero que sirva.
~Gus

Próximamente: IIS Express

Nuevamente Scott Guthrie nos comenta en su blog sobre esta novedad interesante para los desarrolladores de ASP.NET que proximamente estará disponible en forma gratuita.

Pueden ver el post original o su traducción al español por Juan María Ramos.

Enjoy it!
~Gus

viernes, 15 de octubre de 2010

SQL Server CE embebido en ASP.NET

Estas últimas semanas estoy bastante atareado aprendiendo y creando soluciones con VSTO (Visual Studio Tools for Office). Ya tengo agendado media docena de posts sobre este tema para compartir.

Pero ahora quiero compartir otra novedad que me parece muy interesante y útil para muchos.  Hace pocas semanas Scott Guthrie anunciaba que proximamente estará disponible una beta de SQL Server CE 4 (Compact Edition).

Pueden leer el post original de Scott o la traducción al español del bueno de Julian Ramos.

Actualmente pueden descargar el CTP 1 (Community Technology Preview) de SQL CE 4 desde el siguiente link: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=0d2357ea-324f-46fd-88fc-7364c80e4fdb&displaylang=en

Con SQL CE 4 podremos disponer de un motor de base de datos liviano en nuestros sitios web que no requiere la instalación ni configuración de ningún servidor de base de datos.

Solo hay que copiar los ensamblados de SQL CE 4 en nuestro directorio /bin y ya tenemos un motor de base de datos disponible en nuestra aplicación. Sin permisos especiales, sin cuentas administrativas, sin instalación, sin configuración. SQL CE 4 creará archivos de datos con extensión sdf que podemos alojarlos en nuestra carpeta /App_Data.

Una buena noticia es que este motor de SQL CE 4 será compatible con nuestras tecnologías de Acceso a datos como ADO.NET u ORMs como Entity Framework o NHibernate. Adicionalente, podremos escalar nuestra base de datos a motores más avanzados como SQL Express, SQL Server o SQL Azure simplemente cambiando nuestra cadena de conexión.

Un punto a saber es que esta versión de SQL CE no soportará procedimientos almacenados, un feature bastante común en muchos desarrollos, pero muy prescindible para quienes trabajan con ORMs.

Bueno, espero que sirva.
Saludos, Gus

viernes, 3 de septiembre de 2010

La familia crece: Nuevo Visual Studio LightSwitch

Dicen que con esta nueva tool podremos crear rápidamente aplicaciones de negocio de calidad profesional sin tener que escribir mucho código. Podremos crear aplicaciones de escritorio o en la nube en muy poco tiempo. Podemos elegir C# o VB.NET, SQL Server, SQL Azure o SharePoint. También podemos crear aplicaciones SilverLight dentro o fuera del browser y exportar datos a Excel programando casi nada. Y cuando la aplicación crezca podemos personalizarla en Visual Studio Profesional o Standard o el que sea.

Estas cosas ya las escuché muchas veces, pero no dejan de llamar la atención. Hay que probarlo: http://www.microsoft.com/visualstudio/en-us/lightswitch 

Mas adelante les cuento mi experiencia.

Nos vemos!
~Gus

martes, 15 de diciembre de 2009

¿Cómo manejar el ciclo de vida del DataContext/ObjectContext en ASP.NET?

Si estás trabajando en ASP.NET y LINQ2SQL o ADO.NET EF, te habrás preguntado cual es la mejor estrategia o solución para manejar el DataContext o el ObjectContext. Intentaré responder esta pregunta planteando varias alternativas que he conocido, pero verás que cada una tiene sus ventajas y desventajas, y la elección dependerá del escenario donde necesites aplicarlo.

Por cuestiones de simplicidad, a continuación hago referencia al ObjectContext de ADO.NET EF, pero la problemática es la misma con el DataContext de LINQ to SQL.

1. Un contexto por Session

A más de uno se le habrá ocurrido implementar alguna especie de Singleton y almacenar el ObjectContext en el objeto Session de ASP.NET.

Ventajas

  • Existe un único contexto para toda la sesión del usuario
  • Todas las operaciones se realizan usando ese único contexto por usuario.
  • No deberían aparecer los problemas de que no se puede actualizar una entidad porque está asociada a otro contexto.

Desventajas

  • Las opciones como ObjectTrackingEnabled o DeferredLoadingEnabled se aplicarían para todas las operaciones.
  • El contexto puede crecer mucho y afectar la escalabilidad de la aplicación.

2. Un contexto por Request

La idea aquí es similar a la anterior, pero en lugar de almacenar el contexto en el objeto Session, lo guardamos en la colección HttpContext.Items. Esta colección se crea para cada Request y solo existe durante la ejecución de la solicitud.

Ventajas

  • El contexto solo vive durante el hilo de ejecución de cada Request.
  • Las operaciones de diferentes clases de acceso a datos pueden compartir el mismo contexto.
  • La escalabilidad de la aplicación no debería verse afectada, pues el contexto se destruye al finalizar el Request.

Desventajas

  • Las opciones como ObjectTrackingEnabled o DeferredLoadingEnabled siguen afectando a todas las operaciones.
  • Existe una sobrecarga de crear el contexto con cada Request. Aunque esa sobrecarga suele ser despreciable.

 

3. Un contexto por instancia de acceso a datos

En lugar de guardar el contexto en la sesión o en el Thread del Request, lo creamos al instanciar la clase de acceso a datos. Por ejemplo, en el método constructor de la clase.

Ventajas

  • El contexto tiene el mismo ciclo de vida que la clase de acceso datos.
  • Las operaciones de la misma clase de acceso a datos pueden compartir el contexto.
  • La escalabilidad de la aplicación no debería verse afectada, el contexto se destruye cuando se destruye la clase.

Desventajas

  • Las opciones como ObjectTrackingEnabled o DeferredLoadingEnabled siguen afectando a todas las operaciones en la misma clase.
  • Otras clases de acceso a datos no pueden compartir el mismo contexto.
  • Existe una sobrecarga de crear el contexto con cada instancia. Esta sobrecarga puede afectar la performance si muchas instancias de acceso a datos se crean con cada request.

4. Un contexto por operación de acceso a datos

Esta sería la forma más atómica de manejar el contexto. Cada operación de acceso a datos crea el contexto, lo usa y lo libera.

Ventajas

  • El contexto tiene un ciclo de vida mínimo.
  • La escalabilidad de la aplicación no debería verse afectada, el contexto se destruye cuando finaliza el método.
  • Las opciones como ObjectTrackingEnabled o DeferredLoadingEnabled solo afectan a todas las operaciones encerradas por el método.

Desventajas

  • Otros métodos o clases de acceso a datos no pueden compartir el mismo contexto.

Estoy seguro que podemos encontrar otras alternativas o variantes. Aunque no he encontrado ninguna 100% beneficiosa.

De todas las variantes enumeradas aquí, en mis proyectos suelo utilizar la variante 2 (Un contexto por request) o la 3 (Un contexto por instancia de acceso a datos). Y hasta el momento no he tenido problemas significativos.

Si tienes una estrategia mejor o más recomendable para manejar el contexto de datos de LINQ2SQL o ADO.NET EF, no dudes en compartirla.

En un futuro post, intentaré poner algunos ejemplos de código sobre cómo gestiono el contexto de datos en mis proyectos.

Espero que sirva.
Saludos, Gus

miércoles, 23 de septiembre de 2009

Mejores enlaces en ASP.NET

Durante mucho tiempo a la hora de incluir un enlace en mis aplicaciones ASP.NET simplemente utilizaba un control Hyperlink y en su propiedad NavigateUrl escribía la dirección URL. Por ejemplo:

<asp:Hyperlink ID=”ContactLink” runat=”server” NavigateUrl=”~/contact.aspx” Text=”Contacto” />

Este enlace se crea en el navegador como un elemento HTML anchor similar al siguiente:

<a id="ctl00_MainContainer_ContactLink" href="../contact.aspx">Contacto</a>

Este enlace no está tan mal, pero su atributo id es un poco extraño y en este caso particular, como se trata da una URL estática, es innecesario; en consecuencia podríamos evitarlo en pos de lograr un HTML más limpio.

Alguien podría decir: ¿por qué no podemos usar simplemente un elemento HTML anchor en lugar de un control Hyperlink?. Bien, un simple anchor podría estar bien en muchas situaciones:

<a href="/contact.aspx">Contacto</a>

Este enlace funcionaría bien en muchos sitios web, pero trae algunos problemas con los subdominios o subcarpetas. Por ejemplo: si nuestra aplicación ASP.NET está alojada en www.example.com/miapp, el enlace anterior apuntaría incorrectamente a www.example.com/contact.aspx en lugar de www.example.com/miapp/contact.aspx. Es por ello que preferimos usar Hyperlinks y usar el carácter de tilde “~” que nos asegura una URL correcta desde la raíz de nuestra aplicación.

Desafortunadamente no podemos usar la tilde “~” con un simple elemento HTML, pues la tilde se procesa y resuelve en el lado servidor. Un enlace como el siguiente no funcionaría:

<a href="~/contact.aspx">Contacto</a>

Escribiendo enlaces correctos y limpios

Una alternativa para resolver el problema usando el elemento anchor, es usar el método ResolveUrl de la siguiente forma:

<a href=’<%= ResolveUrl(“~/contact.aspx”)’ %>Contacto</a>

Este tipo de enlaces dá como resultado un HTML anchor sin el atributo ID, y funciona correctamente en cualquier sitio con subdominios y es independiente de la estructura de carpetas de nuestro sitio.  El enlace siempre será correcto!. En el navegador se vería como:

<a href="../contact.aspx">Contacto</a>

Mejorando la escritura de los enlaces

Durante un buen tiempo empecé a escribir este tipo de enlaces, pero luego no me sentí muy conforme con la forma de hacerlo. No me parecía muy natural. Otras personas que están aprendiendo ASP.NET les suena complicado o confuso.

Entonces encontré otra forma de lograr el mismo resultado (HTML más limpio y claro), pero de una forma más intuitiva y elegante. El truco consiste en agregar el atributo runat=”server” al elemento HTML anchor y entonces podemos usar el caracter de tilde “~” en el href.

<a href="~/contact.aspx" runat=”server”>Contacto</a>

Esto dá como resultado un enlace HTML limpio y correcto:

<a href="../contact.aspx">Contacto</a>

La buena noticia es que esto podemos aplicarlo también con las imágenes e incluso con los elementos <link> que usamos para referenciar archivos CSS o Javascript en el <head> de nuestras páginas.

Espero les sirva!
Saludos, Gus

 

UPDATE:

Es una costumbre en ASP.NET que al usar controles de servidor proporcionemos un atributo ID al control. Sin embargo, no es obligatorio. Podríamos declarar controles de servidor SIN el atributo ID, como el siguiente:

<asp.HyperLink runat=”server” NavigateUrl=”~/contact.aspx” Text=”Contacto” />

Esto genera en el lado cliente un elemento anchor limpio sin el atributo ID:

<a href="../contact.aspx">Contacto</a>

jueves, 30 de abril de 2009

Microsoft Web Platform Installer

Desde principios de año ya está disponible la versión 1.0 y desde mediados de Marzo la versión 2.0 beta de esta excelente y práctica plataforma que simplifica la descarga e instalación de todo el software que necesitamos en nuestro entorno de desarrollo, pruebas y producción.

image

En esta tool podemos encontrar:

image .NET Framework
Instala la última versión del .NET Framework. Esto incluye todo lo que necesitas para trabajar con ASP.NET
image IIS y Extensiones
Instala la última versión de IIS, incluyendo las últimas extensiones de IIS como el IIS Media Services.
image

SQL Server
Instala la última versión de SQL Server 2008 Express. Incluye tanto la base de datos como las herramientas.

image Visual Web Developer
Instala la última versión del Visual Web Developer Express, nuestra herramienta completa gratuita para desarrollar sitios web.
image

Aplicaciones web populares
Instala las aplicaciones web gratuitas más populares como DotNetNuke y WordPress, Drupal BlogEngine.NET, etc.

image Extras
Incluye la última versión de PHP para Windows!

Pueden descargar la última versión en:
http://www.microsoft.com/web/downloads/platform.aspx

Enjoy it!

martes, 17 de marzo de 2009

Software Libre vs Software Propietario

No acostumbro a escribir sobre estos temas, mis posts generalmente son más técnicos. Sin embargo, desde hace tiempo que a veces me preguntan y muchas veces participo, voluntaria o involuntariamente, en desgastantes debates sobre el mundo Open Source y el Mundo Propietario, y la mayoría de las veces, estas discusiones, responden más a cuestiones ideológicas o fundamentalistas que objetivas.

La verdad es que me gustaría invertir más tiempo en otros temas, pero quise publicar este post para referenciar mi opinión al respecto en futuras e inevitables discusiones sobre este tema inacabable. Espero así en el futuro, cuando me encuentre en estas discusiones y me pidan opinión, pueda decir simplemente: “leé mi post”. ;-)

Encontrarán que hago muchas referencias y expongo ejemplos de o relacionado a Microsoft y sus tecnologías con las cuales trabajo día a día. Sin embargo, intento ser objetivo y espero ver comentarios objetivos de otras personas que tienen o han tenido experiencias en otras plataformas.

Introducción

Existe una gran confusión y un eterno debate entre la adopción de tecnologías basadas en Software Libre versus Software Propietario. Sin ánimos de iniciar un nuevo debate, la mayoría de las personas y organizaciones siempre están de acuerdo en que lo que se busca son soluciones de calidad al menor costo posible. Siempre se piensa en la relación Costo/Beneficio o Retorno de la Inversión.

Yo comparto esa visión, que contiene un amplio sentido común, y he decido evaluar las alternativas y plantear en forma realista diferentes soluciones en ambos enfoques, incluso creando soluciones combinadas para sacar el mejor provecho de cada una.

En este sentido, un aspecto fundamental a considerar es la realidad actual de las empresas y organizaciones, sus tecnologías disponibles, personal capacitado, cambios de plataformas, aceptación de los usuarios, etc.

Antes de estudiar y evaluar las alternativas sobre cada plataforma, veamos algunos mitos que giran entorno al Software Libre y Software Propietario.

Mito 1: Si es Software Libre, es Gratis

La palabra Libre se refiere a que se le concede a los usuarios 4 libertades básicas:

  1. Libertad de usar el programa con cualquier propósito
  2. Libertad de adaptar el programa a sus necesidades
  3. Libertad de copiar y distribuir
  4. Libertad de mejorar y hacer pública las mejoras a toda la comunidad

Cualquier programa que conceda estas libertades será considerado libre, pero esto no implica que sea gratis. Es evidente que para permitir estas libertades se debe proporcionar el código fuente del programa.

En la actualidad muchas empresas privadas desarrollan programas, herramientas y componentes y entregan el código fuente correspondiente junto a licencias que permiten su modificación y distribución, sin embargo no todas lo ofrecen en forma gratuita, pero siguen siendo libres.

Por otro lado, si un programa se distribuye gratuitamente, no significa que sea libre. Existen muchos programas de distribución gratuita que no incluyen su código fuente. Son gratis!, pero no son libres.

Mito 2: Si es Software Propietario, no es Libre

Cada vez más las empresas líderes de software reconocen los beneficios que el software libre puede aportar a la comunidad de usuarios y desarrolladores.

En consecuencia existen iniciativas de dominio público respaldadas por estas empresas que favorecen el uso de software libre y promueven comunidades de usuarios para el desarrollo e intercambio de programas y código fuente. Por el lado de tecnologías Microsoft son muy reconocidas y valiosas las comunidades de intercambio proyectos de código abierto como CodePlex (www.codeplex.com), SourceForge (www.sourceforge.net) y Code Project (www.codeproject.com).

Siguiendo con el mito 2, hace un tiempo que Sun Microsystems ha adquirido el famoso gestor de base de datos MySQL, y por ello no ha dejado de ser libre.

Por su parte, Microsoft también ha liberado el código fuente de su plataforma de desarrollo más preciada: .NET Framework. Y las bases de esta plataforma y el lenguaje C# se encuentran definidos como estándares internacionales por la ECMA; lo que ha permitido el desarrollo de nuevas iniciativas Open Source como el Proyecto Mono (http://www.mono-project.com) y el Proyecto dotGNU (http://www.dotgnu.org)

Mito 3: Si es Software Propietario, hay que pagar licencias

Hoy en día muchas empresas ofrecen innumerables productos, plataformas y servicios en forma totalmente gratuita. Empresas como Sun, Adobe, HP, Oracle y Microsoft ofrecen desde programas de usuario final hasta completas suites de desarrollo y potentes motores de bases de datos en forma totalmente gratuitas.

Por ejemplo:

Las prestaciones de estas herramientas son totalmente funcionales y permiten el desarrollo de soluciones completas y de calidad profesional, no hay que pagar licencias para usarlas.

Mito 4: Si la licencia de uso es gratis, el costo del sistema es cero

Quizás este sea el mito qué más puede confundir y perjudicar. El costo real de un sistema no está en las licencias de uso, sino en el mantenimiento y soporte necesario durante todo el ciclo de vida.

Cada empresa u organización debe evaluar si dispone y/o puede costear el personal técnico capacitado para dar soporte y mantenimiento a los sistemas antes de implementarlos. También debe evaluar el respaldo tecnológico asociado a la plataforma elegida, la comunidad de usuarios técnicos y no técnicos, etc.

Hace tiempo que las empresas y el mundo han comprendido que nada es realmente gratis, todo tiene un costo asociado. Y en las soluciones informáticas, generalmente el principal costo reside en el soporte y mantenimiento que asegure el funcionamiento de los sistemas en las condiciones apropiadas.

Finalmente, no se encuentra mucho valor al enfocarse solo en el costo de la solución, sino en los beneficios que éste puede brindar. Volvemos al principio: la relación costo/beneficio.

Usar lo mejor de cada mundo

La buena noticia de todo esto es que existe competitividad y un gran abanico de posibilidades para elegir. Además no todo es blanco o negro, existe la interoperabilidad entre plataformas.

Por ejemplo, existen soluciones en ASP.NET usando como bases de datos MySql o PostgreSql. Lo mismo ocurre con Java y las plataformas de Sun; y desde PHP podemos conectarnos a Microsoft SQL Server u Oracle. Y ni hablar si usando un enfoque SOA.

En un proyecto actual en el que estoy trabajando, incluye una solución de escritorio, destinado al sector educativo. Hemos visto que todas las escuelas de la región que intentamos dar cobertura tienen PCs con Windows XP y Office. Analizando este escenario:

  • ¿Porqué querríamos cambiar a Linux? ¿Por las licencias?
    Microsoft le ha otorgado licencias a costo casi cero a todas las escuelas.
  • Y si así no lo fuera, ¿cuál sería el costo de contratar personal capacitado para instalar Linux en todas las escuelas?
  • ¿Cuánto costará y cuánto tiempo llevará capacitar al personal administrativo?
  • ¿Qué costos tendría el cambio radical de sus programas y su forma de trabajo al personal?

Con esto no quiero decir que Linux sea una mala opción. Sino que siempre hay que evaluar el escenario. Quizás aquí podría ajustarse una solución desktop para Windows basada en Java o .NET usando como motor de datos MySql o SQL Server Express.

En definitiva, creo que la clave está en evaluar y saber elegir las soluciones más convenientes y apropiadas para cada escenario. Podemos usar lo mejor de cada mundo y debemos tener siempre presente la relación costo/beneficio y podría destacar entre los beneficios, la proyección y visión hacia futuro.

Bueno, espero haber aportado algo de claridad sobre este tema tan discutido.
Saludos, Gus

domingo, 8 de marzo de 2009

ADO.NET Entity Framework: The version of SQL Server in use does not support datatype 'datetime2'

Trabajando con ADO.NET EF, en mi entorno de desarrollo tengo SQL Server 2008 y en producción está SQL Server 2005. Al publicar mi aplicación, en algunas páginas obtengo el siguiente error:

The version of SQL Server in use does not support datatype 'datetime2'

SQL Server 2008 dispone de un nuevo tipo de datos Datetime2 que agrega soporte mejorado de fechas y horas.

Por ejemplo, Datetime2 soporta fechas y horas desde 0001-01-01 00:00:00 hasta 9999-12-31 23:59:59.9999999 (nanosegundos de precisión), mientras que el conocido Datetime solo acepta rangos desde 1753-01-01 00:00:00 hasta 9999-12-31 23-59:59.999 (solo milisegundos de precisión). Pueden leer más sobre esto en el siguiente enlace (en inglés): DATETIME2 vs DATETIME in SQL Server 2008

Para resolver el problema de incompatibilidad usando ADO.NET Entity Framework hay que abrir el archivo .edmx con el editor de XML y cambiar el valor del atributo ProviderManifestToken a 2005.

<edmx:Runtime>
<edmx:StorageModels>
   <Schema Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2005">

Luego guardamos los cambios en el modelo y recompilamos la aplicación. Esto resolverá el error de versiones.

Algo importante a saber es que si posteriormente actualizamos el modelo en nuestro entorno de desarrollo el atributo ProviderManifestToken volverá a establecerse al valor 2008 y deberemos cambiarlo manualmente antes de publicar nuestra aplicación.

Quizás con una tarea postbuild podríamos hacer este cambio automáticamente. Si alguien se anima a crear una tarea como esta será bienvenida.

Espero que sirva.
Saludos, Gus

viernes, 6 de marzo de 2009

Paginación y Ordenamiento del lado servidor con GridView y ADO.NET Entity Framework

Esta vez quiero mostrarles como actualmente estoy implementando paginación y ordenamiento del lado servidor, usando GridView, ObjectDataSource y ADO.NET EF. Aunque de una forma muy similar también es aplicable a LINQ2SQL.

 

Creando los métodos en la capa de negocio o servicios

El primer paso consiste en crear en nuestra capa de negocios o servicios un par de métodos que luego serán invocados por el control ObjectDataSource.

Básicamente necesito 2 métodos para lograr mi objetivo:

  1. Un método que me devuelva la cantidad total de registros
  2. Y otro método que me devuelva los registros paginados

Para el ejemplo voy a crear en una clase CatalogService, un método FindProducts() y otro método FindProductsCount().

public IList<Product> FindProducts(int? code, string description, int? categoryID, string sortExpression, int startRows, int maxRows)
       {
           using (var db = new StoreEntities())
           {
               var query = from p in db.Products select p;

               query = FindProductsFilter(query, code, description, categoryID);
               query = FindProductsSort(query, sortExpression);

               return query.Skip(startRows).Take(maxRows).ToList();
           }
       }

Aquí vemos que FindProducts() llamá a 2 métodos FindProductsFilter() y FindProductsSort() que se encargan de aplicar los filtros necesarios y ordenar los registros, y luego usa los métodos Skip y Take para paginar los resultados.

private static IQueryable<Product> FindProductsFilter(IQueryable<Product> query, int? code, string description, int? categoryID)
{
    if (code.HasValue)
        query = query.Where(p => p.Code== code);

    if (!string.IsNullOrEmpty(description))
        query = query.Where(p => p.Description== description);

    if (categoryID.HasValue)
        query = query.Where(p => p.Category.ID== categoryID);

    return query;
}

private IQueryable<Product> FindProductsSort(IQueryable<Product> query, string sortExpression)
{
    if (string.IsNullOrEmpty(sortExpression))
        return query.OrderBy(p => p.Description);

    return query.OrderBy(sortExpression);
}

Es importante saber que el método OrderBy() no acepta un parámetro string para realizar el ordenamiento. Sin embargo, aquí estoy usando unas extensiones de LINQ conocidas como Dynamic Query para lograr este objetivo.

Pueden leer un artículo de Scot Guthrie traducido al español sobre Dynamic Query y descargar el código fuente.

Sin Dynamic Query, tendría que parsear el parámetro sortExpression y escribir un switch o multiples ifs para aplicar el OrderBy correspondiente según el campo. En pocas palabras, tendría que escribir muuucho más código, entonces prefiero Dynamic Query.

Y ahora el método FindProductsCount() que no hace otra cosa más que contabilizar el total de productos. Este método lo utiliza el ObjectDataSource y la grilla para poder calcular el total de páginas necesarias, sin tener que traer todos los registros para luego paginarlos.

public int FindProductsCount(int? code, string description, int? categoryID)
{
    using (var db = new StoreEntities())
    {
        var query = from p in db.Products select p;

        query = FindProductsFilter(query, code, description, categoryID);

        return query.Count();
    }
}

 

Consumiendo los métodos desde la UI

Ahora creo una página aspx con unos campos para filtrar, un botón y una grilla asociada a un ObjectDataSource para los resultados. El formulario se vería mas o menos así:

image

No deseo explicar cómo enlazar la grilla con un ObjectDataSource, solo bastaría con decir que debemos asociar al método FindProducts() creado anteriormente y asociar los parámetros del método con los controles de la página. Y luego hay que habilitar Paging y Sorting en la grilla.

Las propiedades establecidas para el ObjectDataSource aparecen en negrita:

image 

Las propiedades sortExpression, startRows y maxRows serán pobladas y pasadas al método FindProducts y/o FindProductsCount automáticamente.

La última pieza es escribir código para el botón Buscar:

protected void FindButton_Click(object sender, EventArgs e)
{
    if (!Page.IsValid) return;

    try
    {

    ProductsGridView.DataSourceID = ProductsDataSource.ID;
    ProductsGridView.DataBind();
}
catch (Exception ex)
{
    ShowError(ex.Message);
}

}

Debe observarse que solo en runtime estoy enlazando la grilla con el control ObjectDataSource. Es decir, después de configurar la grilla y el ObjectDataSource, en tiempo de diseño, quito la referencia al ObjectDataSource en la propiedad DataSourceID de la grilla. De esta forma, cuando la página se carga no se hace una búsqueda automática, sino solo cuando se completan los filtros de búsqueda y se presiona el botón Buscar.

Pero esto es una particularidad que quise implementar y no tiene ningún efecto sobre la paginación y ordenamiento, motivo de este post.

Bueno creo que ya está todo, ahora hay que probar.

image

A mí me funcionó de maravillas ;-).

Mirando con el SQL Profiler veo que solo se consultan 10 registros por página. Las consultas al SQL Server devuelven solo los registros que el usuario quiere ver. Esto permite que nuestras aplicaciones sean mucho más escalables, pues solo traemos los registros necesarios y se minimiza la carga de trabajo en la BD.

Bueno espero que sirva.
Comentarios son bienvenidos!

Saludos, Gus

RUN09

Este es el nombre que finalmente fue bautizado al antes llamado Buenos Aires Briefing. Hoy Miguel Saez nos avisa que ya está disponible el site del evento en http://www.puertadeenlace.net/run09. Desde este sitio podrán registrarse, ver los oradores y revisar la Agenda del evento, y quizás descubrir algunas perlitas del site.

image

Es de destacar que el site tiene una UI inspirada en Windows 1.0, pero está desarrollado con las últimas tecnologías de MS. Incluso mike nos comenta en su blog que está disponible un servicio de WCF (http://www.puertadeenlace.net/run09/Models/Service.svc/) que se puede usar para construir otro cliente para el evento en Silverlight, WPF o Gadget de Vista y quizás ganar un poco de publicidad durante el evento.

Bueno, a tomarse un respiro y aprovechar este evento. Seguramente nos encontramos allí.
Saludos, Gus