Desarrollador con calidad vale por dos (o más…)

Las metodologías ágiles nos recomiendan centrar nuestros esfuerzos en aportar valor al cliente. Dicho valor se traslada a través de los entregables que el equipo va liberando en las diferentes iteraciones. En el mundo del desarrollo de aplicaciones informáticas, el más importante de todos los artefactos que entregamos es el Software. Y este software se genera desde el código que generan los miembros del equipo.

Bueno eso este claro. Y que menos se puede pedir al equipo que se aplique al máximo con el código que genera? Como desarrollador de software el código es tu producto final, y este debe ser desarrollado con la máxima calidad que nos sea posible.

Algo que todos (los que entendemos como funciona el negocio del desarrollo de software..) tenemos claro, es que es más rentable asegurar al calidad de nuestros desarrollos desde las primeras etapas del proceso en vez de corregir los errores más tarde. El impacto de los errores crece exponencialmente cuanto más tarde se descubren.

Por lo tanto, como desarrolladores profesionales que somos, debemos poner especial hincapié en mantener presente la calidad en nuestros proyectos. Es fácil de decir, pero como a menudo, no tan fácil de conseguir…

Existen algunos grupos de problemas comunes que podemos identificar como focos problemáticos:

  1. Comunicación pobre y malas interpretaciones
    La capacidad de comunicación del ser humano es uno de los factores que le diferencia del resto de las especies. El grado de abstracción que podemos aplicar a la misma es muy alto. Esta característica, nos permite transmitir mucha información de manera muy efectiva.

    Por ejemplo, si yo te digo, singelton, grano fino, o capa de servicios y ambos tenemos un conocimiento equivalente en la materia, hemos conseguido transmitir una serie de conceptos más o menos complejos de manera optimizada.

    Es una herramienta potente, pero que debemos cuidar para evitar desviaciones igual de potentes. La comunicación debe ser clara y fluida, asegurando que el receptor ha comprendido el mensaje en la misma dimensión que deseamos emitirlo. No se debe escatimar en comunicación funcional, técnica, recabar feedback del equipo y aplicar un poco de psicología (la empatía puede ser la clave). Colaborar en este juego es parte de la tarea de cualquier miembro de un equipo.

  2. Errores de programación
    Las personas  escriben código y las personas comenten errores. Ergo…el código tiene errores (ahora no abusemos del mismo para hacer chapuzas diciendo es intrínseco el error en la persona…)

    Escribir buen código no es fácil. Debemos tener en cuenta aspectos como seguridad, rendimiento, localización, mantenibilidad… y en tiempo record!

    Aunque apoyarnos en el CLR ayuda, siempre existirán bugs que tendremos que corregir y realizar mantenimiento sobre el mismo. Y esto ocurre haciendo las cosas todo lo bien que podemos, esforzándonos al máximo como desarrolladores. Imagínate si no lo hacemos así…

  3. Falta de realimentación de pruebas
    Escribir pruebas unitarias es un trabajo que (casi) no aporta visibilidad. Lleva tiempo y no es código fácil de reutilizar. Aunque los desarrolladores sabemos que debemos escribirlas y esforzarnos y alcanzar la cobertura d código marcada por los parámetros de calidad del proyecto, a menudo nos enfrentamos a desincentivos que tientan a no realizarlas. Pero lo que es seguro, es que sin un buen conjunto de pruebas, (no tiene que ser muchas pero si bien diseñadas) es muy fácil cambiar código y no descubrir los efectos secundarios no deseados hasta demasiado tarde. (vamos creando un coladero…)
  4. Versión distorsionada
    Gracias a la metodología al principio, y a las herramientas de control de código fuente, más adelante no se han producido millones de asesinatos entre los desarrolladores. Aún así existen archivos y configuraciones de puestos que no son propios del código fuente cuyas diferencias producen errores que son difíciles de diagnosticar. Cuantas veces hemos oído eso de «En mi máquina funcionaba!».
  5. Falta de transparencia
    Para desarrollar un proyecto con éxito hace falta todo. Como una de las piezas falle o no se comunique adecuadamente todo el proyecto se puede venir abajo como un castillo de naipes. Tradicionalmente, han sido mundos diferentes (e inconexos!!) aspectos como la infraestructura de desarrollo, el sistema de gestión del proyecto, el trazado de requisitos/errores, métricas…(Intenta sincronizar el s.v.n. con el Visio que se sacó tu gerente de la manga…;))
    En esta situación, el equipo tiene poca visibilidad respecto al estado global del proyecto. (aparte de los odiados y poco fiables informes de estado…)

Cada una de estas cinco categorías son un foco potencial de problemas que afectan directamente a la calidad del código realizado. Esto implica que el mecanismo que el cliente emplea para evaluar el valor aportado, tiene problemas que afectan, directamente, a las sensaciones que transmitimos. La aparición de herramientas que nos permiten gestionar todos los aspectos relacionados con el desarrollo de manera orquestada vienen a facilitarnos la vida, y conocer sus posibilidades es un esfuerzo con seguro retorno de inversión.

Por nosotros que no quede…

¿Es lo mismo arquitectura por capas y N-Tier?

Me parece importante, para optimizar la comunicación entre profesionales, que todos tengamos claros los conceptos y los apliquemos para referirnos exactamente a lo mismo. Esto nos evita malas interpretaciones y errores muy críticos sobre todo en entonos de desarrollo rápido de aplicaciones (RAD). 

Existen dos conceptos arquitectónicos que a veces tendemos a confundir. Estos son la “Layered arquitecture” (arquitectura por capas) y la “N-tier arquitecture” (arquitectura de N-niveles). Me voy a referir a ellas sin traducirlas, puesto que ambos conceptos (“layer” y “tier”) pueden verse traducidas (erróneamente en el caso de “tier”) como “capa” lo cual fomenta aún más la propensión a errores.

Veamos primero que es exactamente “Layered architecture”: 

Se centra en una distribución jerárquica de las roles y responsabilidades proporcionando una separación efectiva de las preocupaciones. (cada cual que se apañe con sus problema…). El rol indica el modo y el tipo de interacción con las otras capas, y la responsabilidad indica la funcionalidad a alcanzar.

Por ejemplo, el diseño de una típica aplicación Web comprende una capa de presentación (funcionalidad relacionada con la U.I.), capa de negocio (procesamiento de reglas de negocio) y capa de datos (funcionalidad relacionada con el accesos a datos.)

El estilo de arquitectura por capas tiene algunas características que  la identifica:

  • Describe una descomposición de servicios de tal manera que las interacciones ocurren normalmente entre capas vecinas. (depende de lo laxos que queramos ser…)
  • Las capas de la aplicación pueden residir en el mismo ordenador fisco o pueden estar distribuidas en separados equipos. El concepto de distribución se aplica siempre que se produzca el mecanismo de marshaling para realizar una comunicación (siempre que no se comparta espacio de memoria…)
  • Los componente de cada capa se comunican con otros componente de otras capas a través de un conjunto de interfaces bien definidos. (sino apañados vamos…)
  • En alguna ocasión ha sido descrito como “pirámide invertida de reutilización” donde cada capa agrega sus propias responsabilidades  y abstracciones a la capas que están por debajo.

Que beneficios conseguimos aplicando esta distribución en capas?

Abstracción, encapsulamiento, capas de funcionalidad muy bien definidas, alta cohesión, reusabilidad (las capas inferiores de la pirámide no tienen dependencias de las superiores por lo que es fácil reutilizarlas) y débil acoplamiento (comunicación basada en abstracciones)

La separación, reduce el riesgo y el impacto de los cambios tecnológicos. Por ejemplo al cambiar el mecanismo de persistencia de la aplicación las capas que lo consumen no tienen porque realizar cambios. Además aumenta el rendimiento (a partir de cierta carga de trabajo) al distribuir las capas sobre múltiples capas físicas. También aumenta la escalabilidad y la tolerancia a fallos.

Este escenario es propicio para implementar una buena política de pruebas, permitiendo conmutar entre diferentes implementaciones de los interfaces (mock, servicios reales…)

Por otro lado tenemos la N-Tier architecture

El estilo de despliegue de esta arquitectura describe la separación de la funcionalidad en diferentes segmentos, de manera similar a la arquitectura por capas. pero cada segmento es un nivel que se encuentra físicamente en un equipo independiente.

Es un estilo que define el despliegue de las capas de la aplicación, se caracteriza por por una descomposición funcional de la aplicación, componentes de servicios y su despliegue distribuido, proveyendo mejoras de escalabilidad, disponibilidad  y utilización de recursos.

Cada capa es completamente independiente del resto, excepto de aquella/s se encuentran inmediatamente por debajo de ella. La capa n sabe como manejar las peticiones a la capa n+1, como trasladar dicha petición a la capa n-1 (si es que existe) y como tratar el resultado de la misma.

Las arquitecturas con “N-Tiers” poseen por lo menos 3 capas lógicas separadas. Cada capa tiene una funcionalidad especifica, de la cual es responsable y están localizadas en diferentes servidores físicos. Una capa (“layer”) se despliega en un nivel (“tier”) si más de un servicio o aplicación es dependiente de la funcionalidad expuestas por la capa.

Veamos los beneficios que nos aporta esta arquitectura:

  • Mantenibilidad
    Cada nivel es independiente de los demás, con lo que se consigue independencia. Se puede actualizar o modificar un nivel sin afectar a la aplicación en su conjunto. 
  • Escalabilidad
    Es razonablemente sencillo escalar puesto que los niveles están basadas en el despliegue de las capas.
  • Flexibilidad
    Cada nivel puede ser gestionado o escalado independientemente, lo cual aumenta la flexibilidad.
  • Disponibilidad
    Las aplicaciones pueden explotar la arquitectura modular empleando componentes fácilmente escalables.

Resumiendo un poco :

Podemos decir que para que una aplicación sea “N-Tier”, es condición necesaria pero no suficiente que mantenga una arquitectura por capas. Esta característica nos permite cumplir los requisitos de despliegue (3 o más capas separadas) que hacen a una aplicación “N-Tier”.

Dulce introducción al Kanban!!

Bueno, parece que SCRUM ha puesto la pica en Flandes y se ha convertido en una metodología ampliamente conocida y respetada. Pues ya está, no? ya tenemos metodología ágil para cualquier tipo de proyecto y para siempre…

Muy confiado tienes que ser para creerte eso…

En mi trabajo hemos desarrollado un producto aplicando SCRUM con unos resultados muy satisfactorios. Dicho producto, se ha comenzado a implantar y ahora entra un equipo de soporte a mantener la primera versión del mismo y comienza una nueva rama de desarrollo de la siguiente versión.

Estaba planteándome como organizar el equipo de soporte y no acababa de encajar SCRUM sobre la naturaleza de su trabajo (la verdad que esta y cualquier otra metodología…). Es muy difícil organizarse para planificar incluso un pequeño Sprint, puesto que no se conocen las tareas de antemano. Por lo tanto, llegué a la conclusión de que necesitamos para este tipo de proyectos (que no son pocos) algo todavía más adaptable que SCRUM…

Tomando un café con el gran (aunque javero) Jorge Prieto me comentó algo sobre Kanban y comencé a tirar del hilo para ver si me podía cuadrar eso que sonaba a pescado crudo…

Así que vamos a aprovechar este post para explicar que es eso de Kanban compararlo con SCRUM e identificar sus conflictos potenciales. Antes que meternos en harina vamos a dejar las cosas claras, haciendo un pequeño resumen de SCRUM y Kanban

SCRUM (en pocas palabras)

  • Divide su organización en pequeños equipos auto-organizados y multidisciplinares.
  • Divide el trabajo en una lista de pequeños elementos muy concretos.
  • Ordenar la lista por orden de prioridad y estimar el esfuerzo relativo de cada elemento.
  • Dividido en iteraciones cortas de longitud fija (normalmente con entrega o demostración después de cada iteración.)
  • Optimizar el plan de liberación y actualizar las prioridades en colaboración con el cliente, sobre la base de conocimientos adquiridos por la inspección de la entrega después de cada iteración.
  • Optimizar el proceso por tener una retrospectiva después de cada iteración.

Resumiendo el resumen:

Pasamos de “Muchas personas haciendo algo muy grande” a “Pocas personas haciendo cosas pequeñas que se integran con regularidad para ver el conjunto.”

Kanbas (en pocas palabras también)

  • Visualizar el flujo de trabajo
    Dividir el trabajo en trozos escribir cada uno de los elementos en una tarjeta y poner en la pared.
    Usar el nombre o columnas para ilustrar en que estado se encuentra cada elemento dentro del flujo de trabajo.
  • Límitar WIP (Work In Progress)
    Asignar límites explícitos obre cuantos elementos pueden estar en cada uno de los estados del flujo de trabajo.
  • Medir el tiempo
    Contar el tiempo promedio para completar un tema, a veces llamado «tiempo de ciclo» y, como es obvio, optimizar el proceso para que el tiempo tan pequeño y previsible como sea posible.

image

 

Podemos observar que Kanban es todavía menos prescriptivo que SCRUM.

Prescriptivo significa “reglas para seguir”. 100% prescriptivo implica que no tienes que usar el cerebro, ridículo verdad?…) y en este apartado vemos que SCRUM aporta mas reglas “out-of-the-box” como por ejemplo encajar en un tiempo los Sprints cosa que Kanban no hace.

Para hacernos una mejor composición podemos observar la escala de “prescriptividad” (toma ya!) de forma gráfica:

image

Como siempre podemos decir que la mejor opción es no limitarse a un herramienta en concreto. Probablemente la solución nuestros problemas se encuentre en una combinación de varias. Muchos equipo Kanban realizan una reunión diaria a primera hora (típica liturgia de SCRUM). Algunos equipos de SCRUM que he conocido, escriben su Backlog como Casos de Uso (típico de RUP) o limitan el tamaño de las colas (típico de Kanbas).

Así que como siempre “haz las cosas como mejor te funcionen”, ya os contaré el resultado de aplicar esta forma de trabajo con el equipo de soporte.

Para terminar os cito a Miyamoto Musashi que los japoneses algo saben de todo esto:

“No desarrolles ninguna dependencia de arma o escuela de lucha”

Los mejores países para hacer negocio

Si estáis pensando en globalizar vuestras líneas de negocio o cambiar de aires profesionales, os puede resultar interesante saber que el World Bank Group ha publicado su informe anual «Doing Business» que clasifica 181 países sobre lo propicio que es su regulación hacia los empresarios.

El informe proporciona una medida cuantitativa de la normativa, que sirva como soporte a la decisión de abrir un negocio y se aplica a las pequeñas y medianas empresas nacionales. Las economías están clasificadas en base a un índice de facilidad de hacer negocios. (Índice creado por el propio World Bank Group)

Los valores más altos de este índice indican un conjunto de reglamentos más ventajosos para las empresas y el fortalecimiento de la protección de los derechos de propiedad.

Facilidad de hacer negocios:

  1. Singapur.
  2. Nueva Zelanda.
  3. Estados Unidos.
  4. Hong Kong. (es una Región Administrativa Especial…)
  5. Dinamarca.
  6. Reino Unido.
  7. Irlanda.
  8. Canadá.
  9. Australia.
  10. Noruega.

Los criterios tenidos en cuenta a la hora de confeccionar este ranking son:

  • Facilidad de hacer negocios
    Procedimientos, tiempo, costo y capital social mínimo para abrir un nuevo negocio.
  • Permisos de Construcción
    Procedimientos, tiempo y costo para obtener permisos de construcción, las inspecciones y las conexiones de servicios públicos.
  • Emplear trabajadores
    Índice de dificultad de contratación, índice de rigidez de horas, índice de dificultad de despido, coste de despido.
  • Registro de la Propiedad
    Procedimientos, tiempo y costo para la transferencia de bienes inmuebles comerciales.
  • Obtención de crédito
    Fuerza de los derechos legales, profundidad de crédito.
  • La protección de los inversores
    Fuerza de la protección de los inversores, grado de divulgación, grado de responsabilidad del director y la facilidad de adaptación del accionista.
  • Impuestos
    Número de pagos de impuestos, el tiempo necesario para preparar y presentar declaraciones de impuestos y pagar los impuestos, relación del total de impuestos con el porcentaje del beneficio.
  • Comercio a través de las fronteras
    Documentos, tiempo y el costo para exportar e importar.
  • El cumplimiento de los contratos
    Procedimientos, tiempo y costo para resolver una disputa comercial.
  • Cierre de una empresa
    La tasa de recuperación de la quiebra.

Como podéis comprobar está todo pensado…

Si queréis profundizar más en el tema, pasaros por aquí World Bank – Doing Business

¿Por que iterar?

Aplicando el patrón C.S.P. (Common Sense Pattern…) en nuestros desarrollos, observamos que debemos cumplir con las necesidades del cliente. Acto seguido, descubrimos, que estas cambian más que los nos gustaría (ouchh!). Por lo tanto, se crea la necesidad de ir ajustando el avance del proyecto a las necesidades reales (y cambiantes) del proyecto.

¿Pero como…?

La respuesta que nos aportan las metodologías agiles es sencilla, iterando. Partiendo el desarrollo de la aplicación en pequeños entregables que el usuario pueda probar e ir enriqueciendo. Suena lógico, pero vamos a hacer un esfuerzo de plasmar negro sobre blanco las principales ventajas que esta forma de trabajar nos ofrece:

  • Gestión de riesgos
    Asumámoslo, el resultado deseado no es concebible por adelantado. Existen riesgos, algunos ya identificados y otros por identificar. Para gestionarlos correctamente debes demostrar o refutar tus requisitos y diseñar las suposiciones implementando incrementalmente elementos que son objetivos del sistema, empezando con los de más alto riesgo.
  • Económicos
    En un ambiente de negocio incierto (casi todos los proyectos lo son !!) es clave optimizar los esfuerzos en las mayores prioridades del proyecto. Debemos manejar cada iteración como un conjunto de fichas de juego a apostar por un conjunto de funcionalidad que se pueda entregar, probar y que funcionen.
  • Enfoque
    Solo podemos mantener una cantidad limitada de elementos en la mente. Trabajando con pequeños lotes de trabajo podemos focalizar nuestros esfuerzos con un conjunto de funcionalidades que comprendemos y somos capaces de encajar y entender.
  • Motivación
    No existe un mecanismo mejor de motivación de acción prolongada (el dinero solo motiva en un espacio reducido de tiempo!!) para un profesional que comprobar como su creación se usa, es efectivo y valorado por los usuarios.
  • Control de la teoría
    Las iteraciones nos permiten controlar mejor las desviaciones, reduciendo el impacto de los errores en las estimaciones y crear un mecanismo de retroalimentación sobre los planes del proyecto.
  • Implicación de los interesados
    Los patrocinadores (clientes, usuarios, dirección…) pueden observar los resultados más rápidamente (cumpliendo así con la visibilidad, requisito fundamental de cualquier desarrollo) y así aportar mayor compromiso, implicación y financiación.
  • Aprendizaje continuo
    Todos los actores del proyecto aprenden en cada iteración. Los miembros del equipo adquieren conocimiento funcional y aportan mejoras desde la prospectiva tecnológica y los funcionales comprenden las implicaciones de automatizar los procesos empresariales. Todos aportan y el proyecto crece rápido y mejora.

Ya tenemos un conjunto de argumentos para convencer a los stakeholders más peleones acerca de las bondades de trabajar en pequeñas iteraciones, ahora el que quiera entender que entienda…

Reflexión "reposada" sobre las metodologías ágiles

A lo largo de los años de experiencia que tengo en el sector de la informática he visto pasar muchas tendencias de largo. Algunas eran buenas ideas mal planteadas, (otras malas directamente) que simplemente no consiguen hacerse un hueco en la comunidad de stakeholders implicados.

En ocasiones han fracasado porque cargaban la balanza de un único lado dejando fuera a la otra parte del negocio. Nos guste o no, estamos obligados a entendernos puesto que en esto que este negocio de la informática tan importante es vender como desarrollar. Como una de las dos partes de la ecuación se sienta fuera del juego nunca una metodología podrá cuajar a alto nivel.

Hace ya un tiempo que estamos oyendo hablar de las metodologías ágiles y con la perspectiva que nos da el tiempo, podemos decir que estas tienen algún que otro as en la manga que las pueden hacer triunfar donde otras fracasaron. (Es verdad que la cosa es más fácil cuando el vecino ya se ha pelado la barba…)

Podemos decir que las cosas están cambiando y más rápido de lo esperado.

Poco a poco, el sector del desarrollo del software se va haciendo un hombrecito. Desde luego este proceso no se ha pospuesto por falta de esfuerzos. La industria, cual madre concienciada, haciendo palanca a través de la Ingeniería del Software ha intentado estandarizar de muchas maneras el “artístico” proceso de crear software. Algunos de estos intentos han sido más forzados que otras (UML, CMMI, Métricas de calidad… ), pero casi todos, por diversos motivos, han demostrado la misma poca efectividad. (Por cierto el VS2010 incluye soporte para los 6 documentos principales de UML!!)

Dichos intentos “encauzadores” de mamá industria han quedado a medio camino por la misma razón, partían de un axioma equivocado:

Todas las metodologías predictivas asumen el resultado del proceso de análisis y diseño como verdades inmutables que constituyen los cimientos sobre los que edificar el resto del proyecto.

Centrando sus esfuerzos en conseguir un terreno firme en el que apoyarse, la realidad, obstinada, nos demuestra que realmente lo hacían sobre arenas movedizas. No por que el resultado de tales esfuerzos estuviera mal hecho  (existen toneladas de documentación sobre como optimizar el proceso de toma de requisitos…) sino por simplificar en exceso el contexto (desestimando el factor cambiante) de cualquier proyecto de Software.

¿Cuantas veces nos ha ocurrido al terminar un proyecto que si lo volviésemos a empezar lo atacaríamos de otra forma…? En relación a otras ciencias (y entornos productivo-económicos) el desarrollo de software avanza muy rápido obligándonos a descartar metodologías de éxito en otros ámbitos por la naturaleza de nuestro negocio.

Alcanzar esta velocidad de crucero implica que hay mucho que mejorar y obliga al sector a reinventarse continuamente. La tecnología, los modelos de negocio, el alcance de la funcionalidad de las aplicaciones, la automatización de procesos, la integración y orquestación de unidades de negocio… todo está en ebullición. Como todos sabemos, no se puede estandarizar lo que no deja de cambiar, por lo que los intentos realizados se han ido quedando anticuados antes de alcanzar su madurez.

Pero en ese reinventarse ha cambiado la perspectiva…

Un buen día nos damos cuenta de que estamos peleando contra la realidad. Nos liberamos y dejemos de atacar y evitar el cambio como un enemigo. Es una actitud provocada por el convencimiento que surge desde dentro de que no hay otra opción. Debemos asumir (cuanto antes mejor) el cambio como algo que está ahí, nos guste o no, no podemos evitarlo. ¡¡Todo cambia!!

En las metodologías predictivas se destinan gran parte de los recursos a ser capaz de predecir lo que se va a desarrollar en los próximos años. Por muy concienzudo que sea dicho estudio, el contexto varía, las necesidades del cliente cambian, surgen nuevas oportunidades y riesgos. El que mayor capacidad de cambio demuestre, contará con una ventaja competitiva significativa.

Por lo tanto, permitir que nuestro cliente marque el siguiente paso a dar (o mejor dicho, pasito…) nos permite alinear el camino a recorrer con las necesidades del cliente que sobre la marcha surjan, aportando un mayor valor al software y satisfacción al cliente, que es (o debería ser) nuestro objetivo.

Aplicaciones multilenguaje ASP.NET MVC

El desarrollo de capa de presentación Web en .NET ha cambiado desde que Microsoft se decidió a realizar una implementación oficial del conocido patrón MVC en la plataforma ASP.NET y la (amplia) comunidad de desarrolladores de ASP.NET lo asumió con todos los cambios que implica.

Y esta implementación ha calado rápido y profundo, (ya se está desarrollando la segunda versión) ha llegado a la gente acostumbrada a Frameworks ligeros de desarrollo web que incluían sus propias implementaciones de MVC. Entre otras ventajas, ha ayudado a estandarizar la organización de los archivos del sitio y refinar las responsabilidades (Controladores -> Procesos de interfaz de usuario, workflow de la aplicación… Vistas –> mostrar la información de manera amigable y recoger los datos, validaciones de formato…).

Si deseamos acogernos a la implementación de Microsoft de dicho patrón deberemos ir encajando los problemas la funcionalidad de toda la vida sobre estas nuevas reglas de juego.

Uno de los requisitos clásicos más general es que nuestra aplicación disponga de características de globalización / localización. La idea general es la de siempre, evitar incluir ninguna referencia explicita a una determinada cultura y jugar con las características de globalización que nos ofrece el .NET Framework. Pero como ya sabemos, en Web todo se complica un poquito más. Al correr sobre un protocolo sin estado como HTTP recae sobre nuestra aplicación recordar la cultura especificada por el usuario entre las distintas peticiones.

Entonces tenemos clara la misión:

Mostrar los elementos de la UI acordes a la cultura que el usuario especifique.

Suena fácil, no? Pues lo es, si somos un poco cuidadosos…

(Por cierto, os dejo al final del post el código de la solución para que os lo podáis descargar y probar.)

1 – Estableciendo las bases, recursos a los ficheros de recursos.

Vamos a ir realizando un ejemplo paso a paso para evitar perdernos:

  1. Creamos un nuevo proyecto ASP.NET MVC Web Application
  2. Incluimos en el proyecto la carpeta de App_GlobalResources
  3. Incluimos un par de ficheros de recursos de acuerdo a la configuración de recursos por idioma que deseamos incluir. 

    La convención de nomenclatura de los mismos dice que la primera parte del archivo es el nombre base. La segunda especifica la cultura (puede también ser solo el lenguaje que la forma). Esta última parte es opcional, entendiéndose como el juego de recursos predeterminado en caso de no exista.

    Es responsabilidad del .NET Framework enlazar automáticamente (en base a los ficheros de recursos especificados) el fichero adecuado con a la cultura especificada en actual hilo de ejecución.

    Por ejemplo, creamos el fichero predeterminado (en Inglés) y otro para español sin tener en cuenta el país. (MLTest.resx y MLTest.es.resx  (para cualquier cultura con lenguaje español)) 

  4. Incluimos en el conjunto de ficheros de recursos todos los recursos que nuestra aplicación va a necesitar. 
    En nuestro caso solo uno con nombre «GREETING«. 
  5. Incluimos desde una vista ( por ejemplo Views/Home/Index.aspx) la forma de consumir el recurso:

    <%
    =Resources.MLTest.GREETING%>

    Fuertemente tipado, Intellisense, detección de errores en tiempo de compilación…(da gusto verlo!!)

Bueno, pues ya tenernos una aplicación que nos muestra los recursos en base a la cultura del Framework instalado (en el servidor Web en este caso) que se encarga de especificar la cultura del hilo de ejecución.

Ya es algo, pero no es lo que queremos, verdad?

(El que dude que revise la misión que hemos puesto arriba)

2- Estableciendo la cultura del hilo en ejecución

Ya sabemos que debemos establecer la cultura del hilo de ejecución para que el Framework cargue el fichero de recursos adecuado, pero ahora la pregunta es cuando?

Recordar que cada petición empieza de nuevo y no recuerda las anteriores ( HTTP es stateless). Indagando un poco en la MSDN podemos ver que la clase Controller (de la que derivan nuestros propios controllers) de la implementación del MVC de Microsoft especifica dos métodos virtuales que nos van a resultar muy interesantes:

  • OnActionExecuting
    Se ejecuta antes de la llamada a cualquier Action Method.
  • OnActionExecuted
    Se ejecuta después de la llamada a cualquier Action Method. (obvio, no?)

Como debemos de establecer la cultura cada vez que nos realicen una llamada a cualquier action method de cualquier controlador, lo ideal es crear un controlador base del cual hereden todos los demás y sobrescribir en el método OnActionExecuting el mecanismo para restablecer la cultura. Nuestros controladores harán así transparente al resto de la aplicación las particularidades de trabajar con estado. También podríamos usar un atributo aplicado sobre la clase base y en la implementación del atributo especificar que implementa el interfaz IActionFilter si lo queremos hacer un poco mas AOP que OO.

En la implementación que os dejo utilizo un atributo con el que decoro la clase base (Al gusto!!) 

En el ejemplo:

La clase base de los controladores:

[SetCulture] 
public class BaseController : Controller 
{ 
... 
}

Y en la implementación de la clase del atributo programo como establecer la cultura seleccionada en el hilo activo:

public class SetCultureAttribute : FilterAttribute, IActionFilter 
{ 
	public void OnActionExecuting(ActionExecutingContext 
actionContext) { CultureHelper.SetCulture(GetCurrentCulture
(actionContext), actionContext.
HttpContext.Session) } ...

Para almacenar la cultura especificada entre las llamadas podemos emplear diferentes mecanismos, en este ejemplo el flujo de trabajo será el siguiente:

  1. Revisar si tiene alguna cookie de nuestro sitio que especifique la cultura.
  2. Comprobar la variable de sessión de la cultura.
  3. En caso de no disponer de ninguna de las dos informaciones anteriores, preguntar por las culturas configurados en el navegador y presentar la interfaz de usuario en base a la primera coincidencia que se produzca.

En la implementación que os dejo del proyecto podéis consultar los métodos que he creado para realizar dichas acciones, son muy sencillos y podéis modificarlos al gusto.

Los principales métodos son:

  • GetCurrentCulture de la implementación del atributo, que consulta la información previamente almacenada en base al flujo que hemos comentado.
  • CultureHelper.SetCulture que recibe la cultura a asignar y el objeto intrínseco Session Object y carga cultura en el hilo actual de ejecución.

Aquí nos aparece otro problema.(Que raro, eh?)

Si el usuario es la primera vez que accede a la Web no tiene cookie ni session establecida. 

Para intentar que la aplicación sea lo más “inteligente” posible, recogemos del navegador las culturas que tiene especificadas y las cruzamos con una sección especifica del fichero de configuración creada a tal efecto.

Por ejemplo, si el usuario tiene Chino e italiano necesito determinar si mi aplicación dispone un algún fichero de recursos que da soporte a alguno de los mismos. Para ello me creo una section en el fichero de configuración y un handler que lo soporte que especifique una lista de culturas soportadas y su orden de aplicación. (Así vemos también como poder realizar esta tarea.)

Observar que la tarea no es tan sencilla como coger el idioma y asignarlo al hilo y dejar que el Framework resuelva. (si no lo puede resolver que aplique la predeterminada) puesto que si el usuario tiene, entre todos los lenguajes del navegador, uno que tenemos implementado nos lo estaríamos saltando. (Por ejemplo Chino, Italiano, Español, Ruso)

En el fichero de configuración especificamos:

<
configSections>

<section name=«EnabledLanguages» type=«AndoniArroyo.MLTest.
Controllers.Infrastructure.Configuration.EnabledLanguagesSection,
AndoniArroyo.MLTest»
/>

</
configSections>

además incuimos la citada sección:

<!–Especifica el conjunto de culturas con el que trabaja la aplicación. La última es la cultura por defecto–>
<EnabledLanguages>
<Languages>
<add title=«Spanish» code=«es-ES» />
<add title=«English» code=«en-GB» />
</Languages>
</EnabledLanguages>

Para que la aplicación pueda manejar esta section debemos implementar el handler que la maneje:

namespace AndoniArroyo.MLTest.Controllers.Infrastructure.
Configuration { public sealed class EnabledLanguagesSection : ConfigurationSection { [ConfigurationProperty("Languages", IsDefaultCollection = true,
IsRequired = true)] internal LanguageElementCollection EnabledLanguages { get { return (LanguageElementCollection)this["Languages"]; } } } }

Estos lenguajes será los que tendrá en cuenta el método que intenta cargar el lenguaje desde la información recogida del navegador.

Pues ya casi lo tenemos.

Nos queda por ver como el usuario puede explicitamente modificar la cultura con la que desea trabajar en la aplicación. Visto todos lo anterior la cosa es fácil, no? Basta con crear un action method de modificación de la cultura y en la implementación del mismo llamar explícitamente al método de establecer cultura con el parámetro recibido. (CultureHelper.SetCulture pasándole la cultura especificada por el usuario y la referencia al objeto de sesión…)

Recapitulando, hemos visto unas cuantas cosas:

  • Hemos observado los mecanismos de globalización que nos da el .NET Framework y como extenderlos para nuestras necesidades en web.
  • Definido una política de establecer la cultura activa de la aplicación intentando que la aplicación se adapte al usuario.
  • El punto donde cubrir las características de sin estado del HTTP para establecer la cultura especificada por el usuario.
  • Hemos creado secciones personalizadas en el fichero de configuración y hemos visto como manejarlas.

Y como extra lo prometido el ejemplo con todas estas ideas en acción.