jueves, 6 de septiembre de 2012

The Saml2SecurityToken is rejected because the SAML2:Assertion's NotBefore condition is not satisfied

Actualmente estamos convirtiendo una aplicación ASP.NET Web Forms para usar Identidad Federada con ACS (Access Control Service). Durante el proceso (que aún no termina), hemos encontrado con muchos issues que poco a poco fuimos resolviendo.

Recientemente me encontré con esta exception y muy poca información en Internet:

ID4147: The Saml2SecurityToken is rejected because the SAML2:Assertion's NotBefore condition is not satisfied.
NotBefore: '9/6/2012 1:03:00 AM'
Current time: '9/5/2012 8:01:55 PM'

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: Microsoft.IdentityModel.Tokens.SecurityTokenNotYetValidException: ID4147: The Saml2SecurityToken is rejected because the SAML2:Assertion's NotBefore condition is not satisfied.
NotBefore: '9/6/2012 1:03:00 AM'

Current time: '9/5/2012 8:01:55 PM'

Este error ocurría después de autenticar satisfactoriamente al usuario contra el proveedor de Identidad (ADFS) y al intentar validar el token emitido, WIF (Windows Identity Foundation) lanzaba esta exception.

Básicamente, el error ocurre porque el Token emitido por el Identity Provider (ADFS en nuestro caso) tiene una fecha futura respecto al servidor donde está hosteada la aplicación (Relying Party). Esto es cierto porque el ADFS que estamos usando está en Inglaterra y la aplicación que valida el Token emitido está en Argentina y obviamente hay una diferencia horaria.

Desafortunadamente solo encontré un post relevante con este mismo issue donde como solución recomendaban que actualice la hora de la máquina.
http://social.msdn.microsoft.com/Forums/en-CA/windowsazuresecurity/thread/f25e9b1b-0063-41f8-98a9-6c26af94bbf2

Después de largas horas de desorientación, recordé un issue similar con WCF y entonces encontré una solución al problema gracias al elemento maximumClockSkew que permite especificar un desfasaje de hora para el token. He agregado la siguiente configuración al web.config de mi aplicación (Relying Party):

<microsoft.identityModel>
<service>
<maximumClockSkew value="23:59:59" />
Con esta configuración estoy indicando hasta casi 24 horas de diferencia para la validación del token.
Después de reiniciar el web server, intenté nuevamente y la aplicación funcionó correctamente!!!
Espero esto sea util para alguien que esté lidiando con estos temas. 
Comentarios y sugerencias son bienvenidos.
Saludos, Gustavo

martes, 5 de julio de 2011

Entity Framework: Code First

Finalizando la serie de posts sobre los enfoques de Entity Framework, ahora intentaré explicar el enfoque Code First.

Puedes leer mis posts anteriores sobre Database First y Model First.

Este post es más bien conceptual, puede contener algunos detalles prácticos, pero no pretende mostrar ejemplos ni guías paso a paso. En futuros post intentaré dar ejemplos prácticos sobre cada uno de estos enfoques.

Code First

Este enfoque está disponible a partir de la versión ADO.NET Entity Framework 4.1 y nos permite crear un modelo de clases POCO (Plain Old CLR Object) a partir del cual podemos generar una base de datos y/o mapear esas clases a una base de datos existente.

Aquí no existe un archivo edmx con las definiciones XML del modelo conceptual, el modelo de datos y el mapeo entre ambos.

El modelo conceptual está definido por el conjunto de clases que hemos creado para representar a las entidades de nuestro modelo de dominio. La idea es que nuestras clases POCO sean mapeadas directamente a la base de datos.

La ventaja de usar clases POCO es que el modelo de clases es más limpio y las clases no tienen dependencia con EntityFramework (como sucede cuando las entidades heredan de EntityObject, implementan ciertas interfaces y contienen atributos).

 

¿Cómo se mapean las clases POCO a la base de datos?

De forma predeterminada, se utiliza un mapeo por convención en lugar de configuración. Es decir, si no especificamos el mapeo, se utilizan los nombres de las clases y sus propiedades para generar los nombres de las tablas y sus campos.

Este mapeo por convención puede ser suficiente en nuevos proyectos, donde estamos definiendo y diseñando el modelo conceptual y la base de datos desde cero.

 

¿Qué pasa si ya tengo una base de datos heredada?

Si el esquema de la base de datos heredada coincide con el modelo conceptual, entonces el mapeo por convención seguirá siendo suficiente y aplicable y todos felices! (Probabilidad: 0.0000001%)

La experiencia indica que si ya tenemos una base de datos heredada, es altamente probable que haya diferencias con el modelo conceptual utilizado en la aplicación. Entonces:

  • ¿Qué hacemos cuando el esquema de base de datos es diferente al modelo conceptual?
  • ¿Qué tal si quiero especificar restricciones, tipos de datos o validaciones a los campos?

Bien, podemos resolver estas cuestiones y otras tantas a través de:

  1. Data Annotations
  2. Mapping Fluent API

 

Data Annotations

Estas clases están disponibles en el namespace System.ComponentModel.DataAnnotations y permiten especificar restricciones o validaciones, especificar nombres de tablas o campos, etc.

image_thumb11

Hay dos artículos interesantes sobre Data Annotations que recomiendo (en inglés):

 

Mapping Fluent API

La segunda alternativa que Code First ofrece para definir el mapeo entre el modelo conceptual y la base de datos es mediante Fluent API. Esta API permite especificar la configuración de mapeo y otras configuraciones mediante código.

image_thumb3

Los siguientes enlaces contienen un artículo interesante con ejemplos sobre Code First Fluent API y un video paso a paso:

 

¿Y el contexto de datos de Code First?

De forma predeterminada, con el enfoque Database First y Model First disponemos de una clase ObjectContext del cual hereda el contexto de datos de nuestra aplicación.

Con el enfoque Code First tenemos un nuevo contexto llamado DbContext del cual debe heredar el contexto de datos de nuestra aplicación.

image_thumb5

En el contexto de datos, básicamente estamos definiendo cuáles son los conjuntos de entidades que serán mapeados a la base de datos.

Adicionalmente, podemos usar inicializadores de bases de datos, especificar configuraciones de mapeo o interceptar las operaciones de SaveChanges (entre otras).

DbContext no es más que una versión simplificada de ObjectContext, y también puede ser usando con los enfoques Database First y Model First.

 

¿Cómo o cuando se genera la base de datos?

Cuando se crea una instancia de DbContext, de forma predeterminada, se utiliza una estrategia de inicialización que crea a base de datos si no existe, opcionalmente se puede agregar código para insertar registros después de la creación.

Estas operaciones de inicialización pueden ser implementadas usando el método Database.SetInitializer. Éste método toma como parámetro una estrategia de inicialización de base de datos.

Entity Framework Code First incluye 3 inicializadores:

  1. CreateDatabaseIfNotExist
  2. DropCreateDatabaseAlways
  3. DropCreateDatabaseIfModelChanges

Podemos utilizar estos inicializadores de base de datos, cuando la aplicación se inicia. Por ejemplo, en una aplicación web podríamos usarlo en el evento Application_Start del archivo global.asax, en una aplicación de consola podríamos incluirlo en el método Main del programa principal.

image

Adicionalmente, podemos crear una clase que hereda de alguno de estos inicializadores y sobreescribir el método Seed para insertar registros después que la base de datos es creada.

image

Luego, usamos esta clase al iniciar la aplicación:

image

 

¿Cómo sería la inicialización de base de datos en un entorno de producción?

Bueno, es claro que en el entorno de desarrollo o pruebas, la inicialización de base de datos puede ser muy útil. Pero en un entorno de producción podría ser un problema.

Simplemente podemos “apagar” la inicialización de base de datos, pasando null como parámetro del método SetInitializer:

image

 

Conclusión

  • Code First es el nuevo enfoque soportado por Entity Framework. Permite mapear nuestras clases POCO directamente a la base de datos.
  • De forma predeterminada, el mapeo es por convención en lugar de configuración.
  • Configuración adicional de mapeo puede especificarse mediante Data Annotations o Fluent API.
  • DbContext API nos permite realizar las operaciones de acceso a datos.

Espero que esta serie de posts haya aclarado un poco más sobre las alternativas de trabajo con Entity Framework.

Dedicaré nuevos posts con ejemplos más prácticos de cada uno de estos enfoques, ventajas, desventajas, limitaciones, etc.

Saludos
~Gus

viernes, 1 de julio de 2011

Entity Framework: Model First

Continuando con la serie de posts sobre los enfoques de Entity Framework, ahora intentaré explicar el enfoque Model First.

Puedes leer sobre el enfoque Database First en mi post anterior.

Este post es más bien conceptual, puede contener algunos detalles prácticos, pero no pretende mostrar ejemplos ni guías paso a paso. En futuros post intentaré dar ejemplos prácticos sobre cada uno de estos enfoques.

Model First

La idea aquí es crear primero el modelo conceptual y a partir de este generar la base de datos.

image_thumb4

Usando Visual Studio podemos arrancar creando un archivo .edmx vacío y utilizamos el diseñador visual para crear nuestras entidades con sus propiedades y relaciones con otras entidades.

Cuando tenemos nuestro modelo conceptual completo, podemos generar los scripts de SQL para crear el esquema de base de datos.

image

¿Qué pasa si la base de datos cambia?

En realidad, la base de datos debe cambiar como consecuencia de un cambio en el modelo conceptual.

Ok ¿Qué pasa si el modelo conceptual cambia?

Habrá que actualizar el modelo conceptual de EntityFramework y generar los scripts SQL de creación de la base de datos.

Desafortunadamente, los scripts SQL generados a partir del modelo conceptual son solo scripts de creación. Es decir, no son scripts de cambios o actualización de nuestro esquema de base de datos. En consecuencia, deberíamos borrar la base de datos y volver a crearla. Obviamente, esto no será factible en un entorno de producción y deberemos elegir otras alternativas. Por ejemplo:

  1. Actualizar el esquema de datos a través de scripts escritos a manos o generados mediante una herramienta de comparación de esquema de datos. También podríamos alterar el esquema usando el Administrador de base de datos
  2. Luego deberíamos, actualizar el modelo conceptual de Entity Framework (edmx) y asegurarnos que el mapeo hacia la base de datos es correcto.
  3. Finalmente, actualizar el código existente en la aplicación.

Ojalá que en un futuro, el equipo de EF pueda incorporar un comparador de esquemas y generar scripts de actualización.

Ya tengo mi modelo conceptual creado, como sigo?

Bueno, a partir de ahora no difiere del enfoque Database First. Podemos escribir querys contra el modelo conceptual y realizar las operaciones de persistencia necesarias.

¿Las clases de entidades generadas con Model First son POCO?

De forma predeterminada NO. Las clases contienen metadata y heredan de clases dependientes de EntityFramework. Al igual que con Database First, disponemos de una clase que hereda de ObjectContext que nos permite interactuar con el modelo.

Sin embargo, es posible tener clases POCO agregando un ítem de generación de código llamado: ADO.NET POCO Entity Generator.

image

Esto elimina todo el código generado en el archivo .edmx.designer.cs y crea clases POCO basadas en plantillas T4.

image

Otra alternativa para generar clases POCO es eliminar la herramienta de generación de código EntityModelCodeGenerator asociada al archivo .edmx y generar las clases a mano.

image

image

Para finalizar este post, es interesante saber que estas técnicas para generar clases POCO, también son aplicables al enfoque Database First.

 

Conclusión

  • El enfoque Model First nos permite crear primero un modelo conceptual y generar luego el esquema de base de datos.
  • Al igual que Database First se basa en un archivo edmx para almacenar las definiciones XML del modelo conceptual, modelo de datos y mapeo entre ambos.
  • Las clases generadas automáticamente no son POCO, pero podemos generar clases POCO usando otras herramientas de generación de código.

El próximo post estará dedicado al enfoque más reciente soportado por Entity Framework: Code First.

Espero que sirva.
~Gus

jueves, 30 de junio de 2011

Entity Framework: Database First

En esta serie de post intentaré resumir los enfoques que hoy permite Entity Framework para crear nuestro modelo conceptual y resolver nuestras necesidades de persistencia.

Este post es más bien conceptual, puede contener algunos detalles prácticos, pero no pretende mostrar ejemplos ni guías paso a paso. En futuros post intentaré dar ejemplos prácticos sobre cada uno de estos enfoques.

Introducción

Actualmente con Entity Framework podemos elegir entre 3 enfoques diferentes para crear el modelo conceptual:

  1. Database First: El modelo conceptual se crea a partir de una base de datos existente.
  2. Model First: se crea el modelo conceptual y se genera la base de datos.
  3. Code First: nuevo a partir de EF 4.1. Un enfoque simplificado que permite mapear nuestras clases POCO a la base de datos usando convención, Data Annotations o Fluent API.

Este post estará dedicado al primer enfoque: Database First.

Database First

Este enfoque permite inferir un modelo de clases a partir del esquema de una base de datos existente.

image

Usando Visual Studio, podemos agregar un ítem de proyecto llamado Entity Data Model e iniciar un asistente para conectarnos a una base de datos, seleccionar los objetos que queremos incluir en el modelo (tablas, vistas, stored procedures) y generar un archivo .edmx que contiene una representación XML de:

  • El modelo conceptual (CSDL – Conceptual Schema Definition Language)
  • el modelo de datos (SSDL – Store Schema Definition Language)
  • y el mapeo entre ambos modelos (MSL – Mapping Specification Language)

El siguiente gráfico muestra un ejemplo del contenido XML de un archivo .edmx:

Es importante entender que el modelo conceptual (CSDL) no debe ser necesariamente igual al modelo de datos (SSDL), y por ello existe el modelo de mapeo (MSL).

A partir de ese archivo .edmx, se genera automáticamente (usando plantillas T4) un archivo .edmx.designer.cs (.vb en el caso de VB.NET) que contiene las clases que representan a las entidades del modelo conceptual.

Puede observarse que estas clases heredan de EntityObject y tienen varios atributos y propiedades dependientes de EntityFramework.

Típicamente, se crea una clase (entidad) por cada tabla de la base de datos, incluyendo propiedades que se mapean a campos y las relaciones entre las tablas son representadas mediante propiedades de navegación.

image

Además de las clases de entidades se genera también una clase que hereda de ObjectContext y representa el contexto de base de datos. A través de esta clase tendremos acceso a las entidades y colecciones del modelo y podremos realizar todas las operaciones de lectura y escritura de datos desde y hacia la base de datos subyacente.

En el siguiente ejemplo, BookstoreEntities es la clase generada por EF que hereda de ObjectContext:

image

Luego podemos usarla para acceder al modelo:

image

¿Puedo modificar o extender las clases de entidades generadas por EF?

Las clases generadas en el archivo .designer son re-generadas cada vez que se actualiza el modelo en el archivo .edmx. En consecuencia, no podemos modificar o agregar código a esas clases. La buena noticia es que son clases parciales y podemos extenderlas en otro archivo o bien podemos usar herencia.

¿Qué pasa si la base de datos cambia?

Habrá que actualizar el modelo conceptual. Esto puede lograrse fácilmente a través del designer del edmx:

image

Se inicia el asistente de actualización en el cual podemos agregar nuevas tablas, vistas o stored procedures, refrescar las tablas existentes o eliminar otras.

image

Una vez finalizado el asistente, el archivo edmx se actualiza y se re-generan las clases de entidades. Luego habrá que actualizar el código que hace referencia a las entidades modificadas (si corresponde).

Conclusión

  • El enfoque Database First nos permite generar rápidamente nuestro modelo de clases y mantenerlo sincronizado cuando el modelo de datos cambia.
  • El archivo edmx contiene una definición XML del modelo conceptual (CSDL), el modelo de datos (SSDL) y el mapeo entre ambos.
  • Las clases generadas heredan de EntityObject y se utiliza una clase que hereda de ObjectContext para administrar el modelo y realizar las operaciones de persistencia.

En los próximos post continuaré con los otros dos enfoques de Entity Framework (Model First y Code First), y hablaremos sobre las opciones de generación de entidades POCO, etc.

Espero que sirva, saludos.
~Gus

martes, 7 de junio de 2011

Imperdible el Barcamp NEA 2011!!!

Ya está confirmada la fecha para el Barcamp NEA 2011. Será el sábado 25 de Junio en las instalaciones de la UTN Resistencia.

Si querés saber de qué se trata todo esto y seguir las novedades ingresá a www.barcampnea.com.ar y registrate!

También podés leer el post de Luis que explica todo lo que necesitás saber para participar, colaborar, difundir y asistir a este importante evento.

Aún faltan muchas cosas para el evento, así que toda colaboración será bienvenida.

Aprovecho en este post para sumarme a la iniciativa de Facundo y agregar un par de diseños de remeras, uno con el diseño clásico y otro más… nosé…

barcampnea_2011_classic

(Clic para agrandar)

barcampnea_2011_green

Bueno, quizás estas remeras puedan estar disponibles ese día.

Seguí todas las novedades del evento en Twitter @barcampnea o Facebook.


Sigan difundiendo, nos veremos allá.
~Gus

viernes, 25 de marzo de 2011

Tutorial de MVC3

Como sabrán hace poco tiempo fue liberada la versión 3 de ASP MVC, y ya se pueden encontrar muchos recursos, tutoriales, videos, etc. acerca de las bondades de MVC3. Un tutorial muy recomendado es el de Scott Hanselman: Getting started with MVC3.

Si bien este tutorial se encuentra online y disponible para toda la comunidad he decidido compilar el tutorial completo en un documento PDF imprimible y publicarlo para su descarga:

image

Pueden descargar este tutorial desde: http://www.avanic.com.ar/downloads/docs/getting_started_with_mvc3_cs.pdf

Espero lo disfruten!
Gus

viernes, 12 de noviembre de 2010

Twitter is over capacity…again!

Hoy Viernes 12 de Noviembre de 2010 a las 12:59hs, Twitter está caído. Es la segunda vez que lo veo personalmente. Como esto no es tan frecuente, uno hasta lo mira con aprecio a la pantalla.

image

Hubiera pensado que a estas alturas ya estaban montados sobre alguna plataforma más escalable del estilo PAAS o IAAS, pero parece que no.

¿Alguien sabe de la infraestructura actual de Twitter?

Nos seguimos, Gus

lunes, 8 de noviembre de 2010

IsNullOrWhiteSpace, that’s the question!

Seguramente muchos ya lo han observado en C# 4.0. Existe una nueva función aplicable al tipo String: IsNullOrWhiteSpace()

A la vieja y conocida función IsNullOrEmpty() le faltaba chequear los espacios en blancos o otros caracteres no visibles.

Esta nueva función agrega justamente eso. Es decir, no solo verifica lo que indica su nombre, sino también cadenas vacías y otros caracteres no visibles que son irrelevantes en muchos procesos.

Si antes, para considerar los espacios en blanco, teníamos que escribir lo siguiente:

if (string.IsNullOrEmpty(value) || value.Trim() == string.Empty)

ahora es suficiente y más eficiente escribir:

if (string.IsNullOrWhiteSpace(value))

Hace algún tiempo había escrito un extension method que hacía más o menos esto. Pero ahora esta nueva función integrada, es bienvenida y tendré que jubilar mi extension method (o usar la nueva función internamente).

Debo reconocer que al principio me guié solo por el nombre y pensé que no consideraba las cadenas vacías. Quizás esperaba un nombre como:

IsNullOrEmptyOrWhiteSpaceOrAnotherInvisibleChar()

Pero creo que es mejor el nombre actual. A propósito, esto me hace recordar un viejo método disponible desde las primeras versiones del framework:

FormsAuthentication.HashPasswordForStoreInConfigFile()

Lo he usado muchas veces, pero nunca para guardarlo en un archivo de configuración ;-)

Me pregunto: que habrán estado pensando cuando bautizaron a este método?

Espero que sirva.
Gus

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