Mmmm… no parece la gran cosa. Pero eso es porque no lo han visto en su página original.
La verdad que un video así los hace merecedores de una compra al por mayor.
Visto en FayerWayer.
Mmmm… no parece la gran cosa. Pero eso es porque no lo han visto en su página original.
La verdad que un video así los hace merecedores de una compra al por mayor.
Visto en FayerWayer.
Antes que nada: si usted, querido lector-programador de .Net, no tiene y/o no quiere tener nada que ver con el .Net MVC de Microsoft siga leyendo de todas maneras, que la cuestión va mucho más allá de eso y es interesante.
El hecho es que en el .Net MVC de Microsoft, las vistas no tienen codebehind. En realidad no es que no tengan o no puedan tener, sino que por defecto no lo tienen, siendo el estilo de codificación sugerido para las vistas más o menos como lo muestra esta imagen:
Es decir, utilizamos los viejos y conocidos tags <% %> para escribir código C# inline en medio del aspx, el javascript y el html. Los controles del lado del servidor (TextBox, CheckBox, DropDown) han sido reemplazados por un helper que utilizamos para no escribir un montón al implementar tareas comunes (como ponerle un valor a un input type=text) pero que es sólo eso, un helper.
La verdad que es un cambio importante en la forma de pensar y escribir una página web en .Net. Personalmente a mí me ha costado muchísimo adaptarme (y, les adelanto, me he dado por vencido y vuelto al codebehind). Indagando un poco sobre este tema me encontré con que, obviamente, no soy el único.
Pero vamos a las opiniones, y primero las que están en contra (del codebehind): Steven Smith, comentando la reaparición del codebehind en las próximas versiones del framework, dice en su blog que, lisa y llanamente, Codebehind Files in ASP.NET MVC are Evil. Steven no es ningún improvisado, hay que pensar en sus razones (el resaltado es mío):
The problem with having a codebehind file for a View comes down to temptation and habit. If it's there, anybody who's been using "classic ASP.NET" for the last 8 years or so is accustomed to putting all kinds of things into the ASP.NET codebehind files. From click handlers to Page_Load to event wireups to changing display settings based on the value of a data item - most web forms apps have a ton of logic in their codebehind files. And that's great - but not typically how it should be done with ASP.NET MVC.
[…] If having the codebehind file available by default is a temptation to stray from the canonical correct MVC path, then not having it there by default would help most developers do things the right way without thinking about it.
Encontré, en el mismo set de resultados en google, una respuesta de Luis Abreu posteada en su blog en una entrada titulada (obviamente) Codebehind files in ASP.NET MVC *ARE NOT* evil (el resaltado es mío).
Before going on, I understand Steve’s point of view: keeping the codebehind files might lead you to put code that belongs to the controller on the view. As I said, I understand, but I want to believe that a good developer will understand MVCs strenghts and will, after some time, have no doubts on where some behaviour (code) should go.
On the other hand, I’m not sure that removing the codebehind file will be enough for stopping a “bad” programmer […]
Luis tiene un sueño, que yo comparto:
Let me share with you a dream which makes me stick harder with the “pro-codebehind” approach […]
Imagine seeing no more of those <% %> floating everywhere on your aspx page…having a clear separation between markup and code, which doesn’t happen with the current view engine. If you want to really imagine it, just compare the old spaghetti ASP code with the elegance of the ASP.NET web forms page but don’t think about events and view state…just concentrate on the markup. Now be honest: do you preffer the spaghetti or the web form’s approach […] ?
Yo mismo no lo hubiese expresado mejor. Pero esa es mi opinión, es hora de comenzar otra sección.
Si hay algo que no me gusta en cuestiones de arquitectura (y de desarrollo de software en general) son las opiniones categóricas: “los tags <% %> son el demonio”, “el codebehind es el demonio”, “todo el sql debe estar en la base de datos”, “los parámetros opcionales son el demonio”, “los objetos no deberían tener propiedades”… un largo etcétera. Me parece que se confunden directivas de diseño con reglas inmutables escritas en piedra, tiendo a pensar que el que las pronuncia no está pensando en la situación actual y real del día de hoy sino evadiéndose hacia un mundo perfecto donde la arquitectura y las necesidades son la misma cosa.
Yo soy más del estilo de aquellos Principios de Diseño de Guido van Rossum que publiqué en uno de mis primeros posts. Voy a traer a colación los que me parecen relevantes:
No hay absolutos, hay momentos en los que hay opciones, herramientas entre las que hay que elegir, ventajas y desventajas. Con Rick Hunter (más que experimentado arquitecto) solíamos terminar este tipo de discusiones con la frase “no nos queda otra… hay que pensar”. No queríamos pensar, queríamos una regla mágica que nos solucionara la vida… si existe la verdad es que nunca la encontramos.
Volvamos al caso. Piensen en los cuatro puntos de Guido, recuerden –si es que han trabajado con él- ASP 3.0. Ahora vuelvan a mirar la imagen de arriba e imaginen esa sintaxis en la implementación de una página realmente compleja. Las interfaces de la vida real son complejas, los usuarios quieren interactividad, quieren ver lo que pasa cuando cambian valores, quieren cosas que llamen la atención sobre los errores lo antes posible, no son un formulario en el que el tipo introduce datos, aprieta un botón y se va a su casa.
Yo veo un infierno de colores en el que se mezclan C#, markup de .Net, html, javascript, y cuanta cosa se nos ocurra meter en una página web. Por cierto, Guido también dice:
Yo creo que sería mejor tener todos esos lenguajes separados que revueltos e interactuando juntos en el mismo lugar.
Steven Smith le teme a los inexpertos, a los viejos y a los malos programadores (todos les tenemos miedo). Respecto de los primeros, siente que nunca abandonarán .Net “tradicional”, y que si abre esa puerta van a implementar toda la funcionalidad en la vista, dejando los controladores vacíos. A los últimos quiere obligarlos a hacer las cosas bien.
Eso es imposible. Un mal programador hará las cosas mal (no “más fácil” o “más difícil”, sino simplemente mal) independientemente de dónde esté picando código. Y eso es inevitable. Si hubiese una forma de forzar a un programador a hacer bien las cosas, entonces su trabajo sería reemplazable por una herramienta automática, y por lo tanto inútil… en general no es ése el caso.
El “malo”, ya lo dije, es incorregible y sólo podemos alejarnos de él o a él de nosotros. Al resto, a los inexpertos o a los “viejos” que vienen de otras tecnologías basta con mostrarles que es mejor separar la lógica entre vista y controlador, seguirlos, corregirlos, darles las herramientas y los criterios para elegirlas.
No creo que el objetivo un framework sea el control o la restricción. Su objetivo es estructurar, proponer un orden, facilitar el desarrollo, no impedirlo. Un buen framework no es aquél en el que no se puede programar mal, sino aquel en el que que programar bien es más fácil.
Volviendo a MVC: yo voy a cambiar los <%=Html.Input(…)%> por controles, y a agregar el codebehind para establecer sus valores e implementar la lógica de presentación en forma separada del html. Porque es más prolijo, más lindo, tal vez disperso pero mejor que denso, tal vez más complejo, pero mejor que complicado.
¿Y a uds. qué les parece?
Silencio de radio estos días, ¿lo notaron? Tal vez sí –eso espero-, ya que corté un período de extrema verborragia que abarcó las últimas semanas, aunque –reconozco- con más relleno que ideas.
El relativo silencio tiene su origen en una sucesión de días –y noches-febriles en los que se juntaron el inicio de las clases -con su carga de revisiones, correcciones e improvisado planeamiento (tal cosa existe)- y el inicio de un nuevo proyecto en el trabajo, que es lo que quería comentar en este post, y –por fin- voy al grano.
Este proyecto es mi primera aplicación desarrollada con el ASP.Net MVC de Microsoft y es también el primero que se desarrolla con esta tecnología en la empresa para la que trabajo.
Creo que puede ser interesante ir comentando a medida que avanzo. Muchos de ustedes son programadores y seguramente han trabajado, jugado o leído algo sobre el MVC de Microsoft, y saben muy bien que el partido se juega muy diferente al entrenamiento con ejemplos y tutoriales: la funcionalidad requerida no es negociable (salvo en pequeños detalles), hay que terminar en tiempo y forma, y la presión de no saber (no saber estimar, no saber cómo se hacen tareas comunes, no saber si el framework cubre o no determinada necesidad, no saber si algo es fácil o difícil…) y tener que cumplir, pesa.
El proyecto es pequeño, dos programadores con una agenda de aproximadamente cuatro semanas de trabajo. Es una típica aplicación de gestión del estilo pantalla-contra-base-de-datos, con dos o tres complicadas y el resto ABM’s. Pero cargamos también con cierta obligación de entregar como subproducto la experiencia plasmada en herramientas puedan reutilizarse y métodos y prácticas estándar que puedan transmitirse… y errores que no vuelvan a repetirse.
Somos dos programadores senior, y me toca aportar la experiencia previa de haber trabajado con el patrón MVC los últimos 3 años, si bien implementado sobre un framework desarrollado ad-hoc y mantenido, corregido y mejorado constantemente por el mismo equipo durante ese largo período de tiempo.
Ya dije que trabajamos sobre C#, sobre el .Net 3.5 con el MVC 1.0, resta aclarar que la aplicación trabaja sobre Oracle. Demasiadas innovaciones para un sólo proyecto (en mi caso), así que decidí implementar entidades y acceso a datos con plantillas de CodeSmith, una herramienta de la cual no estoy enamorado pero manejo, y que para mí representa un problema menos.
De lado del cliente utilizamos el framework de javascript jQuery (algo sin lo cual ya no vale la pena vivir), con jQuery UI y el plugin jqGrid (una súper grilla que hace de todo).
Para ser sincero tengo que aclarar que robé la estética (hojas de estilo y demás) de otra aplicación ya desarrollada para el mismo cliente, así que no puedo opinar demasiado en cuanto a las facilidades para el diseño de estas herramientas, salvo que son muy fáciles de reproducir copiando y pegando archivos.
Estoy comentando aquí la curva de aprendizaje del patrón MVC en sí mismo: cuánto se tarda en aprender los conceptos, los términos, la nomenclatura y darse un par de palos contra la pared hasta llegar a ese punto en el que “vemos en MVC”, es decir cuando logramos encajar intuitivamente las funcionalidades requeridas dentro del patrón.
Así que no vale mi experiencia, sino la de mi compañero de proyecto –programador senior con buena predisposición y mucha experiencia con .Net-, que creo que luego de tres días completos de idas y vueltas (más o menos) ya le está tomando la mano (¡que comente!).
Para recomendar: comenzamos con estos videos cortos de Microsoft, un muy buen punto de partida.
Mi primera impresión fue “esto es buenísimo, es más o menos la misma arquitectura que venía implementando a mano, con los detalles escabrosos ya resueltos y muy bien integrada con el Visual Studio”.
Pero apenas completados los primeros tutoriales (de esos en los que armamos una aplicación -tan funcional como inútil- de punta a punta en 5 minutos) y comenzado el trabajo “en serio”, aparecieron las falencias. Lo que está está razonablemente bien implementado pero hay algunas cositas bastante desagradables, y mi impresión actualizada es que “le faltan cosas”, y que probablemente la próxima versión (2.0) represente una mejora muy significativa.
Puntos fuertes: la sobria estructura de la plantilla inicial nos ayuda a mantenernos organizados, una muy bien implementada relación entre vista y controlador, sencilla y flexible a la vez, la extensibilidad del framework en general (siempre hay dónde meter los dedos para adaptarlo a nuestra forma de trabajo). Por otro lado hay una comunidad grande y muy activa, con muchos y muy buenos recursos.
Por lo menos tengo que reconocer que el resultado final, el html, es mucho… muchísimo más razonable y manejable que el que produce como salida el .Net “sin MVC”: no más viewstate, no más update panel, no más ver una cosa del lado del servidor y otra (compleja, pesada y que encima no funciona) del lado del cliente.
Puntos débiles: el lado javascript, concretamente en lo más fundamental: carece de un método de conexión sencillo que soporte AJAX entre el cliente y el servidor. Las librerías de Microsoft… miré un poco la documentación y bien gracias, el código ni lo abrí. Como siempre, una copia berreta y muy complicada de algo que es muy fácil de implementar con herramientas ya existentes (en breve la adaptación de la serie al MVC). jQuery está ahí, viene con el paquete casi como una sugerencia, pero no vi ningún tipo de integración real (si alguien puede desasnarme éste es el momento).
Otra que no me gustó es cómo quedan –por defecto- las vistas cuando hacemos pantallas “reales” (y no formularios tontos de ejemplo)… esos “helpers” me recuerdan mucho a ASP 3.0 y la verdad que la legibilidad final, si implementamos las cosas tal como dicen los tutoriales… y… es una mezcla horrorosa de javascript, html y tags del lado del servidor. Pero, veremos en breve, eso es salvable.
Así que, en resumen: si ya conocemos el patrón MVC y también el framework .Net, veremos que ésta implementación es un grandioso punto de partida que nos resuelve lo básico, un poco más, y nos da la base para armar un esquema de desarrollo realmente ágil.
Pero no está regalado, hay que hacerlo. Los detalles tras bambalinas (vistas tipadas, implementación de validaciones del lado javascript, helpers, bindeo) se vuelven un tanto complejos cuando se los quiere forzar por fuera del muy limitado uso estándar para el que están pensados pero, como dije antes, todavía no tuve un problema al que no le haya encontrado solución con un poco de ayuda de google.
Yo voy… pongámosle una semana a tiempo completo, y me considero en forma para esta pequeña primera aplicación con intenciones de sentar una base para algo mejor.
Mucha teoría, mucho discursito en el aire, ya lo sé. Voy a ir armando algunos posts más complejos con ejemplos y algunas soluciones implementadas. No hay mejor manera de validar la razonabilidad de un esquema que mostrarlo y prestar oído a los comentarios.
La gente de Manolith ha recopilado estos sitios en su entrada 20 of the Worst Designed Websites In the World.
Si bien hay algunos que -en mi opinión- no acumulan suficiente mérito como para ser incluidos en semejante “lista de la vergüenza”, el resultado final del recorrido es un fuerte mareo y dolor de cabeza.
Lo malo no es ser incapaz de crear un buen diseño –yo soy incapaz de ello- sino el mal gusto liso y llano –y la falta de un poco de sentido común- que impide al creador del sitio (la frase “diseñador del sitio” está fuera de lugar, queda claro que no todo el que diseña es diseñador) reconocer que algo no está del todo bien.
Un par de ejemplos:
A ver si alguno de los incluidos en esta lista se decide a pedir ayuda profesional, o por lo menos a robar inspirarse en algún sitio un poco más sobrio y bien diseñado.
Encontrarán la lista completa y los links a los sitios (si es que se quedaron con ganas) en el artículo original.
Visto en Menéame.
No es el uso, es el abuso, que puede transformarse en delirio.
Mi opinión sobre el uso (resumen de los links anteriores) está muy bien condensada en uno de los puntos del artículo: XML es perfecto para para crear documentos estructurados que puedan ser manipulados “como cajas negras” por aplicaciones o, más apropiado todavía, interpretados fácilmente por seres humanos. Por ejemplo:
…pero si tenemos que compartir una gran cantidad de datos entre aplicaciones con una estructura preestablecida… ¿Para qué especificarla junto a los datos mismos si está, justamente, preestablecida?
Tal el caso que se ilustra en how xml threatens big data, un artículo reciente de Dataspora Blog (en inglés) donde el autor comenta brevemente su fracasado intento (enderezado a tiempo) de usar XML como formato para compartir grandes cantidades (ahí el problema) de datos entre aplicaciones.
En resumen, tres razones para el fracaso:
XML aumenta la burocracia: creación, parseo, tipado, conversión…
El tamaño importa. XML encaja bien para documentos (cantidades de información manejable por seres humanos), pero no para datos (cantidades de información manejable por aplicaciones).
La complejidad tiene su costo. XML es mucho más complejo que otros formatos (CSV, JSON).
… y una propuesta de tres reglas para “Rebeldes del XML”:
¡Basta de inventar nuevos formatos XML!
Obedece la regla de los 50 15 minutos: no debería llevar más de 50 15 (¡ay! mi inglés) minutos aprender el formato.
Adoptar modelado de datos tardío (Lazy Data Modeling), un concepto comparable a la “evaluación tardía”: grabar los datos como son y dejar su interpretación (tipado) para el momento en el que se los requiera, implementando esa interpretación de acuerdo a las necesidades del caso. Es un un punto que tal vez merece más reflexión y que da para mayor discusión.
Ése es el resumen, mucho más detalle por aquí, en el artículo original.
| “A modern paradox is that it’s simpler to create complex interfaces because it’s so complex to simplify them.” – Pär Almqvist |
Desarrollados en el artículo original (en inglés): 10 User Interface Design Fundamentals (vía @DeliciousHot).
Cuando salió Silverlight me entusiasmaron bastante las posibilidades del “chiche nuevo”. Por fin aquellos que nos dedicamos más a la programación que al diseño gráfico tendríamos una alternativa a Flash (demasiado “visual” para mi gusto por el código) para crear interfaces ricas del lado del cliente.
Pero un jugador rezagado cambió todo eso: Javascript. Siempre estuvo ahí, no recuerdo una web sin él, pero en la época del dominio del IE 5 apenas era útil para hacer un par de validaciones y algunos efectos muy menores.
¿Cual era el problema? En ese momento, ninguno. Uno creía que javascript era para eso, y que para hacer cosas más complejas o vistosas estaban Flash u otras tecnologías similares.
Hoy, lo sabemos, el problema era el IE. La gente de Microsoft apuntaba para otro lado y el hecho de que su motor de javascript fuese una carreta no parecía importarles demasiado. Firefox empezó a cambiar el rumbo y desató una carrera en la que el IE resultó un gran perdedor y Javascript, de la mano de Firefox, Safari y Chrome, el ganador absoluto.
Mientras Microsoft intenta desesperadamente poner el IE al día y Silverlight queda relegado al lugar de herramienta para programadores (que ocupa muy dignamente), lejos incluso de la menguante popularidad de Flash, las posibilidades en Javascript son cada vez más amplias. De la mano de prototype, jQuery, mooTools y otros frameworks ya no hay mucho que javascript tenga que envidiarle a Flash o Silverlight en materia de posibilidades.
Y si no me creen vean 16 Impressive Flash-Like Javascript Animation Inspirations, Tutorials and Plugins. La gracia no es tanto la complejidad de lo que se presenta (aunque algunos ejemplos son realmente increíbles), sino la aplicación del lenguaje a la creación de páginas con fuerte acento en el diseño gráfico sin plugins ni descargas adicionales, sólo el viejo y querido trío HTML+CSS+Javascript.
world of merixStudio sorprende por la suavidad del movimiento:
arnaud-k.fr utiliza muy sutilmente las posibilidades del plugin de jQuery jparallax:
Además de los ejemplos sorprende la cantidad y calidad de librerías para animación, simulación y efectos que han ido apareciendo en estos últimos tiempos. 16 Impressive Flash-Like Javascript Animation Inspirations, Tutorials and Plugins es una muy buena recopilación para tener en cartera. No se lo pierdan.
La semana pasada escribía sobre el paradigma que rodea cualquier actividad, sobre lo importante que resulta el conocimiento y la comprensión de éste para desarrollar con éxito un software alineado con el negocio, y lo difícil de su transmisión al equipo de desarrollo.
Rara vez es explicitado en manera alguna –decía- y cuando lo es –cuando pretende serlo- se materializa en forma de frases de compromiso que rara vez tienen que ver con la cosa real que dicen reflejar. Es un poco como la visión a la que tanta importancia le dan las normas de calidad: pocos saben qué es y de poco sirve saberlo -salvo para certificarse en algo- pero no se puede tener éxito sin ella. Análogamente, los negocios exitosos no son los que saben qué es un paradigma sino los que tienen un paradigma exitoso. Siempre es bueno racionalizar, poder poner en palabras, explicitar, pero lo indispensable es tener qué explicitar.
El problema es, volviendo al primer párrafo, que el equipo de desarrollo necesita conocer el paradigma real que subyace al modelo de negocio para derivar de él lineamientos concretos con los que diseñar un software. Imaginemos por un segundo que creamos un sistema de gestión para una empresa de la industria farmacéutica partiendo de que, tal cual rezan sus documentos sobre políticas internas, “la base de nuestro negocio es proveer los medicamentos para curar todos los males de la humanidad”… Imaginemos ahora la cara de los directivos cuando mostremos nuestros reportes y panel de control de gestión conformados por indicadores tales como tasa de mortandad, calidad de vida, reducción de casos de tal y tal enfermedad… cuando midamos el éxito de un producto de acuerdo a la cantidad de pacientes que se han curado gracias a él… “¡Hey! ¿Dónde está el estado financiero? ¿Y la cotización en bolsa? ¿Dónde se muestra el ROI?”.
Entonces, para conocerlo y comprenderlo cabalmente se requiere estar ahí. Es tarea propia de analistas funcionales, representantes comerciales y demás. Pero, normalmente, los programadores no pueden estar ahí y la solución propuesta por metodologías ágiles como XP –tener al usuario dentro del equipo- no siempre rara vez es posible. Surge entonces, como siempre en el desarrollo de software, el problema de la comunicación.
Pero… ¿No pueden estar ahí? ¿Nunca? ¿Ninguno? ¿Ni de visita? ¿Ni por un rato? Difícil de creer. A pocos se les da la oportunidad de conocer a los usuarios en su entorno real de trabajo. Incluso cuando esto es posible, incluso cuando es sencillo encontrar la oportunidad. Más raro aún es que esta actividad sea establecida formalmente entre las tareas de un programador durante el proceso de desarrollo.
Para los que han tenido esta experiencia -como parte de una visita formal o no- ha sido casi reveladora. Día a día, inevitablemente y de forma intuitiva, encerrados tras una muralla de código, los programadores derivan, imaginan, se forman una imagen del negocio para el cual programan. Lo hacen a partir de los requerimientos, del diseño propuesto para las pantallas, de las funcionalidades. Pero es muy difícil que esta imagen, condicionada por su experiencia y sus propios paradigmas, coincida con la realidad.
Creo que es una práctica fácil, barata y muy productiva el llevar a los programadores “de paseo” al entorno del cliente en cualquier oportunidad que se presente (oportunidad para tomarles fotos vestidos decentemente… ¡o hasta de saco y corbata!). ¿Para qué? Para que conozca a los usuarios, su nivel, su entorno, su trabajo. Por ejemplo…
¿Son usuarios avanzados en el uso de una computadora en general? Hace ya mucho tiempo (no creo que esto pueda suceder ahora) me di cuenta de que el significado de los íconos más básicos y estándar –guardar, abrir- de la barra de tareas del sistema eran completamente oscuros para el usuario de nuestro sistema, que utilizaba sólo el menú porque allí decía “Abrir”, “Guardar”, haciendo todo de una manera muy incómoda. El detalle cool (para mí) de poner íconos grandes y sin texto hacía que la barra fuese completamente inútil. El gesto –tan natural para mí- de poner el cursor encima de un ícono para ver una descripción de su funcionalidad era imposible en esta persona.
¿Son jóvenes, personas mayores? ¿Necesitan algún tipo de accesibilidad para utilizar el sistema? Allá lejos y hace tiempo tuve un compañero de trabajo, un contador –creo- que era tan corto de vista que tenía que usar la lupa… y les aseguro que el sistema se veía MUY diferente de esa manera.
¿Su trabajo les exige interacción constante con el sistemao es más bien esporádica? ¿Tienen otros sistemas abiertos? ¿Tienen que consultarlos alternativamente? ¿Llevan a cabo varias tareas al mismo tiempo? Esa transacción, que nosotros imaginamos como una rápida carga de datos y un enter final tal vez requiere de varios minutos entre ingreso e ingreso para conseguirlos. Otra de las cosas impensadas que vi fue un usuario que primero copiaba todos los datos necesarios a un archivo de texto. Lo hacía desde diferentes planillas, sistemas, desde el navegador y luego abría el sistema de presupuestos y los pegaba desde allí. ¿Por qué? Era obvio, porque temía perderlos y el sistema no le dejaba grabar el registro –aunque sea localmente o en un repositorio temporal- si no tenía los datos completos. Esta era una funcionalidad que yo había discutido tercamente por demasiado problemática en relación al beneficio –según mi propio punto de vista- que representaba para el usuario. Cuando lo vi no discutí más.
¿Están cómodos? No es lo mismo utilizar el sistema localmente que hacerlo a través de un escritorio remoto, o sentado cómodamente en un escritorio que de parado frente a un rack de servidores.
Siempre hay, en definitiva, alguna cosa rara. Se me dirá que es cuestión de hacer lo que los analistas o diseñadores nos piden y listo, que al fin y al cabo ellos han estado allí –o ha leído un documento redactado por alguien que ha hablado con alguien que estuvo allí-, pero eso nos limita a lo que ellos consideran fácil o posible.
Esto último me hizo acordar algo que había escrito en La “respuesta” a “¿Cuál es el error?”, la ambigüedad, su resolución y, finalmente, la realidad:
[…] ya lo dijimos, vivimos en un mundo imperfecto. Muchas veces (en todo proyecto real esta situación es más que frecuente) el cliente no está disponible […] o no entiende la pregunta. ¿Entonces?
[…] hay veces que hay que adivinar y seguir adelante, rellenar los huecos en las especificaciones apelando al sentido común […]
Cultivar el “sentido común” -al que apelan los programadores cuando tienen que inventar algo para tapar algún hueco- mostrándoles “la vida real” del proyecto para el cual trabajan ahorraría innumerables idas y vueltas entre desarrollo y producción y seguramente haría que surjan ideas y mejores posibilidades para el sistema.
Los desarrolladores somos –¿hipótesis?- ante todo humanos, luego usuarios, luego desarrolladores.
Como humanos –entre otras cosas-, tendemos a sobrevalorar la propia experiencia. Por ejemplo, si el sistema que desarrollamos nos es fácil de utilizar solemos atribuirle esta característica obviando el hecho de que hemos aprendido a utilizarlo “desde atrás” (es decir, desde el código, el diseño o los requerimientos) y no “desde adelante” (desde la pantalla, los manuales o la capacitación). Para cuando nos enfrentamos a la pantalla de inicio ya sabemos casi de memoria todo lo que sigue. Abstraerse de este conocimiento es –por más que me juren y recontrajuren- imposible, y es por eso que nuestras pruebas y experiencias personales son bastante objetables como medida de lo que sucederá en el mundo real. Esto se aplica, con variaciones, tanto a desarrolladores como a analistas, testers, líderes de proyecto y a cualquiera implicado en el desarrollo de software (excepto, claro está, al cliente y al usuario).
Además de humanos –si es que damos por válida la hipótesis-, somos usuarios de sistemas de un determinado negocio: entornos de desarrollo, clientes de bases de datos, herramientas de diseño y documentación de requisitos, entre muchos otros, conforman el software de soporte al negocio del desarrollo de software. Negocio en el que estamos inmersos y que, como todos, tiene su paradigma establecido y materializado en la forma de determinados estándares: flujos de trabajo, herramientas visuales, disposición física de los objetos en una oficina… todo lo que nos rodea se deriva de éste en alguna medida.
La importancia de estos elementos –paradigma y estándares- que sobre el papel parecen un conjunto arbitrario de caprichos funcionales -¿por qué Ctrl+U y Ctrl+Shift+U? ¿Por qué un árbol y no una serie de listas encadenadas?- radica en que condicionan toda nuestra visión de la realidad (¡vaya si estamos condicionados por los paradigmas de nuestro negocio!). Los sistemas -si pretenden ser exitosos- deberán respetar –o revolucionar, pero esto es más difícil-, sobre todo en la interacción con sus usuarios, los paradigmas del negocio para el que fueron diseñados.
Como desarrolladores que somos –de eso sí estamos seguros- nos sería imposible, si estuviésemos librados a nuestro criterio, no aplicar el paradigma y los estándares propios del negocio al que pertenecemos –el desarrollo de software- a los sistemas que desarrollamos.
El problema es que, como establecimos más arriba, otros negocios o actividades tienen estándares y paradigmas diferentes. Internalizarlos es prácticamente imposible (deberíamos ser, por ejemplo, tan usuarios de distintos sistemas de gestión como lo somos de distintos entornos de desarrollo, tanto como lo es un empleado administrativo que ha transitado por diferentes empresas y puestos). Sólo podemos pretender, a lo más, conocerlos. Y para ello se requiere de una experiencia… “presencial”. Es la experiencia que trata de transmitir el analista funcional, el área comercial o quienquiera que tenga contacto directo con el cliente.
Pero un modelo mental es algo realmente difícil de describir, los estándares que se deriven de éste serán en su gran mayoría reglas y prácticas comunes y no estarán explicitadas en ningún lado. Es, en definitiva, difícil de transmitir. Por todo esto, cuantos más intermediarios haya entre aquellos que conocen a los clientes y usuarios y los desarrolladores, más probabilidades habrá de que nos apartemos del paradigma y los estándares a los que ellos están acostumbrados.
Allá lejos y hace tiempo, creo que por el año 2001 (tiro de memoria) Microsoft lanzaba la séptima versión mayor del Visual Studio (el primer “puntonet”) y con ella prometía llevar a los desarrolladores “de aplicaciones de escritorio” al mundo de las “aplicaciones web”.
Yo (supongo que junto a muchos otros), que venía desarrollando “aplicaciones web” de gestión en ASP 3.0, me sorprendí gratamente con el chiche nuevo que me permitía (entre otras cosas) separar fácilmente el código de la presentación (aunque nada me lo impedía antes) y crear clientes en HTML “como si fueran formularios de Windows”, con controles, eventos y todo eso.
Lleno de entusiasmo, empecé a tirar controles sobre el diseñador y a escribir código para los eventos. Casi lloro al apretar F5 y ver a la aplicación levantarse mágicamente en un servidor local lista para depurar paso a paso, “como si fuera un formulario” (también se podía antes, pero había toda una burocracia previa). Todo parecía fácil y natural.
Pero el sueño dorado se convirtió en una terrible pesadilla cuando, apenas superadas las primeras pruebas triviales, conocí a dos horrendas criaturas, dos verdaderos abortos de la naturaleza: Postback y su deforme hermano siamés, Viewstate.
Postback envía toda la información contenida en la página al servidor, obligándola a recrearse constantemente una y otra vez para acometer desde la más compleja a la más trivial de las tareas: cambiar el color de una etiqueta, mostrar un mensaje de error de validación, lo que sea. Para eso necesita a su inseparable hermano Viewstate, que almacena… muchas cosas, un montón de cosas, todas las cosas. Creo que en el Viewstate de una página ASP.Net “creada como un formulario de Windows” se encuentra el sentido de la vida, el universo y todo lo demás, pero que es inhallable.
Metiéndome un poco más en la cosa, empecé a darme cuenta de lo que Microsoft había hecho para “facilitar las cosas” en el desarrollo web. No había magia detrás de todo ello sino un conjunto de complicadísimos y muy poco elegantes hacks que hacían de aquello tan fácil y divertido llamado HTML+Javascript un verdadero infierno.
XMLHttpRequest y esa gran bolsa de gatos llamada Ajax ya era utilizada por los sitios más modernosos dando origen a las RIA's y se perfilaba como el estándar que un usuario final más o menos exigente esperaría de allí en más. Yo lo había utilizado bastante, de una manera muy rudimentaria pero con muy buenos resultados (visuales, que por adentro, ¡madre mía!). Al querer combinarlo con el modelo propuesto por ASP.NET me metí en verdadero laberinto. Si antes las cosas me parecían desprolijas ahora se me hacían imposibles.
Un (largo) tiempo después apareció Atlas… baste decir que me cuesta (y desisto de) encontrar una referencia a esas primeras versiones de… lo que sea que haya querido ser (¿herramienta? ¿plantilla? ¿paradigma? ¿framework? ¿manotón de ahogado?). Lo que es seguro es que resultó otro conjunto de engendros mutantes a los que Microsoft les dio temprana y prolija sepultura (cambiándole el nombre, como suele hacer). Pero puedo resumirlo fácilmente: no era otra cosa que Postback y Viewstate (y otro ejército de hacks berretas) actuando en las sombras para no asustar al desarrollador con su horrible refrescado en cámara lenta.
Creo que me gané el derecho a adjetivar a esa visión del desarrollo de una aplicación web (tirar controles a un diseñador y codificar eventos) como “un verdadero desastre”, una obra maestra en hacer difícil lo fácil e imposible lo (no muy) complejo. Derecho que me gané (y ahora ejerzo) por haberlo intentado seriamente. Realmente intenté (Rick Hunter es testigo) desarrollar una aplicación web razonable siguiendo ese modelo. Y fracasé, una y otra vez. Tal vez soy yo, tal vez no le encontré la vuelta, pero así fue.
Fue hora de separar los tantos: el Framework .Net, desde su primera versión, fue y es una herramienta fabulosa que mejora en cada versión, eso que quede claro. Pero esa no era la forma de utilizarla, por más que su creador la fomentara.
Una vez alejado del camino oficial marcado por una visión que pretende que desarrollar una aplicación web es lo mismo que desarrollar una de escritorio* (y guiado por Rick Hunter, que ya se había apartado de ella hacía tiempo), todo fue “casi” sencillo (eso fue irónico, pero de todas maneras valió la pena).
Primero hubo que encerrar a Viewstate (suprimiéndolo) en una página base de la que derivan todas las demás y en las que utilizamos controles controles propios que producen HTML sencillo y como Dios manda. Luego combinar con un framework de Javascript (puede ser propio o alguno de los tantos que circulan por allí) para enviar sólo lo necesario de vuelta al servidor e incrustar los datos (o el HTML, o las dos cosas, ¿por qué no?) elegantemente en la página, sin generarla nuevamente.
Es decir que terminé haciendo lo de antes, lo mismo que hacía (desprolijamente) en ASP 3.0: producir el HTML una sola vez y luego ingresar, validar, actualizar y modificar la página con Javascript (validar en Javascript es opcional –aunque muy recomendable-, que las validaciones tienen que estar del lado del servidor sí o sí, por supuesto).
Lo de antes, sí, pero ahora con herramientas (el Framework .Net) que permiten hacer más fácilmente una implementación rápida y prolija y con mucha reutilización. Después de haber superado, claro, la amansadora .NET.
* Acerca de eso de “desarrollar una aplicación web no es lo mismo que desarrollar una de escritorio”… puede ser que con XAML y Silverlight Microsoft haya encontrado un camino para unificar las herramientas de desarrollo, aunque todavía le falte mucho. Por otro lado, está más que demostrado que con Javascript también se pueden crear interfaces complejas sin perder agilidad (en cualquier navegador que no sea el Internet Explorer, claro) y sin la molestia adicional de instalar algo en el cliente, con lo que… ¿podríamos decir que en algún punto compite con Silverlight…?
Sebastian Hermida comparte unos posters y y folletos con las “9 rules for a better object orientation” inspiradas en el libro ThoughtWorks Anthology (hizo también algunas viñetas, la primera de ellas aquí).
En el artículo “Object Calisthenics” Jeff Bay propone el ejercicio de elaborar un programa de 1000 líneas siguiendo estas reglas estrictamente (verán que son terriblemente restrictivas) con el objetivo de mejorar la orientación a objetos de nuestro código.
Primero lean, luego seguimos con mi propia verborragia.
Use only one level of indentation per method. If you need more than one level, you need to create a second method and call it from the first. This is one of the most important constraints in the exercise.
Don’t use the ‘else’ keyword. Test for a condition with an if-statement and exit the routine if it’s not met. This prevents if-else chaining; and every routine does just one thing. You’re getting the idea.
Wrap all primitives and strings. This directly addresses “primitive obsession.” If you want to use an integer, you first have to create a class (even an inner class) to identify it’s true role. So zip codes are an object not an integer, for example. This makes for far clearer and more testable code.
Use only one dot per line. This step prevents you from reaching deeply into other objects to get at fields or methods, and thereby conceptually breaking encapsulation.
Don’t abbreviate names. This constraint avoids the procedural verbosity that is created by certain forms of redundancy—if you have to type the full name of a method or variable, you’re likely to spend more time thinking about its name. And you’ll avoid having objects called Order with methods entitled shipOrder(). Instead, your code will have more calls such as Order.ship().
Keep entities small. This means no more than 50 lines per class and no more than 10 classes per package. The 50 lines per class constraint is crucial. Not only does it force concision and keep classes focused, but it means most classes can fit on a single screen in any editor/IDE.
Don’t use any classes with more than two instance variables. This is perhaps the hardest constraint. Bay’s point is that with more than two instance variables, there is almost certainly a reason to subgroup some variables into a separate class.
Use first-class collections. In other words, any class that contains a collection should contain no other member variables. The idea is an extension of primitive obsession. If you need a class that’s a subsumes the collection, then write it that way.
Don’t use setters, getters, or properties. This is a radical approach to enforcing encapsulation. It also requires implementation of dependency injection approaches and adherence to the maxim “tell, don’t ask.”
¡Ja! Dos preguntas: ¿Estas reglas llevan a una mejor orientación a objetos? ¿Qué opinan de seguir estas reglas a rajatabla en “la vida real”?
Yo creo que sí, que indudablemente llevan a una mejor orientación a objetos. En cuanto a la segunda pregunta, mi propia opinión se resume en aquel principio de diseño del BDFL Guido van Rossum:
“Lo pragmático gana a la pureza”.
Y que el ejercicio de aplicarlas estrictamente debería quedarse en eso: un ejercicio acotado a un sistema de más o menos 1000 líneas.
Si programar es como escribir, un sistema es como un libro: hay un argumento central con algunos pasajes magistrales, algunos secundarios que hacen a que la historia sea completa y coherente, y mucho relleno y lugares comunes que siempre –o casi siempre- tienen que estar. La proporción de unos sobre otros determinará la calidad del resultado final, que puede ir del folletín a la obra maestra.
Todo es cuestión de saber dónde y cuándo utilizarlas, porque conllevan cierto esfuerzo adicional. Aplicadas en las funcionalidades críticas del sistema (en aquellas más complejas o indefinidas que se llevarán el grueso de las horas de cambios y mantenimiento) supondrán un ahorro considerable y la diferencia entre el código que resiste las modificaciones (e incluso mejora con ellas) y el que cae sobre sí mismo como un castillo de naipes al viento, convirtiéndose en una masa desordenada de clases. Utilizadas obsesivamente a través de todo el sistema no es más que una pérdida de tiempo.
Las reglas son muy bonitas pero, como decimos a veces en el trabajo “hay que pensar, no queda otra”, todavía no encontramos el método que nos libre de eso… por suerte, porque ese día nos quedamos sin trabajo.
De todas maneras me llamó la atención el libro, habrá que conseguirlo.
Los asiduos habrán notado una brusca caída del ritmo de publicación en estas últimas dos semanas. El trabajo tuvo algo que ver (no mucho). El inicio de clases, con las corridas y preparativos de última hora pesó un poco más. Pero la razón principal ha sido el fallecimiento de mi computadora de escritorio (una Pentium 4 HT 3.2Ghz).
Es posible que haya muerto de envidia. Su deceso se produjo a las pocas semanas de la compra de una Acer Aspire One (apenas una netbook, pero ya la superaba en performance). A través de este post le rindo un sentido homenaje…
Pero la vida sigue. No soy de jugar con el hardware. Cada vez que una máquina dice “basta” hago el esfuerzo y compro el equipo más potente que puedo para olvidarme del tema por un par de años, durante los que no me preocupo en lo más mínimo por su mantenimiento hasta que casca nuevamente.
Es ésa y no otra la razón de mi elección por un Intel Core 2 Quad Q8200, sobre un motherboard Intel DG31PR con 4Gb de RAM y una placa de video “decente” (no soy un fanático de los juegos), una GeForce 9400 GT.
Lo anterior solamente viene a cuento de poner en contexto lo que realmente me interesa, que no es el hardware sino el software. Hace un tiempo que venía con ganas de probar la beta del Windows 7, así que aproveché la obligada migración para distribuir un poco más racionalmente mis datos (después de un par de años programas, documentos, fotos, videos y desarrollos e instalaciones a medias convirtieron mis discos en una masa compacta, indivisible y desordenada de archivos) e instalarlo en una partición propia.
La verdad es que si bien la muy respetable opinión (y entusiasmo) de uno de mis compañeros de trabajo cultivó mi curiosidad, era escéptico respecto de la nueva interfaz.
He visto el Windows Vista de lejos pero en la oficina sigo con el XP (que es, en mi opinión -y creo que en la de la mayoría de los usuarios-, el mejor sistema operativo de Microsoft al momento). Esperaba entonces más o menos lo mismo de siempre: muchos cambios estéticos, algunos realmente molestos, la mayoría simplemente inútiles o intrascendentes, y las opciones y funcionalidades de siempre redistribuidas de modo que se maximiza la frustración en las primeras semanas de uso, hasta el momento en el que uno se rinde y somete a los designios de la nueva UI.
Las críticas al Vista, y mi percepción de que el 7 seguiría a grandes rasgos la misma línea no ayudaban mucho. Escéptico por naturaleza, descreía del buzz positivo alrededor de la nueva versión. En resumen, esperaba el chiste de siempre: uno se pasa la primera media hora jugando y los dos o tres primeros días tratando de dejar todo como estaba.
Primero hacer un poco de espacio: achiqué la partición de un disco de 300Gb (nota mental: es bueno tener por lo menos dos particiones –datos y sistema operativo-) con el Partition Magic y creé una nueva de 20Gb. Un par de errores y reintentos después los datos contenidos en aquel disco estaban perdidos. Empezamos bien.
Ya molesto por el trabajo de recuperación que se avecinaba inicié con el disco de instalación del build 7057 de Windows 7.
Primera sorpresa: Ok, empezaba con una partición limpia, pero eso no resta méritos. Siguiente-siguiente-siguiente, escasos 20 minutos y ya está. No lloró por drivers, ni pidió actualizaciones, no aparecieron las típicas e inútiles preguntas que interrumpen la instalación cada 5 minutos (obligándome a aburrirme cerca de la máquina), ni siquiera se equivocó con la distribución de teclado.
Me pasé el resto del día recuperando y reorganizando los archivos perdidos en el movimiento de particiones, para finalmente reformatear todo el espacio libre. Trabajo aburrido si los hay, pero tengo que reconocer que la vida es más fácil teniendo las cosas ordenadas.
Sorpresa. Es lindo. Bueno, eso era esperable. Pero más que lindo… es casi… sobrio. No molesta. No pregunta. No aparecen mensajes extraños ni anuncios catastróficos compitiendo por mi atención para que baje, actualice o descubra.
Lo primero que llama la atención es la barra de tareas, con el famoso preview que aparece al pasar el cursor por encima del ícono del programa abierto.
Pero es más que un “chiche”. Moviendo el cursor sobre el preview la ventana emerge al frente mientras las demás se vuelven transparentes, desde allí mismo podemos cerrarla o minimizarla, o volver a la ventana anterior con sólo desplazar el mouse fuera del preview. Se puede agregar o quitar el acceso directo a ese programa en la barra de tareas desde allí mismo, por lo que ya no hay que “personalizarla”, uno lo va haciendo y deshaciendo sobre la marcha.
La otra característica que me impresionó desde el primer momento es el cuadro de búsqueda en lo que antes era el “menú de inicio”. Mantiene el foco siempre que esté abierto el menú y va mostrando los programas y opciones de configuración que concuerdan con lo que vamos tipiando. Creo que puede extenderse para buscar en internet desde allí mismo, pero todavía no lo he probado.
Ese primer día me la pasé explorando y tocando opciones… y dejé todo como estaba. No, no dejé todo igual al XP, dejé todo igual a la configuración por defecto.
Luego reinstalé el XP en otra partición (hay que conservarlo, no olvidar que esto es una beta), y obviamente eso rompió la instalación del 7. Reparé la instalación del 7 desde el CD (identificó el problema –XP instalado después del 7 o Vista embarulla la configuración del multiboot- y lo reparó puntualmente, sin reinstalar) y –obviamente- rompió el XP (bueno, algunas cosas no cambian nunca). Indagando un poco me enteré de que el viejo y sencillo boot.ini fue reemplazado por el retorcido y complicado BCDEdit, que superó en largo mi paciencia para estos temas, con lo cual decidí simplemente borrar todo, instalar primero el XP en una partición, luego el 7 en otra y a otra cosa mariposa (¿ven para qué es bueno tener datos y archivos propios por separado? Yo aprendí de la manera difícil). Pero más allá de esos primeros roces los dos sistemas operativos conviven y comparten el resto de las particiones sin problemas.
Me rindo, tengo que reconocerlo: Windows 7 es muy, pero muy bueno. Me molesta trabajar con XP, simplemente me molesta. Las nuevas características (sobre todo las dos mencionadas arriba) son tan naturales que es tan fácil acostumbrarse a ellas como difícil resignarlas luego.
Es obvio que Microsoft ha escuchado mucho a sus usuarios y se ha adaptado más a ellos que en otras versiones, abandonando esa actitud de –me parece- imposición de visiones en la forma de interacción con el sistema.
El rendimiento es impecable, aunque es obvio que si no lo fuera en esta máquina ya sería el colmo. Me han comentado que se degrada elegantemente en equipos con menos recursos, pero no lo he probado personalmente.
Han cascado varios programas (por mérito propio), y por supuesto que programando y probando he metido un par de bucles infinitos, ejecutado algún que otro código malicioso, y llevado la máquina casi al límite (con un par de máquinas virtuales haciendo de servidores de base de datos y de páginas web al mismo tiempo) y el sistema operativo ha respondido siempre sin problemas. Dudo que alguna vez le exija más que eso y estoy seguro de que un usuario medio tampoco.
De que Microsoft le ha vuelto a robar ideas se ha vuelto a inspirar en Apple, a Ubuntu y demás no caben dudas. De que nos vuelven a usar como beta testers gratuitos han escuchado a los usuarios tampoco. También es verdad que para mí, por primera vez desde aquel traumático primer pasaje del NT 3.11 al 95 (¡¿dónde están mis grupos?! ¡¿Qué es esto del escritorio?!) la transición es suave, relajada, para nada traumática, y, en definitiva, muy positiva.
Windows 7, en beta y todo, ya es mi sistema operativo por defecto desde hace una semana completa, en la que me he dedicado más a trabajar que a jugar (aunque he vuelto a jugar bastante, ahora que puedo) y tengo que reconocer que es más que cómodo. Por primera vez Microsoft ha logrado que su interfaz llegue velozmente al objetivo: volverse invisible al usuario.
Ahora no hay excusas para volver al ritmo habitual. Nos leemos.
Ya he pasado mucho más tiempo con el título que con la entrada. Finalmente recurrí a mi nuevo mejor amigo para evitar el ridículo (gracias a Verónica por presentármelo): el Diccionario panhispánico de dudas que puede consultarse desde la página principal de la RAE.
Resumen: currículum vítae es una locución latina que significa literalmente “carrera de la vida”. El plural -en latín- es currícula, y no debe usarse. Lo correcto es utilizar la voz adaptada currículo y su plural, currículos (ver Diccionario panhispánico de dudas - RAE).
¿A qué venía todo esto?
Ah, sí. Recomendarles una divertida entrada en 101.es, "Currículum creativos" (mal, y encima en el título), en la que se recopilan algunos currículos creativos.
Un par de muestra (hay más en el artículo), uno con el look & feel de Google, y éste en forma de mapa del metro:
Casi me olvido: visto en el twitter de @yoriento.
Bad Usability Calendar: 12 consejos sobre lo que no debemos hacer al diseñar un front-end presentados con mucho humor.
Visto en webmaster libre.
En principio definamos claramente usuario dentro del contexto de este post, para evitarnos problemas: usuario es el que opera el sistema en una situación real para alcanzar un objetivo determinado que coincide con el que fue requerido al desarrollar el sistema.
Mi definición tiene sus vericuetos: un analista probando una instalación del sistema no es un usuario, ya que su objetivo es el de encontrar errores, por más que esté en un entorno real. No es el líder del equipo presentando el producto, no es un hacker que intenta romperlo o extraerle información. Tampoco es uno de los empleados si simplemente lo está "explorando" para "familiarizarme un poco con él", ni es un cualquiera que lo ha abierto por equivocación, ni siquiera una persona que por desconocimiento quiere utilizarlo para algo para lo que no fue diseñado (ej.: el gerente entra al sistema de emisión de facturas (orientado hacia lo operativo) buscando saber el total de facturación de un cliente).
La definición también descarta los casos de de fallos en la interpretación o definición de los requerimientos. En definitiva, se acota el sinfín de situaciones posibles a aquéllas en las que el usuario y el sistema "quieren hacer lo mismo".
Un buen desarrollador siempre presente la siguiente máxima (hay muchas variaciones, pero ésta es la que viene más al caso):
El usuario es tontoo maliciosoa menos que se demuestre lo contrario.
He tachado malicioso porque fue descartado por la definición anterior.
Entonces... ¿el usuario es tonto? ¡Qué novedad! pensará cualquier desarrollador. El que no lo sea tal vez se sienta ofendido. Lo siento, la verdad duele. El usuario es tonto. Siempre.
Tenemos un sistema interno de carga de horas. Es bastante nuevo, y muy simple. Por suerte en esta empresa no somos muy perseguidos con el horario (siempre y cuando las cosas más o menos salgan, claro) ni hay una cultura del tipo "qué-pasa-que-tus-ojos-no-están-sobre-la-pantalla", en donde suena una alarma cada vez que uno levanta la vista o no presiona una cantidad de teclas por minuto. Así que está exclusivamente orientado a cargar las horas a los proyectos correspondientes.
Cualquiera diría que tal sistema, sobre todo con el nivel de usuarios que tiene, no necesita de mayor asistencia para su uso. Error.
Es divertido ver como analistas funcionales, administradores de bases de datos, programadores de todo tipo y edad (entre los que me incluyo), líderes de proyecto, todos somos tontos a la hora de utilizarlo.
Y yo soy el primero, ojo. Basta hacer alt-tab desde el entorno de programación hacia este sistema para transformarme automáticamente en mi señora madre, que apunta y presiona compulsivamente cualquier forma cuadrada que aparezca más o menos por el centro de la pantalla.
Sí, ya sé "yo no hago eso", "yo no soy así"... vamos, no les creo. La diferencia entre un usuario experto y un novato es que el experto recurre a su experiencia para captar rápidamente convenciones y formas comunes, disminuyendo la necesidad de muchas de las secuencias de pruebas-y-errores que intenta el novato, quien además las ejecuta más lento.
¿Es así? ¿Por qué? Habrá una segunda parte.
97 Things Every Software Architect Should Know es un interesantísimo proyecto en forma de wiki. La idea es reunir axiomas de la arquitectura de software propuestos por y discutidos entre quienes desempeñan este papel.
Cada tanto entro y pispeo las modificaciones y contribuciones. Sinceramente me muero de ganas de meter bocadillo, pero armar una frase que pegue en inglés y argumentar con la exactitud de conceptos requerida es un desafío que hasta ahora no pude superar.
Hay algunas realmente buenas:
Hay para relamerse, y las discusiones asociadas son muy buenas. Es recomendable leer sobre aquellas con las que uno no está de acuerdo. Las mejores 97 serán incluidas en "97 Things Every Software Architect Should Know", un libro que será publicado por O'Reilly Media, Inc.
Visto en Pensamientos ágiles.
Hubo, allá lejos y hace tiempo, una publicidad que no me acuerdo de qué era. Un tipo con cara de bobo delante de una máquina (monitor ámbar). Lo vemos de frente. Se acerca alguien (¿el socio?) y el informático bobo le dice algo así como "¡mirá, da vueltas!" embelesado con una "A" fea y cuadrada girando en la pantalla, de la cual estaba obviamente muy orgulloso. El otro ponía cara de "¿Ésto es en lo que perdés el tiempo con la computadora? ¿Ésto va a atraer a los clientes?".
Cuando alguien hace alguna funcionalidad tan linda como inútil siempre me trae a la cabeza esa frase.
Hace un par de días estrenaba con éste agradecimiento una nube de tags en mi blog, simple, común y silvestre, funcional. Todas las etiquetas, las que contienen más artículos más grandes que las otras. Una nube de tags, qué más.
Había visto, en mi investigación previa, el componente Tag Cloud, en el Roy Tanck's Weblog, pero como era para Wordpress no le había dado mucha bola, aunque me parecía mucho más atractiva.
Cuestión que hoy un compañero de trabajo me dice "mirá este tipo, qué buena nube de tags que tiene". Inmediatamente reconocí a la mencionada arriba, es muy bonita, ya ven.
Y me digo... ya está, ya lo hice, está funcionando... no está para Blogger... pero... da vueltas... ¡da vueltas!.
Así que la busqué, alguien la había adaptado a Blogger. La puse en el blog.
En seguida me dí cuenta de que, por ejemplo, los tags eran todos del mismo tamaño... el flash es innecesario y hace que la página tarde en cargar... hay veces en las que el movimiento no es tan fluido y mi procesador (que no es de última generación) nota la carga. Es difícil ver todas las etiquetas de un vistazo. Buscar una en especial es incómodo... ¡pero da vueltas!
A Cerebrado le pasó lo mismo que a mí (lo siento por el escrache, pero tengo que demostrar que no soy el único). Es inevitable quedarse un rato haciéndola girar cada vez que entro al blog.
Claro que hasta un par de horas después no se me había dado por hacer click... qué importa a dónde me lleva... ¡da vueltas!
Hice click entonces, recuerdo que en "procrastinación" y... me llevó a la página de la etiqueta correspondiente pero sin ninguna entrada en ella. A ver: puede que alguna de mis etiquetas tenga pocas entradas, pero seguro que procrastinación no es una de ellas.
Era, muy evidentemente, un problema con el link. Después de un rato de pruebas y puteadas maldiciones miro los comentarios en la página de donde la había sacado y veo que "algún problema" (comillas, porque no indagué demasiado) con el encoding tenía. Desistí de intentar arreglarlo.
Qué decepción... no funciona. Puedo tolerarle todo, pero no funciona. Alguien (¿quién? ¿alguien hace click ahí?) va a tocar y no va a encontrar las entradas correspondientes y abandonará decepcionado el blog.
Pero da vueltas...
Es tan linda...
Para resumir, verán que mis etiquetas ya no tienen acentos ni eñes. Sí, dice "diseno" en vez de "diseño". Pero da vueltas.
Que los sistemas, que la funcionalidad, que la solución más simple... no será muy funcional, pero gira.
Recordatorio: es evidente que en algunos casos podemos reemplazar funcionalidad esencial con unas lindas luces de colores.
BTW, Google no ha podido ayudarme esta vez, es que es demasiado ambiguo... ¿alguien se acuerda de qué era la publicidad?
A estas alturas no espero que se den cuenta, pero por fin conseguí un Tag Cloud para el blog, que pueden ver en la barra de la derecha.
Buscando por ahí encontré varias soluciones posibles. Finalmente me quedé con el código que encontré en el blog Compender. Es de lo más simple y estudiándolo un poco se aprende bastante sobre los templates de blogger.
¡Gracias Raymond, por compartir el código!
En PSP (Personal Software Process) o como pasarse de rosca midiendo se comenta el caso en el que un desarrollador "pierde" algún tiempo codificando (por supuesto que con algún errorcito) una función que valida fechas al estilo IsDate de Visual Basic... en realidad, idéntica al IsDate de Visual Basic.
¡Qué barbaridad! ¡Qué pérdida de tiempo! ¡Qué desconocimiento del lenguaje!
Ésta es una breve historia sobre cuatro programadores.
Programador A
Luego de un par de meses el Programador A que ha codificado la función ValidaFecha idéntica a IsDate ve ese código, se sonríe un poco y piensa "qué inútil". Borra el cuerpo de la función y lo reemplaza por la llamada a IsDate.
Programador B
Programador B no ha creado la función "inútil" para validar fechas. Luego de resolver el tema en una pantalla en particular copia y pega las 130 líneas de código en cada una de las 50 pantallas del sistema.
Pero después de un par de meses ve ese código en una pantalla, se sonríe un poco y piensa "qué inútil". Lo reemplaza por IsDate. Se queda pensando... revisa todas las pantallas y encuentra las mismas líneas junto a otras que hacen algo parecido. Está molesto, porque sabe que tiene que corregirlo y se le hace trabajoso. Le molesta pensar que tiene que probar nuevamente todas las pantallas del sistema. Finalmente, crea una clase dedicada a validaciones donde, entre otras, encapsula la función IsDate.
Programador C
Programador C ha comenzado igual que Programador B (copiando todo en todos lados), también busca en todo el sistema y las reemplaza por la llamada a IsDate en cada una de las pantallas.
Programador D
No sabemos qué solución adoptó el Programador D, pero en todo caso podemos estar seguros de lo siguiente: cuando lo vuelva a ver no reflexionará ni un segundo sobre cómo ha llegado allí, ni sobre si está bien o mal, salvo cuando se presente algún error (que puede ser en todo el sistema o en una pantalla en particular). En este caso corregirá el tema puntual y seguirá con su vida.
Ahora, con un poco de perspectiva, juzguemos a cada uno.
Obviamente Programador A es un junior, o apenas ha comenzado a programar en VB. Hizo lo mejor que pudo con las herramientas y el conocimiento que tenía. Trabajó prolijamente y en una forma tal que luego no tuvo problemas en mejorar el código a la par de su propio conocimiento.
Casi lo mismo podemos decir de Programador B. Pero en mi opinión tiene más mérito. ¿Por qué? Corrigió el error en todo el sistema y buscó la forma de que no le vuelva a suceder. Empezó un escalón más abajo que Programador A, y llegó más arriba. En realidad no importa si su solución es óptima o incluso correcta. El Programador B intenta solucionar los problemas "de aquí en más". Cuanto más se equivoque más aprenderá.
Lo único que ha aprendido Programador C es que existe una función llamada IsDate que valida fechas, que no es poco pero tampoco tanto. Es el tipo de persona que dice "muchos árboles" en vez de "bosque".
La vida del Programador D evidentemente pasa por otro lado. Supongo que poco le importará nuestra opinión de él o de su código, en tanto conserve su trabajo.
En definitiva, desde nuestro punto de vista, grandes desarrolladores que hemos nacido sabiéndolo todo y que nunca hemos reinventado la rueda, todo es una gran pérdida de tiempo. Sabemos perfectamente cuándo hay que usar IsDate y cómo se comporta por lo que nunca tendremos problemas con ella, y tal vez hasta vemos un poco inútil el encapsularla en una clase de validaciones.
Al resto de los mortales sugiero juzgarlos no por la corrección de sus soluciones en un momento dado, sino midiendo cómo capitalizan su experiencia a través del tiempo.
A partir de los comentarios de la entrada "Jaque" me quedé dando vueltas alrededor de la arquitectura de la capa de datos en una aplicación.
El primer punto a definir es qué entendemos por capa de datos. Me gusta tomar Wikipedia porque siento que representa el mínimo común denominador entre todas las acepciones posibles. Una base sobre la que (creo) estaríamos todos de acuerdo. En la correspondiente entrada (Programación por capas) encontramos:
[...] Capa de datos: es donde residen los datos y es la encargada de acceder a los mismos. Está formada por uno o más gestores de bases de datos que realizan todo el almacenamiento de datos, reciben solicitudes de almacenamiento o recuperación de información desde la capa de negocio.
Lo que sigue a continuación es toda la secuencia de experiencia previa, análisis, pruebas y errores que nos llevó a la capa de acceso a datos que tenemos armada ahora, con la que estoy bastante conforme. Está claro que dependiendo del proyecto las atribuciones y responsabilidades de esta capa podrán variar sutilmente. Para el caso, necesito agregar una responsabilidad más, que puede o no asignarse a esta capa, pero que en todo caso quiero incluir en la discusión:
Transformar objetos que representan la estructura de la base de datos en otros que representan la lógica del negocio y viceversa.
Como decía, puede que se lo asignemos o no a la capa de datos, pero en lo que estaremos todos de acuerdo es en que los objetos que maneje la capa de negocios no deberían estar absolutamente condicionados por la estructura de los datos en la base, por más que tengan alguna relación con ellos o que utilicemos las tablas como punto de partida. Por ejemplo:
Traducido a la capa de acceso a datos, estamos haciendo un JOIN entre la tabla de clientes y la de facturas por un lado y la de incidentes por el otro, más todas las tablas satélite que se puedan requerir en cada caso.
En el framework de trabajo existente hasta ese momento, cada objeto de negocio utilizaba una capa de datos para acceder a la base, pero definía su propia consulta utilizando el lenguaje específico, SQL, que se iba armando en el mismo objeto de negocio. La capa de datos devolvía objetos genéricos (DataTable, DataReader, etc.) que eran utilizados directamente. En este caso provee la persistencia y la conexión, pero se desentiende de la consulta en sí misma.
Los problemas más notorios son que el código de consulta ensucia la clase de negocio, no permite reutilización alguna y se producen infinitos puntos de acceso a datos. Por otro lado la utilización de objetos de datos genéricos como el DataTable hacen que el código sea difícil de seguir, sobre todo si se utilizan subíndices para acceder a los datos en particular (ej.: saldo=dataRow[1] + dataRow[3]).
Con este punto de partida, los primeros esfuerzos se orientaron a optimizar y ordenar el armado de esas consultas. En principio se adoptó una filosofía estricta de utilizar siempre procedimientos almacenados, para separar el código SQL del resto de la lógica.
Eso emprolija un poco el código, pero no resuelve los demás problemas. Era una tarea necesaria, pero que no atacaba el centro de la cuestión, representado por el ejemplo anterior: necesitamos manejar objetos de negocio específicos, no genéricos ("Cliente" en vez de "DataTable") y necesitamos acceder a propiedades evitando el uso de subíndices, entre otros.
Entonces comenzamos a armar una capa de acceso a datos que asumiera esa tarea de transformación de datos en conceptos de negocio, montado sobre el "proveedor de persistencia y conexión" (por llamarlo de alguna manera) existente.
Otro problema era lograr cierta reutilización. Estaba claro que si se creaba un procedimiento almacenado para cada necesidad estaríamos simplemente poniendo el muerto bajo otra alfombra. Todas la consultas que antes ensuciaban los objetos de negocio pasarían a formar un inmenso (e inmanejable) repositorio de procedimientos almacenados.
Aquí es donde entra en juego el problema de los JOIN en los procedimientos almacenados que se menciona al pasar en los comentarios de Jaque. En nuestro ejemplo, si hago un JOIN en la base de datos necesito dos consultas o procedimientos almacenados: una para Cliente-Facturas y otra para Cliente-Incidentes.
Algo similar sucede con las transacciones. Necesito grabar Clientes-Facturas en una única transacción. Si la implemento en un procedimiento almacenado, ese procedimiento sólo podrá grabar esa combinación de datos.
Era claro que por ese camino y sólo tomando las dos o tres tablas principales del sistema tendríamos una miríada de consultas diferentes, cada una respondiendo a una combinación cabecera-detalle diferente. Se descartó por ser a todas luces poco práctica la posibilidad de una súper-consulta que recupere (por ejemplo) un cliente y todos sus datos devolviendo una especie de súper-entidad. Está claro que la tabla cliente podría tener más de 20 tablas de detalle independientes (ej.: facturas, remitos, incidentes, pedidos, contactos, pagos, cheques, movimientos, y todo lo que se nos ocurra), y que rara vez se utilice más de un par en cada módulo de negocio (es claro que el módulo que maneje la chequera poco tiene que hacer con los incidentes). Por otro lado también se descartó la posibilidad de cargar esa súper-entidad "on demand" por presentarse demasiado compleja.
Es cuando surge como una posibilidad más sencilla el tener un conjunto de consultas estándar, las clásicas SELECT, INSERT, UPDATE y DELETE para cada tabla y con ellas llenar las estructuras de datos más complejas en el código. En la gran mayoría de los casos esto no representa problemas de rendimiento. Pero de todas maneras nada impide tener una consulta especial sólo para aquellas situaciones que sí lo justifiquen.
Surgieron así las clases de acceso a datos creadas automáticamente a partir de la estructura de cada tabla. Para nuestro ejemplo, tendríamos tres clases ya predefinidas: ClientesDatos, FacturasDatos, IncidentesDatos. El objeto de negocio las utiliza para llenar Facturación.Cliente.Facturas y CRM.Cliente.Incidentes en cada caso. Estas clases devuelven objetos tipados, también creados a partir de la estructura de las tablas.
Con las transacciones sucede lo mismo. Al momento de grabar un cliente y sus incidentes la clase de negocio abre una transacción, llama a las clases de datos correspondientes y la cierra. No puede abrirse una transacción en la misma clase de datos, ya que esto impediría la reutilización. Conceptualmente tiene sentido. Una transacción queda definida en la operación de negocio que se realice. No es lo mismo facturar que insertar un incidente, pero a la capa de datos no tiene por qué interesarle esto.
Pero estoy haciendo trampa, porque en mi ejemplo omití una situación común. Se puede argumentar, con razón, que IncidentesDatos devuelve, según mi ejemplo, incidentes para un cliente, y que probablemente otro módulo requiera, por ejemplo, "incidentes por responsable interno" o "incidentes sin responsable" o "incidentes no resueltos", etc. Para cada uno de estos casos deberíamos armar un procedimiento almacenado y estaríamos de vuelta con el problema anterior.
Esto era justamente lo que nos estaba comenzando a suceder. Si bien era fácil tener clasificados los procedimientos almacenados (ya que siempre se referían a una única tabla), la realidad era que por ese camino iban a ser demasiados.
Hubo que romper el mito de "todo procedimientos almacenados" (con cierta reticencia inicial por mi parte, pero por suerte la mejora se notó rápidamente, despejando las dudas). De vuelta a generar código automático, esta vez para crear objetos que encapsularan un criterio WHERE generado dinámicamente. Un especie de filtro extremadamente configurable para cada tabla.
La clave fue el encapsulamiento. Si la lógica de armar consultas "on the fly" se hubiese expandido sin control por todo el sistema estaríamos de vuelta en la situación inicial. Estos objetos (uno específico para cada tabla) se volvieron internos de la capa de datos.
Para resumir, en el cuerpo de un método de la capa de acceso a datos se crea uno de estos objetos, se lo configura con un par de líneas de código y al ejecutarlo nos devuelve un objeto tipado que representa los datos de una tabla de la base. Un objeto de la capa de negocio puede llamar a varios métodos de la capa de acceso a datos para crear objetos complejos según su necesidad.
Cambiamos procedimientos almacenados por métodos, que resultaron más fáciles de clasificar, mantener y controlar. Un ejemplo en este sentido: si cambio la estructura de una tabla y genero automáticamente el código de la clase de filtro para esa tabla, se provoca automáticamente un error de compilación en todos los métodos de datos que se vean afectados por el cambio (y sólo en ellos). Una vez arreglados estos errores de compilación puedo estar seguro de fue implementado sin mayores consecuencias. Es decir, si compila funciona, si no funciona no compila.
¿Y dónde quedaron los JOIN y los procedimientos almacenados en T-SQL? Reservados sólo para algunos casos especiales, donde la consulta se realiza sobre tablas muy grandes o donde es necesario alguna lógica adicional u optimización relacionada con los datos. Pero resultaron ser apenas un par de casos excepcionales.