Mostrando las entradas con la etiqueta antipatrones. Mostrar todas las entradas
Mostrando las entradas con la etiqueta antipatrones. Mostrar todas las entradas

lunes, 20 de abril de 2015

Broken Culture

Los norteamericanos tienen una capacidad increíble para estandarizar cualquier realidad y encajarla en un set de historias prefabricadas, por más compleja que sea. Si, todo el mundo estandariza y encaja realidades en historias… es sólo que ellos lo hacen especialmente bien.

Mis feeds de “desarrollo” en inglés están llenos de telenovelas: los programadores somos la mucama inteligente, buena y fea; los managers, la malvada bomba sexy; la empresa (el capitalismo), el millonario que parece malo por estar atrapado sus redes pero que en el fondo es bueno. El final es cantado: la mucama inteligente se gana el corazón del millonario a fuerza de honestidad, bondad y trabajo duro, y en la última escena es la que está más buena de todas. La mala cae envuelta en sus propias telarañas y termina desenmascarada como la chupasangre inútil que es, desterrada en quién sabe dónde.

Tim Chevalier toma la decisión de abandonar la telenovela-sistemas y da sus razones. Después Michael O. Church sintetiza esas razones en una pregunta: “Can tech fix its broken culture?”, y responde “si” pero con más palabras. ¿Y cómo? Como dicta la trama: resistiendo los ataques del management-malvada-bomba-sexy y demostrando valía con honestidad, inteligencia y trabajo duro (y muy poca paga) hasta que el capitalismo-sociedad-millonario se de cuenta y expulse a los managers-malvada-bomba-sexy del juego.

La afirmación que más fuerte me suena en el post Michael no es “podemos reparar la cultura de sistemas”, sino otra mucho más desesperada y sutil: “hay una historia con un final feliz en el que los buenos que resisten son recompensados”.

En algún momento (allá lejos y hace tiempo) en el que hubiese coincidido (y hasta se podría buscar prueba de eso en este blog), un tiempo en el que lo “Agil” prometía ser la movida que desenmascararía las malvadas maquinaciones del management, demostrando de una vez y para siempre que los “techies” somos el verdadero corazón de las empresas.

Pero ahora, un par de años después, “Agil/Scrum” es más o menos lo mismo que “CMMI”. Todos los puntos de aquel manifiesto que hubiesen podido cambiar algo fueron ignorados o licuados; sólo quedaron las reuniones. ¿Y los tests y la integración continua y la nube y los frameworks y el open source…? ¿No son avances? Sí son avances… también las pantallas planas, los multi core, el wifi y los celulares… Pero el escenario es el mismo en el que se escribió The Mythical Man-Month (en 1975). Sólo cambió el decorado.

El argumento es “la mucama con esfuerzo llega al millonario”. En sistemas se dice “los techies programando van a dominar la industria”. El problema en la trama es “que la mala tiene al millonario engañado”. En sistemas, “que los managers son explotadores parásitos de la empresa”. Pero en ambos casos la industria/la empresa/el capitalismo siempre recompensa el valor generado. En última instancia verá quiénes generan el valor cuando los managers, a fuerza de incompetencia, caigan en su inevitable desgracia y se desencadene el final feliz.

En pocas palabras: hay que salir y mostrarle al mundo que los técnicos son los que generan valor. Siguiendo esa línea, si fuésemos adolescentes sobreexplotados de McDonalds deberíamos unirnos para revelarle al mundo que somos los que hacemos las hamburguesas.

Es una telenovela simplificadora que justifica lo que hacemos ante nosotros mismos mientras estamos dentro. Nos convence de quedarnos y nos explica por qué se van los que se van, separándonos de ellos para que no se nos ocurra tomarlos de ejemplo. “Cualquier parecido con la vida real”, lejos de ser casual, ha sido elaborado, refinado y corregido a lo largo de los siglos (si, siglos: Cenicienta) para identificarnos con la mucama-pobre-heroína de la trama mientras hacemos girar la rueda del molino, caminando en círculos hacia ninguna parte.

Como las telenovelas, es un discurso que no tiene ni pretende ser real ni tener sentido, sólo coherente y útil hacia dentro. Si uno rompe “la cuarta pared” y abandona el set ya no ve ni buenos ni malos ni lindos ni feos ni historia ni nada: sólo un montón de actores representando un guión más o menos delirante que no escriben ni escribieron.

Bueno, y “Can tech fix its broken culture?”

La “cultura de las empresas de tecnología” no está rota. La “cultura de las empresas” surge y prospera en tanto las hace funcionar, sobrevivir y prosperar… a las empresas, no a las personas. No está ahí para conseguir la felicidad ni el bien común de nadie… pero tampoco para impedirlos.

Personalmente creo que no hay nada que demostrar ni a quien demostrarle nada; nadie mirando, sólo nosotros mismos. No hay héroes buenos-pero-feos enfrentados a managers-malos-que-parasitan-las-empresas, ni millonarios naive a los que hay que llevar por la buena senda para bien de todos. Ni siquiera hay un “somos” ni un “son”: no hay una historia común encaminada hacia un final feliz, o hacia ningún otro lado. Lo que hay es un momento y un espacio y ciertas reglas más o menos fijas… A algunos les conviene el status quo, a otros no. Para los que no, a veces se puede y vale la pena dar la pelea por el cambio, a veces no.

De lo que estoy más seguro es de que no se toman buenas decisiones mirando telenovelas.

sábado, 30 de agosto de 2014

Mi aplicación

Casi todos (los programadores, obvio) tenemos “mi aplicación”. Ésa que, cuando haya tiempo, vamos a hacer “como se debe”.

El “como se debe” varía con cada uno, pero me arriesgo a generalizar: no es una afirmación positiva sobre ciertas herramientas y prácticas, es más bien una negación de aquellas que venimos utilizando, utilizamos o nos obligaron a utilizar, o de las que escuchamos hablar mal por ahí o… un largo etcétera.

En criollo: “mi aplicación” no va a ser como éste proyecto-huérfano-engendro-mutante del que me contaron, caí o armé (“por culpa de…”, seguro).

¿Cómo es “mi aplicación”? La mía de mi propiedad, al día de hoy, es:

-Una aplicación web hosteada en google.

-Server side: en java, pero va a devolver exclusivamente JSON. Pura data. Lo juro.

-Con alguna base de datos no relacional, porque son re-cool.

-Bootstrap.

-Pero no pienso escribir una sola regla de css. Lo juro.

-Ni tampoco mucha imagen ni iconito. Si puedo quedarme sólo con lo de bootstrap, mejor.

-Ni meterle 10.000 plugins (aunque ya empecé… pero lo voy a deshacer, y cuando lo deshaga lo juro).

-Jquery

-Jquery validation, si hace falta (imagino que sí).

-Knockout.

-Require.

-Y visjs, porque necesito algo así.

-Y NADA más.

El problema es… el de más arriba: que es cuasi-simétricamente-opuesto a todo lo que alguna vez hice: no soy diseñador ni mucho menos (estoy aprendiendo que entre “seguir la onda”, y “diseñar” hay un abismo insondable). Nunca programé en java (profesionalmente, proyectitos de prueba hicimos todos). Nunca usé bootrstrap. De íconos y gráfica o imágenes… sólo sé buscar en google, y al photoshop no me lo presentaron (ni siquiera sé usar bien el paint.Net). Visjs es genial, pero todavía estoy leyendo la documentación. Los únicos viejos conocidos son Knockout, require, jquery y compañía. Pero son herramientas, no una forma de trabajar con la que uno viene acostumbrado, y en la que “el camino para hacer tal cosa” aparece casi naturalmente.

Como todo primer intento, es… bueno, como se imaginan que es. Pero hay que seguir haciendo y rehaciendo hasta que salga. Mentalmente, claro, porque en la real realidad, uno va dedicándole horas a cuentagotas entre proyectos más rentables, con la esperanza de que en algún momento éste también lo sea.

Si bien “construir éste sistema lo antes posible” es la madre de todas las cag…, también es la madre de todas las cosas que están ahí afuera en este preciso momento, satisfaciendo necesidades de éste preciso momento, probablemente tan efímeras como la combinación de herramientas que (ahora) “me gusta”.

“Como a mí me gusta” va variando a medida que avanzamos. A veces más, a veces menos, pero siempre, con cada paso hacia adelante, surge el imperioso impulso de pasarle la guadaña a (casi) todo lo que se deja atrás… y uno va y lo hace. Porque ésta es “como a mí me gusta”. Es inevitable: la motivación parte de “armar un proyecto como a mí me gusta”, y no “construir éste sistema lo antes posible”.

Pero bueno, juntar dos o veinte librerías, copypastear un poco de código y salir con algo rápido a ver si pega es, probablemente, eficaz. O por lo menos un fracaso rápido y a otra cosa… pero no es lo que tengo ganas de hacer ahora.

Tengo ganas de seguir jugando.

Y a todo esto… ¿qué hace, exactamente, “mi aplicación”?

Por ahora, nada.

¿Qué debería hacer?

No está muy claro, ya veremos. Lo importante es que “esté como a mí me gusta”.

¿Verá la luz del sol?

martes, 25 de mayo de 2010

La integración de la base de datos. Una cura definitiva para esta enfermedad crónica.

Martín Gargiulo Una colaboración de Martín Gargiulo (*).


Es muy común que los equipos de desarrollo trabajen sobre un ambiente de base de datos compartido. ¿Quién no ha sufrido las consecuencias de los desfasajes entre *la* base de datos y el resto del proyecto? ¿Quién no ha sido víctima –o victimario– de algún improperio cuando, en pleno desarrollo, un cambio en alguna propiedad u objeto de la base deja al resto del código pataleando en el aire?

Nunca, desde mis tempranos inicios, a través de diferentes proyectos en varias compañías, tuvieron estas cuestiones la suficiente importancia como para quitarle el sueño a nadie. Siempre, esto es lo realmente grave, parecieron ser lo normal. Estaba ante una enfermedad crónica.

Desarrollar implica agregar código, depurar, refactorizar y repetir estas operaciones un número de veces hasta obtener una determinada pieza de software. A nadie se le ocurre, hoy en día, que no se disponga de un sistema de control de código fuente, que permita a cada integrante del equipo trabajar localmente y luego, una vez concluida la construcción de la pieza, incorporar sus cambios al repositorio común.

Cada desarrollador debe trabajar en su propio espacio. Siguiendo esta premisa, ¿por qué la base de datos, siendo parte esencial del producto, no se incluye en él? ¿Por qué no es natural que cada desarrollador trabaje sobre su propio ambiente de base de datos?

Surge un problema. Si cada programador opera sobre su propio ambiente, ¿cómo obtienen los demás integrantes del equipo las modificaciones al esquema realizadas localmente? Del mismo modo que lo hace con el resto del código de la aplicación: mediante el repositorio de código fuente.

Por ello es indispensable que los scripts de base de datos estén incluidos en el controlador de código fuente, al igual que todo el resto del código. Es a través de estos scripts que se deben formalizar los cambios en la base que completan la programación de una pieza de software.

La base de datos, a diferencia de una pieza de código común, contiene estado (para eso está). Por eso, además del código para la creación de sus objetos, se deben tener en cuenta scripts de inserción de datos básicos para la aplicación (tablas paramétricas, tablas maestras) y, eventualmente, algún pequeño set de datos de prueba.

…continuará…


(*) Andrés dice: por fin, y luego de dos años de arrastrarme, alguien ha escuchado mis ruegos, dignándose a brindar… ¡una colaboración! Y en buena hora, que en este lugar ya se empezó a juntar el polvo. Esperemos que sea la primera de una larga serie y dé comienzo a una maratón de talentosos desarrolladores ansiosos por ayudarme a mantener vivo este humilde espacio (esperar es gratis, dicen).

jueves, 18 de marzo de 2010

Visibilidad.

Gran Proyecto (con mayúscula), muy “visible” para la gerencia de Megaempresa, vital para la subsistencia de NoTanGranPeroGranConsultoraOSoftwareFactory, y por tanto muy “visible” también para la gerencia de ésta última.

Desde nuestro punto de vista (de sistemas) no es más que otra aplicación de formularios que le pegan una y otra vez a una base de datos, más un sinfín de reportes que vienen a sacar lo que los formularios pusieron.

Otra gran, torpe, enmarañada, traicionera, e incansable generadora de un aburrido caudal de incidentes de fácil solución técnica, y que serían de fácil solución a secas si no fuera por el hecho de que más o menos la mitad de ellos contradice lo que indica la otra mitad.

Así que una horda de programadores armada con papel secante intenta contener ese río, resuelve uno y otro y alterna entre “A” y “no A” en un proceso que arroja tanta agua como recoge.

Hay otro caudal que lo alimenta, un caudal de programadores, analistas, managers y demás sacos de carne “recursos” que van pasando, pasando y pasando a ritmo creciente. Si no fuera por este otro caudal que aporta toda la energía desperdiciada en aquél ida y vuelta inútil el proceso descrito sería el santo grial del movimiento continuo.

Los gerentes, como esto es importante, están en contacto con “el equipo”, los conocen, interactúan con ellos más que con el resto. Es a esto a lo que se le llama “visibilidad” y que consiste en que, de vez en cuando, se abre un espacio en esos cielos y asciende alguno, (probablemente aquél con más habilidad para el alpinismo que para la programación) dejando al proyecto, que es realmente importante, en manos del resto que ahí queda, papel secante en mano (mientras el alpinista saluda desde lo alto).

Así es que, gracias a la “visibilidad” del proyecto los otros reman, reman y reman hasta que, hartos y sin esperanza, abandonan en busca de algún horizonte en donde sus entrenados brazos sean mejor recibidos. Aquellos en los que el entrenamiento no hace efecto y que por lo tanto carecen de otras expectativas (que los hay), esperan pacientemente su turno para el ascenso.

Unos y otros son reemplazados velozmente, así que eso que llamamos “equipo” (y que no es más que un fotograma de una película interminable) apenas puede acumular una muy vaga idea del negocio que el sistema viene a sostener, ya que el escaso conocimiento penosamente adquirido por prueba y error se va tan rápido como se acumula. Del negocio se sabe que es grande y millonario y que no es una verdulería ni un almacén de ramos generales, pero eso no alcanza para dividir las aguas y tomar la mitad de correcciones que corresponde para parar la rueda.

En fin… cualquiera que trabaje en sistemas un tiempo es expuesto a una de las más generosas fuentes de fina ironía que esta vida puede dar: el trabajo y, sobre todo, el trabajo en sistemas y, sobre todo, el trabajo “corporativo”. Si este tiempo es más o menos largo el sistémico, si sobrevive y lo sigue siendo (o mejor dicho, para sobrevivir y seguir siéndolo) habrá desarrollado un fino sentido de la ironía y del humor, o un cinismo a toda prueba, o todo eso junto. Por suerte algunos explotan genialmente esos efectos colaterales esas habilidades, y así tenemos a Dilbert (adivinen de dónde sacó Scott Adams la inspiración para sus personajes), o a Sinergia Sin Control, o al mayor repositorio de esfuerzo sin sentido y desperdicio de inteligencia jamás creado, TDWTF.

Porque lo más irónico de todo es que funciona y que buena parte de nosotros hemos vivido o viviremos de ello, y que es lo que termina financiando los juguetes (lenguajes, metodologías, herramientas, patrones, arquitectura) con los que nos entretenemos mientras, distraídamente, hacemos girar la rueda. En fin…

…que al mundo nada le importa
yira…
yira…

miércoles, 25 de noviembre de 2009

Complejo.

Hace semanas que vengo demorando una entrada sobre la complejidad. Es que hay tanto que decir sobre la complejidad que la cosa se vuelve un poco compleja… y soy poco dado a las cosas complejas.

Así que procrastinando otra vez el bendito post –que a estas alturas ya sé que nunca voy a escribir-, picando de aquí y allá en el reader, me encuentro con un -ya viejo- artículo de Joel: The Duct Tape Programmer.

Sencillamente imperdible, un compendio de frases impactantes delicadamente hilvanadas:

Sometimes, you’re on a team, and you’re busy banging out the code, and somebody comes up to your desk, coffee mug in hand, and starts rattling on about how if you use multi-threaded COM apartments […] and you have no friggin’ idea what this frigtard is talking about, but he just won’t go away, and even if he does go away, he’s just going back into his office to write more of his clever classes […]

Ya ven para donde apunta:

One principle duct tape programmers understand well is that any kind of coding technique that’s even slightly complicated is going to doom your project.

Y básicamente eso es todo lo que hay que decir al respecto de la complejidad. Me hizo acordar a esta otra gran frase, que no recuerdo muy bien de dónde saqué:

“Los buenos programadores resuelven los problemas complejos, los grandes programadores los evitan”.

Resolver un problema es ganar una batalla. Eliminar la necesidad de resolverlo es evitar la guerra. Es como la depuración: no se trata de meter más código sino de quitar el que sobra, no se trata de conocer más patrones, frameworks, herramientas, plugins y la mar en coche, se trata de encontrar la combinación más simple que nos permita implementar la funcionalidad necesaria, y de simplificarla todavía más.

Para evitar un problema es imprescindible crear el ambiente propicio para esas preguntas que ponen incómodos a todos: “¿realmente hace falta hacer esto? ¿por qué? ¿para qué? ¿hay otras posibilidades? ¿qué pasa si no hacemos nada?” Son esas preguntas las que llevan al pensamiento lateral, y es por eso que la aparición de respuestas tautológicas nos alertan tempranamente de que estamos perdiendo el rumbo: “Porque sí”, “Porque el cliente lo pidió así” (es casi decir lo mismo), “No sé, pero hay que hacerlo”, “Esto ya está pensado”…

Lo complejo se torna complicado muy rápidamente, casualmente en el preciso momento en el que los ingeniosos desaparecen.

jueves, 22 de octubre de 2009

Plugimanía, plugiadicción, plugidependencia, pluginitis.

jQuery está buenísimo. Lo uso todos los días, lo dije una y otra vez, y no me cansaré de repetirlo.

Su mayor fortaleza, opino, no radica en su reducidísimo (como corresponde) core sino en la amplísima comunidad de desarrolladores que aportan, oficial o extraoficialmente, nuevas funcionalidades encapsuladas en forma plugins.

Yo imagino que, como en toda comunidad, se sigue la regla del 90-10: 10% aporta activamente y 90% utiliza las funcionalidades provistas “as is” o a lo sumo con un poco de manoseo. Entonces, si derivamos la cantidad de desarrolladores-usuarios a partir de la cantidad de desarrolladores-aportadores obtendremos… no sé, un montón de gente.

Los usuarios-desarrolladores son aquellos que encuentran en jQuery la forma de implementar en cinco minutos aquella funcionalidad que estaban buscando. Es decir que llegan a jQuery a partir de una necesidad concreta que usualmente satisfacen rápidamente para proseguir con su camino, habiendo sumado una herramienta más a su caja de experiencias y dispuestos a volver a utilizarla allí donde consideren que sea más apropiada que otras.

Luego tenemos a los plugimaníacos, aquellos quienes ya han utilizado intensivamente la herramienta y por ello buscan en jQuery el plugin mágico que resuelva algún nuevo problema. Son los que lo crean si es que no lo encuentran o mejoran uno ya existente si es que no cubre totalmente sus necesidades… o por simple y sana diversión. Es aquel 10% del que hablábamos.

Una porción menor de desarrolladores siente que tiene que hacer eso tan difícil en jQuery, que necesita hacerlo en jQuery. Desarrolladores que prefieren implementar un nuevo plugin aún ante la existencia de herramientas o soluciones más apropiadas para el requerimiento concreto en el que están trabajando.

Ahí donde una pequeña animación en flash o un applet de java o silverlight parezcan soluciones más razonables o naturales veremos a los adictos decir “eso puede hacerse con jQuery” y poner manos a la obra, prestos a demostrar sus (en general extraordinarias) habilidades y a defender el orgullo de su herramienta (¡hablamos de jQuery, malpensados!) ante las demás. Son, del 10% de aportantes activos, el 1% que lleva jQuery al límite y hacia nuevos horizontes.

Pero, dentro de estos últimos, otra minoría, los plugiadictos, no sólo se bandean para el lado de lo extremadamente complejo, sino que también lo hacen hacia lo extremadamente simple. Si son de buscar en el mundo jQuery se habrán encontrado con más de uno que ha creado algún plugin que encapsula la más trivial y estándar de las tareas o que ha utilizado una ferrari (del tipo jqGrid) para la más aburrida de las tablitas no paginadas.

Hasta aquí toda gente normal, simpática, o a lo sumo un tanto extravagante. Pero cuando avanzamos en la progresión exacerbando un tanto más estas conductas pasamos de castaño a oscuro y entramos en el terreno de las patologías. Citaré dos de ellas: la plugidependencia y la pluginitis. Es posible, como se verá, que un caso extremo de la primera desemboque en la segunda.

El plugidependiente no es (ni puede ser, se verá) un aportador al repositorio de jQuery. El plugidependiente, debido al uso y abuso de la herramienta (ya sea motivado por él mismo o por su entorno) ha olvidado (o nunca aprendido) que existen cosas llamadas HTML, Javascript o DOM.

Lo reconocemos por un clásico afán de probar que “eso no puede hacerse” mediante la búsqueda infructuosa de un plugin de jQuery que lo haga. En su mundo aquello que jQuery no pueda hacer no puede hacerse, y punto.

Otras características remarcables, en casos extremos, son el desconocimiento de HTML más allá de los tags más básicos (aquellos que sirven de soporte a plugins de jQuery, como DIV y TABLE) y recurrentes intentos de utilizar sintaxis de jQuery en otros contextos (Javascript, o más extremo aún: C#, Visual Basic o cualquier otro lenguaje). Intentos que suelen culminar con un asombrado “¿ah, eso es de jQuery?”.

En el extremo absoluto de esta patología el desarrollador desconoce jQuery como extensión y cree que $(“DIV”).each( function(){…} ) es la sintaxis propia de Javascript o parte de HTML.

Como sucede con todas las herramientas y cosas en general, el abuso vuelve nocivo aquello que en el uso es beneficioso. Llegamos a la pluginitis.

El primer síntoma es una página web que tiene un título y una tablita y tarda unos 5-10 segundos en descargar. ¿Qué sucede? Pues nada, que tiene referencias a jQuery, jQuery UI, jqModal (pero… ¿no hay algo parecido en jQuery UI?) y unas 10 o 20 referencias más a archivos .js externos sin minimizar que no se utilizan absolutamente para nada… tal vez la página ni siquiera tenga un script, sino que simplemente… bueno, pluginitis.

Otros síntomas son: un browser (que no es el IE) que se arrastra, puro contenido generado dinámicamente del lado del cliente, imposibilidad de seguir la generación de ese código o de averiguar siquiera cual de las 3 o 4 extensiones parecidas de las incluidas en la página es la que está dibujando ese contenido.

¿Cómo salir? El primer paso es reconocer el problema. El segundo buscar ayuda y el tercero es una dura combinación de sacrificio, paciencia y constancia.

De mi parte, espero que el pequeño esfuerzo de escribir este post se justifique por haber ayudado, aunque sea a un sólo plugidependiente o pluginoso, a abrirse a una nueva vida. Si ése es tu caso, agradeceré tu comentario.

domingo, 6 de septiembre de 2009

El estilo, la legibilidad, los “malos” programadores y el ¿diabólico? codebehind en el Microsoft .Net MVC.

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.

Los hechos.

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:

MVCview

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.

Las opiniones

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.

Mi punto de vista 1: la estética.

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:

  • Hermoso es mejor que feo.
  • La legibilidad cuenta.
  • Los casos especiales no son suficientemente especiales como para romper las reglas…
  • Aunque lo pragmático gana a la pureza.

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:

  • Disperso es mejor que denso.

Yo creo que sería mejor tener todos esos lenguajes separados que revueltos e interactuando juntos en el mismo lugar.

Mi punto de vista 2: los “malos” programadores.

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.

Mi personalísima conclusión

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?

domingo, 30 de agosto de 2009

20 sitios web muy mal diseñados.

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:

014

094

143

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.

lunes, 10 de agosto de 2009

Señales de que eres un mal programador.

Más allá de los muy buenos chistes que contiene y del tono jocoso en general, Signs that you're a bad programmer es un artículo imperdible que debe tomarse en serio.

Está dividido en tres partes: “Señales de que eres un mal programador”, “Señales de que eres un programador mediocre” y “Señales de que no deberías ser un programador”. En cada una de ellas se presentan estas “señales” con sus respectivos síntomas y consejos para superarlas (carreras alternativas, para el último caso).

Aunque la gravedad de cada una en particular es discutible (yo no calificaría de “malo” a un programador con dificultades para seguir la recursión, me parece lo suficientemente complicado como para marearse sin merecer un calificativo tan extremo) es innegable su utilidad para identificar problemas y puntos débiles en uno mismo y los demás (o para decidirse a cambiar de carrera).

Más que puntear las que me parecen más importantes, voy a mencionar los síntomas que me resultan más molestos:

zombie "voodoo (o zombie) code"

Mantener código que no hace al objetivo del programa: inicializar variables que luego no se utilizan, llamar a funciones que no hacen nada o cuyo resultado es descartado, producir información que finalmente no se muestra.

Esto hace que seguir el código sea exasperante y su corrección peligrosa, ya que uno tiene que ir separando la paja del trigo para entenderlo, corriendo el riesgo de sacar algo que sí servía. Una solución posible es no limpiar nada, lo que nos lleva a…

noloborres “no lo borres”

Con lo que me gusta borrar código… Esto me molesta sobre todo cuando aparece en la forma de cierta tendencia -que veo incluso en programadores experimentados- a llevar el control de cambios en medio del código mismo (¿costumbres de una época en la que el uso de sistemas de control de código fuente no era tan común?). Me refiero a éste tipo de comentarios:

“J.P. 25/7/2006: arreglo del incidente nro. XXX. El cálculo del total de…”

Estoy tratando de entender que hace el código ahora, y no me interesa saber qué hacía hace tres años. Para hacer investigación histórica está el historial de cambios. A la basura.

Pero… por algo debe estar ahí, ¿por qué mejor no lo dejamos?…

candados “por las dudas”

Código que se ejecuta “para estar seguro de…” O estamos seguros y no hay que asegurarse o no estamos seguros y hay que molestarse en entender hasta estarlo, ¿no? ¿Seguro que Trim borra los espacios a los dos lados de la cadena? Mmmm… mejor hagamos miCadena=miOtraCadena.LTrim().RTrim()… por si acaso. O escribamos (int)4, no sea cosa que… Para asegurarse está la ayuda, no el código.

Una variación sutil de lo anterior es arreglar un problema en la salida de una función manoseando el código que la consume, “por las dudas” de que “alguien más” la esté utilizando. ¿Alguien más la está utilizando? ¿Tan difícil es ir, fijarse en dónde y en todo caso corregir esos otros lugares? Esto me lleva a un punto que me parece que falta en el artículo referenciado:

anteojeras “programar con ateojeras”

¿Vieron las anteojeras que se le ponen a los animales de tiro para que vayan siempre para adelante sin asustarse con lo que pasa a su alrededor? Hay gente que programa con eso puesto. Si tienen que corregir el incidente n que aparece en la pantalla x van a corregir eso y solamente eso, indiferentes a cualquier otro problema, por más grueso que sea.

incisión Son como cirujanos que acceden al código y extirpan un tumor con precisión milimétrica… sin darse cuenta de que hace tiempo que el paciente está muerto. Finalmente el aporte de estas acciones al proyecto en general es tanto como su alcance… milimétrico.

Bueno, hay mucho más… mejor lean el artículo.

viernes, 12 de junio de 2009

NUTS-QL (Negate/Unite/Test Standard Query Language) [DRAFT].

cucú


Nota para lectores del feed: el código SQL es más legible si lo ven formateado en la entrada original.


¿Qué es NUTS-QL? Para hacer honor a su nombre, comencemos por la negativa: NUTS-QL no es un dialecto SQL. NUTS-QL es una técnica de creación y mantenimiento de consultas SQL, un conjunto de prácticas y principios, y por lo tanto puede aplicarse en conjunción con cualquiera de los dialectos de SQL conocidos.

¿Cuáles son sus orígenes? NUTS-QL es una etiqueta bajo la cual se agrupa un conjunto coherente de técnicas que -por separado- son conocidas y utilizadas por innumerables desarrolladores a lo largo y ancho del globo. Esta compilación y su organización es obra, humildemente, de mi autoría.

¿Cuáles son sus ventajas? La principal ventaja de NUTS-QL es que va más allá de asegurar un código SQL legible: hace que la legibilidad sea irrelevante.

Vamos directamente a un ejemplo. El requerimiento será desarrollar el “Reporte de movimientos diarios”.

El primer paso es escribir lo primero que se nos venga a la cabeza, probar que compile y mandarlo a pruebas:

SELECT C.ID, C.DESCRIPCION, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
WHERE C.FECHA = @FECHA
ORDER BY C.FECHA

¡Y eso es todo! No hace falta documentar nada. En el improbable caso de que luego de un par de días, semanas o meses, a alguien le toque modificar la consulta, aplicará los principios de NUTS-QL.

Digamos que ahora se necesita que “en los movimientos de emisión de cheques (MOVIMIENTOS_CABECERA.TIPO=1) se presente el número de cheque emitido”.

Lo primero que tenemos que hacer es implementar el requerimiento con una consulta aparte que satisfaga sólo el caso mencionado. Si bien puede utilizarse la consulta anterior como base, usualmente es más fácil no preocuparse por lo que ya está hecho, que probablemente no sirva para nada. Otra vez escribimos lo primero que se nos viene a la cabeza:

SELECT C.ID, C.DESCRIPCION, CHQ.NUMERO, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
INNER JOIN CHEQUES AS CHQ ON CHQ.MOVIMIENTO_EMISION_ID = C.ID
WHERE C.FECHA = @FECHA AND C.TIPO = 1
ORDER BY C.FECHA

Ahora hay que integrar las dos consultas. Son tres fases. La primera es la de negación (Negative), en la que excluimos de las cláusulas anteriores los registros que incorporamos en la nueva. Esto es fácil porque podemos tomar el WHERE de la nueva y agregarlo en la primera precedido por los operadores AND NOT (ver que la línea 5 del ejemplo siguiente es la negación de la línea 5 del ejemplo anterior). La primera consulta nos queda:

SELECT C.ID, C.DESCRIPCION, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
WHERE C.FECHA = @FECHA
	AND NOT (C.FECHA = @FECHA AND C.TIPO = 1)
ORDER BY C.FECHA

La segunda es la de unión (Unite), en donde unimos las dos consultas con la cláusula UNION:

SELECT C.ID, C.DESCRIPCION, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
WHERE C.FECHA = @FECHA
	AND NOT (C.FECHA = @FECHA AND C.TIPO = 1)
ORDER BY C.FECHA

UNION

SELECT C.ID, C.DESCRIPCION, CHQ.NUMERO, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
INNER JOIN CHEQUES AS CHQ ON CHQ.MOVIMIENTO_EMISION_ID = C.ID
WHERE C.FECHA = @FECHA AND C.TIPO = 1
ORDER BY C.FECHA

La tercera es la de prueba (Test), que consiste en ejecutar y corregir hasta que funcione. En este caso hay dos problemas: el ORDER BY está repetido (va uno sólo al final) y la cantidad de campos en la sección SELECT no coinciden entre las dos partes (rellenamos con nulos donde sea necesario). Necesitaremos al menos dos intentos. El resultado será:

SELECT C.ID, C.DESCRIPCION, NULL AS NUMERO, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
WHERE C.FECHA = @FECHA
	AND NOT (C.FECHA = @FECHA AND C.TIPO = 1)

UNION

SELECT C.ID, C.DESCRIPCION, CHQ.NUMERO, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
INNER JOIN CHEQUES AS CHQ 
	ON CHQ.MOVIMIENTO_EMISION_ID = C.ID
WHERE C.FECHA = @FECHA AND C.TIPO = 1

ORDER BY C.FECHA

Es muy, muy improbable que surja una tercera modificación o error, pero agreguemos una a modo de ejemplo. Supongamos que nos enteramos de que “los importes en moneda extranjera (registros en los que MOVIMIENTOS_DETALLE.IDMONEDA <> NULL) no se están convirtiendo a la moneda corriente de acuerdo al tipo de cambio indicado en MOVIMIENTOS_DETALLE.COTIZACION”.

Apliquemos NUTS-QL. La consulta para los registros en moneda extranjera será:

SELECT C.ID, C.DESCRIPCION, 
	D.DEBE * D.COTIZACION, 
	D.HABER * D.COTIZACION
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
WHERE C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL
ORDER BY C.FECHA

Ahora, en la etapa de negación, debemos modificar la sección WHERE de las consultas anteriores negando la condición WHERE de la nueva sección (ok, son 2, pero es sólo copiar y pegar).

La primera queda:

WHERE C.FECHA = @FECHA
	AND NOT (C.FECHA = @FECHA AND C.TIPO = 1)
	AND NOT (C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL)

y la segunda:

WHERE C.FECHA = @FECHA AND C.TIPO = 1
	AND NOT (C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL)

Luego, en la etapa de unión nos queda:

SELECT C.ID, C.DESCRIPCION, NULL AS NUMERO, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
WHERE C.FECHA = @FECHA
	AND NOT (C.FECHA = @FECHA AND C.TIPO = 1)
	AND NOT (C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL)

UNION

SELECT C.ID, C.DESCRIPCION, CHQ.NUMERO, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
INNER JOIN CHEQUES AS CHQ 
	ON CHQ.MOVIMIENTO_EMISION_ID = C.ID
WHERE C.FECHA = @FECHA AND C.TIPO = 1
	AND NOT (C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL)
ORDER BY C.FECHA

UNION 

SELECT C.ID, C.DESCRIPCION, 
	D.DEBE * D.COTIZACION, 
	D.HABER * D.COTIZACION
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
WHERE C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL
ORDER BY C.FECHA

Ya en la etapa de test, nos damos cuenta de que (otra vez) el ORDER BY está repetido y de que tenemos que rellenar el SELECT de la nueva consulta con campos nulos para que coincida con el de las anteriores. El resultado final será:

SELECT C.ID, C.DESCRIPCION, NULL AS NUMERO, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
WHERE C.FECHA = @FECHA
	AND NOT (C.FECHA = @FECHA AND C.TIPO = 1)
	AND NOT (C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL)

UNION

SELECT C.ID, C.DESCRIPCION, CHQ.NUMERO, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
INNER JOIN CHEQUES AS CHQ 
	ON CHQ.MOVIMIENTO_EMISION_ID = C.ID
WHERE C.FECHA = @FECHA AND C.TIPO = 1
	AND NOT (C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL)

UNION 

SELECT C.ID, C.DESCRIPCION, NULL, 
	D.DEBE * D.COTIZACION, 
	D.HABER * D.COTIZACION
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
WHERE C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL

ORDER BY C.FECHA

Y listo, nuevamente a pruebas y producción.

Los puristas encontrarán que en aquellos registros que corresponden a cheques nominados en moneda extranjera no se está mostrando el número. En el cuasi-imposible caso de que esto se detecte nos llegará el requerimiento correspondiente. Normalmente deberíamos entender toda la consulta y buscar el error. Gracias a NUTS-QL simplemente hacemos lo de siempre.

Para abreviar les dejo sólo el resultado final de aplicar la técnica a este último caso (es un buen ejercicio que el lector lo haga por su cuenta y compare los resultados):

SELECT C.ID, C.DESCRIPCION, NULL AS NUMERO, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
WHERE C.FECHA = @FECHA
	AND NOT (C.FECHA = @FECHA AND C.TIPO = 1)
	AND NOT (C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL)
	AND NOT (C.FECHA = @FECHA AND C.TIPO = 1 
		AND NOT D.IDMONEDA IS NULL)

UNION

SELECT C.ID, C.DESCRIPCION, CHQ.NUMERO, D.DEBE, D.HABER
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
INNER JOIN CHEQUES AS CHQ 
	ON CHQ.MOVIMIENTO_EMISION_ID = C.ID
WHERE C.FECHA = @FECHA AND C.TIPO = 1
	AND NOT (C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL)
	AND NOT (C.FECHA = @FECHA AND C.TIPO = 1 
		AND NOT D.IDMONEDA IS NULL)

UNION 

SELECT C.ID, C.DESCRIPCION, NULL, 
	D.DEBE * D.COTIZACION, 
	D.HABER * D.COTIZACION
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
WHERE C.FECHA = @FECHA AND NOT D.IDMONEDA IS NULL
	AND NOT (C.FECHA = @FECHA AND C.TIPO = 1 
		AND NOT D.IDMONEDA IS NULL)

UNION

SELECT C.ID, C.DESCRIPCION, CHQ.NUMERO, 
	D.DEBE * D.COTIZACION, 
	D.HABER * D.COTIZACION
FROM MOVIMIENTOS_CABECERA AS C 
INNER JOIN MOVIMIENTOS_DETALLE AS D ON C.ID=D.ID
INNER JOIN CHEQUES AS CHQ 
	ON CHQ.MOVIMIENTO_EMISION_ID = C.ID
WHERE C.FECHA = @FECHA AND C.TIPO = 1 
	AND NOT D.IDMONEDA IS NULL

ORDER BY C.FECHA

Comentarios: se le achaca a este método producir sentencias cada vez más ilegibles e ineficientes. Pero hemos visto que no es necesario leerlas, por lo que el primer punto es irrelevante. En cuanto al segundo… bueno, eso es un problema de hardware ¿no?

Lo mejor de todo es que lograr la adopción de NUTS-QL es fácil: una vez que un desarrollador comienza los demás están obligados a seguirlo, basta con respetar el punto de no documentación de requerimientos (si éstos estuviesen documentados, un programador inexperto podría estar tentado a reescribir toda la sentencia). Así, es un camino de ida.


Nota para lectores del feed: el código SQL es más legible si lo ven formateado en la entrada original.

miércoles, 18 de febrero de 2009

Guía para el buen programador en un mal día.

cansancio Es bastante común encontrar colecciones de pequeños consejos de estilo de codificación, “tips” del tipo:

  • Comenta el por qué y no el cómo.
  • No copies y pegues sin entender qué es lo que estás copiando y pegando.
  • Los nombres de las variables deben indicar qué dato contienen (totalVentas) y no su tipo o uso dentro del código (auxDecimal).
  • No incluyas el nombre de la clase en el nombre de un método(Cliente.Actualizar en vez de Cliente.ActualizarCliente).
  • Resuelve el problema antes de comenzar a codificar.

… y un largo etcétera que pueden buscar por ahí. Es bueno conocerlos, releerlos de vez en cuando, tenerlos en la cabeza.

Así, como estamos motivados para codificar cada vez mejor, en forma más legible, elegante, eficiente y fácil de mantener, son de gran ayuda.

Pero hay veces que uno tiene un día de m***. Enojado con la tarea, el trabajo, el mundo o la vida en general. O sin ganas de trabajar. O tal vez medio dormido después de una noche de juerga.

Hay veces que uno no tiene ganas de hacer las cosas bien. El que diga que no le pasó nunca, miente.

Yo aconsejaría no codificar en ese estado “de desgracia”, pero hay veces que la tarea es ineludible o que la tarea misma es la que nos pone de mal humor.

Así que empecé a pensar en tips para programar “en esos días de angustia y dolor”. Se me hace bastante más difícil, sólo logré esbozar algunas propuestas:

  • ¿Seguro que no puede resolverse sin codificar?
  • ¿O mejor dejarlo para otro día?
  • En fin… Si estamos modificando algo, considerar borrarlo e implementarlo de vuelta. Lo que hagamos en este estado tampoco será de gran calidad, de todas maneras.
  • Es preferible no comentar el código a comentar cualquier cosa.
  • Al copiar y pegar código sin mirar borrar los comentarios copiados.
  • Para días no tan malos, seguir las dos indicaciones anteriores y poner un comentario al principio (también al final, ¿será mucho pedir?) de lo copiado, indicando qué pretendemos que haga (y una plegaria pidiendo que por favor lo haga).
  • Asegurarse de que el muerto quede encerrado en un sólo procedimiento o clase.
  • Prestar atención aunque sea a los nombres y parámetros de los elementos públicos, no hay por qué molestar a los demás con nuestra desgracia… ok, los nombres de los privados pueden quedar para otro día.
  • Lanzar una excepción del tipo NotImplementedException o similar para casos del tipo “nah, eso no se va a dar nunca”. Es mejor que algún caso raro falte y se note a que el sistema “siga de largo” haciendo cualquier cosa.
  • ¿Todo en un sólo procedimiento de 500 líneas o más? Bueno, por lo menos dejar un par de renglones entre las diferentes partes. O si el día no es tan malo ponerle una línea de guiones de separación.
  • Es mejor poner el código de un recurso inexistente que hardcodear una cadena en la interfaz con el usuario (odio cuando los sistemas quedan traducidos a medias).
  • La performance puede quedar para el final… o mejor para mañana. Funciona, ¿no?

La consigna es “algo es algo”. ¿Ideas?

jueves, 28 de agosto de 2008

Requerimientos: cuando no son asteroides sino sólo polvo cósmico.

Nota: esta entrada es una contribución de Cerebrado relacionado con la entrada Asteroides, que les recomiendo leer primero.

Hay veces en las que el requerimiento es la implementación de una solución.

¿Cómo? Analicemos.

Sí, hay veces en las que lo que se requiere es que se implemente una solución. Se entiende por solución una forma determinada, específica, de resolver de un problema. ¿Cómo? ¿No es así siempre? No, no debería ser así. El requerimiento debería ser el planteo de un problema. El equipo debería encontrar la solución.

Por las dudas va un ejemplo. Un requerimiento normalmente diría:

El sistema debe detectar que el saldo de una cuenta ingresa en rojo y alertar al ejecutivo de cuentas asignado al cliente.

Pero hay veces en las que dice:

Implementar un trigger sobre la instrucción insert de la tabla cuentas_movimientos. En este trigger, cuando sld_cnt - deb_pnd + crd_pnd sea menor a 0 insertar un registro en la nueva tabla notificaciones con los siguientes valores: ....

En vez de asteroides llega sólo polvo cósmico de esa nube de requerimientos de la que se hablaba en Asteroides.

Hay un intermediario que filtra, soluciona, resuelve... pero no comparte ni la información obtenida ni el método que usó para obtenerla.

En definitiva se requiere que escribas lo que otro pensó. Hasta ahí no habría mucho de qué quejarse, incluso hay gente que no es proactiva y a la que éste tipo de tareas le cae más que bien.

Uno implementa esa solución, sin saber qué resuelve. Actúa por el "cómo", y no por el "qué".

Pero luego ocurre un problema, un cambio en el requerimiento, la funcionalidad no trabaja como debería. Y ahora sí, nos llega un asteroide hecho y derecho con forma de reporte de error... ¿por qué no aparece de vuelta ese polvo cósmico con la solución detallada?

¿Y ahora qué se hace? En los restos del polvo cósmico original no hay piezas suficientemente grandes como para extraer información de cómo debería funcionar la cosa, ni de por qué funciona mal.

Entonces es cuando uno hace dotes de adivino, prueba y falla, busca al intermediario para sacudirle los bolsillos hasta que caiga al menos alguna piedrita... si lo encuentra (suelen tener la habilidad de aparecer y desaparecer a voluntad y escasa voluntad para ajustar sus propias soluciones). Así hasta que el intermediario queda satisfecho con lo que hemos hecho.

Puede tomar mucho tiempo, mucho esfuerzo, y el resultado puede no ser el óptimo.

¿Cuales son los resultados posibles?

  • Puede que hayamos entendido qué hicimos. Sería el mejor de los casos.
  • Puede que hayamos creído entender lo que hicimos.
  • Puede que no hayamos entendido un catzo.

Para cada una de las anteriores, puede que no nos importe... o que sí. La cosa anda, pero si vuelve a ocurrir algo en la nube (y con seguridad va a ocurrir) volveremos a recorrer el mismo penoso camino.

¿La falla es del intermediario, por no saber transmitir? ¿Por no confiar (con o sin razón) en el poder analítico de su subalterno? ¿Es nuestra, por conformarnos (y acostumbrarnos) a la información reticente? ¿Por no exigir / pedir más definiciones?

La falla es un composé de muchos puntos:

  • Comunicacional. El intermediario no sabe / puede / quiere comunicar.
  • De rango: porque cree que dar la menos información es tener más control.
  • De confianza: porque no confía en su gente.
  • De experticia: porque no sabe trabajar en equipo.
  • De incumbencia: porque el intermediario resuelve a ese nivel de granularidad aunque sus funciones no lo especifiquen.
  • De usos y costumbres: porque se han resuelto demasiados problemas de esta manera como para poder plantear la posibilidad de que haya algo malo en el método.

Ahora, la pregunta es... ¿queremos un asteroide o sólo polvo cósmico?

miércoles, 27 de agosto de 2008

eXtreme Programming es un arma peligrosa.

Algunas veces la búsqueda de la agilidad nos lleva al descontrol. Hay una zona gris en donde es fácil mezclar movimientos rápidos con desprolijidad (y sólo logramos ser torpes), eficiencia aparente con trabajo pendiente (y sólo logramos ser eficaces), cumplimiento de plazos con baja calidad (y apenas logramos llegar a tiempo a la fiesta de entrega, vestidos de traje pero sin calzoncillos). Resumiendo, a veces se confunde agilidad con velocidad.

Las presiones del negocio hacen que la búsqueda de la agilidad se vuelva obsesión (y esto es bueno). Tratamos de hacer lo menos posible de la manera más simple posible.

Así, planeamos a medida que avanzamos, nos integramos con el cliente, diseñamos a medida que construimos, construimos pensando en la reutilización y el cambio, integramos continuamente y utilizamos tests codificados en todo el proceso... o al menos eso deberíamos hacer, si seguimos los postulados de XP (Programación extrema, PE o eXtreme Programming, XP), a mi entender la metodología más obsesionada por la velocidad la agilidad.

Por desgracia muchos han leído la entrada en Wikipedia y han googleado, picando de aquí y de allí, pero pocos han leído el libro que da origen a la cosa, Extreme Programming Explained, de Kent Beck. No conozco a nadie que haya participado en un equipo ágil tal cual lo define el libro, aunque sí a algunos integrantes de equipos que de "ágiles" sólo tienen la etiqueta (no está mal tener sólo la etiqueta, siempre que uno sea consciente de ello).

Para que quede claro, antes de comenzar con el sarcasmo o de tirar ejemplos concretos: la belleza de XP radica en que es un sistema, y no una colección de partes que pueden reordenarse o intercambiarse a voluntad. Sin embargo, es esta belleza lo que lo vuelve peligroso puesto en manos de algún monito. Ya me explico.

Se suele utilizar XP menos para desarrollar que para defender lo indefendible y justificar lo injustificable por la supuesta búsqueda de "agilidad", opinando de oídas sobre un punteo de conceptos centrales. La frase "...pero XP recomienda..." debería estar prohibida en equipos que no implementan XP. Ahora sí, repartamos palos.

Monito de contacto con el cliente + Tijeritas + XP = Los requerimientos son cambiantes, toda documentación más allá de lo indispensable una pesada carga para el equipo que no aporta valor al cliente y la comunicación informal la más conveniente siempre. Entonces, como estamos muy apurados y tendríamos que haber empezado ayer, no pasemos los requerimientos por escrito. Esto es ágil.

Todos los antecedentes son correctos, eso es innegable. Pero eso no vuelve verdadera la afirmación. Lo que sigue al "entonces" es una barrabasada.

Por empezar, incluso en XP uno de los documentos requeridos (y en XP no hay muchos) es, justamente, el que especifica un requerimiento: la historia del usuario. Pensemos cuánta importancia tiene este documento que en la metodología más minimalista es requerido. Y no sólo eso. XP obliga a que el documento realmente exista, por ejemplo al centrar en él el proceso de planificación. Casi todas las tareas de XP se centran alrededor de éste documento.

Los requerimientos no son parte del sistema, los requerimientos **definen** al sistema. Por si no queda claro: yo puedo crear un sistema sin diseño, sin computadoras, sin código, sin empleados, sin nada. Puedo crear un sistema tan sólo diciéndole al cliente "haga esto y lo otro y luego esto otro". Si me pongo filosófico, puedo decir que puedo crear un sistema con sólo pensarlo (al fin y al cabo es una construcción teórica), y ni siquiera necesito comunicarlo para que exista.

Pero no puedo crear un sistema sin requerimientos, el objetivo es parte de la definición de sistema, explícitamente. En un sistema informático, los requerimientos son el objetivo, y por tanto son lo que hace que el sistema funcione. ¡En serio! A ver: tengo un programa que cada vez que lo ejecuto hace que Windows tire un BSOD... ¿Funciona? No sé, a ver los requerimientos... "es un sistema contable": entonces no, no funciona; "es un virus": entonces funciona perfectamente.

Ahora un poco más en serio: la memoria nos juega malas pasadas, los charcos se secan, a las palabras se las lleva el viento. Cuando surge una duda sobre un requerimiento, enormes porciones del sistema se tambalean. Si esperamos que los requerimientos cambien velozmente, tendremos que pensar en algo para no confundir los de la semana pasada con los de la anterior. Esto me ha sucedido: llega el requerimiento "A", luego el requerimiento "B = not A", luego el "A", luego el "B"... y así ad eternum. Si los cambios están separados por un par de meses jamás nos daremos cuenta de que en realidad la solución es poner un parámetro en la configuración... puedo hacer los cambios velozmente, pero que nadie me diga que eso es ser ágil.

El desarrollo de software no es más que un teléfono descompuesto entre el cliente y un algoritmo. La metodología no es más que un desesperado intento por arreglarlo. XP lo intenta minimizando la cantidad de "nodos" en la línea: el cliente mismo está al lado de los codificadores, escribiendo los requerimientos.

Conclusión: el monito de contacto ocupa un lugar clave en donde una palabra, apenas un pequeño malentendido, puede tener consecuencias imprevisibles. Sea precavido: domestique a su monito de contacto (recuerde que la letra, con sangre... entra).

Monito analista + Cuchillo dentado + XP = Los diseños se refinan durante la codificación, ya que sólo obtenemos una comprensión acabada del problema al resolverlo. Es un proceso iterativo. Por eso vos empezá programando con lo que más o menos te acabo de contar, después te paso el diseño y vemos. Esto es ágil.

De vuelta, correctos antecedentes con una conclusión mágica que sólo guarda una relación aparente con ellos.

En XP diseño y codificación van de la mano no porque sean procesos iterativos e incrementales (que se entienda: sí que son iterativos e incrementales, sólo que no es lo central en relación a éste aspecto de XP en particular), sino porque en XP parte del diseño (tal como se lo define tradicionalmente) se amalgama con la codificación, a fin de lograr una comunicación más directa entre el desarrollador y el cliente. No hay una actividad de diseño sin parte de codificación ni viceversa, por tanto un analista, a menos que pueda codificar, no podrá diseñar en un equipo XP (siempre hablando en el sentido clásico del término "diseñar").

En XP se especifica claramente que la historia del usuario le llega directamente a un par de programadores quienes, para empezar, la estiman por su cuenta (mientras el analista nos va a buscar un café), luego la planifican con el líder del proyecto (mientras el analista va por el azúcar... siempre se olvida del azúcar) y que finalmente van codificando y "elaborando el diseño" a medida que codifican (mientras el analista descansa un rato antes de volver a la máquina expendedora)...

Pero bueno, ya que éste analista trabaja en un equipo que no adopta XP, que haga el análisis que corresponde en vez de justificarse en cualquier cosa y pasarle un garabato de compromiso a un pobre programador que encima terminará haciéndole el trabajo, ya que el caradura no tendrá mejor idea que acercarse luego y preguntar "¿cómo lo resolviste?"... eso si alguna vez elabora los famosos documentos.

Luego hay un error en el código y no hay forma de saber qué es lo que el sistema debería hacer... ah, y es culpa del programador, que no siguió con las especificaciones (que él mismo le pasó -sin querer- al analista).

Para terminar esta sección, un divague futurista... un monito analista no debería ensalzar demasiado a XP. Esta metodología nos lleva por una senda que puede llegar a determinar su anulación en proyectos pequeños, tal vez en medianos y en una de esas en grandes. Lo rebaja a la categoría de ayudante de redacción (del cliente al elaborar las historias del usuario) y diseñador y ejecutor de tests funcionales... y yo me arriesgo a decir que incluso este último papel está un poco amenazado: la mayoría de los tests se pueden automatizar (sí, incluso muchos funcionales), así que si al analista no se le ocurren tests nuevos todo el tiempo, el pobre hombre ya no sirve para nada... perdón, sí sirve, está el tema del café... bueno, logramos acomodarlo, ¡bien por él! Sólo un analista es capaz de justificar su inacción utilizando una metodología que en una de esas lo deja sin trabajo (bueno, si lo pensamos bien... esto le da la razón al analista y a la metodología).

Monito programador + anteojos de recorte de la realidad + XP = El código es la documentación. Hay que diseñar a medida que se codifica. El código es compartido. Hay que tener coraje para hacer un refactory cuando es necesario. Así que no documento ni comento, charlo un rato con el analista y luego hago lo que mejor me parece donde mejor me parezca. Migré el front-end desde Java a .Net porque leí en un blog que la nueva versión es muy superior. Luego lo volví a Java (recodificando, no hacia atrás) ya que en otro blog aprendí varios temas de performance que me hicieron cambiar de idea. Luego descubrí Silverlight así que lo implementé (me quedó muy bonito) pero finalmente me enteré de que sigue en beta... me pareció que no era estable, así que en definitiva quedó en .Net. ¡Qué semana productiva! ¡Aprendí un montón!... Y es más ágil.

En el equipo en el que trabaja el monito de arriba no se programa de a pares, no hacen programación orientada al test, no se integra continuamente, no hay un representante del cliente en el equipo y no se elaboran historias del usuario ni se hace el juego de la planificación.

Pero al tipo le encanta XP (¡programadores al poder!) e intenta aplicarlo en todo lo que puede, porque es más ágil.

Usted, señor programador, que leyó hasta aquí con una sonrisa en los labios y con un ocasional "sí, es así, exactamente" en voz alta... usted, que seguramente le ha advertido al analista (que pasó frente a su escritorio en busca de un café) "tenés las horas contadas"... usted, gran orangután, es el peor de todos.

Porque es justamente usted, el programador, el que tendría que entender que no se puede pretender que un sistema funcione si le extirpamos arbitrariamente un pedazo de código y lo reemplazamos por otro que funciona bien... en otro sistema.

Porque seguramente usted se da cuenta de que así no funciona. Pero en vez de impulsar un cambio integral o buscarse un equipo más acorde a sus expectativas (o a su ansiedad) prefiere ser el engranaje que gira solo al doble de velocidad que los demás... muy ágilmente, por supuesto.

XP, como cualquier metodología, conforma un sistema. Cada punto de XP tiene una razón de ser dentro de ese sistema, no es una simple recomendación que "deberíamos" adoptar. Sólo por ejemplo: la codificación/diseño se apoya en la programación de a pares, que asegura que el diseño sea discutido al menos por dos integrantes del equipo. El refactory frecuente se apoya en la codificación orientada al test, ya que sin testeo automático es una actividad peligrosa. El minimalismo en la documentación funcional se apoya con la integración de un representante del cliente en el equipo al que se lo puede consultar continuamente, si no fuese así podría perderse mucho tiempo en la resolución de ambigüedades... todo tiene que ver con todo.

Por supuesto que hay que adaptar la metodología a cada caso particular. Y que sí se puede implementar parcialmente. Por ejemplo, sé que la programación de a pares es un punto usualmente resistido. Entonces, hay que compensar la no-adopción de esa práctica con algo... no sé, habría que probar. Podrían ser reuniones para fijar estándares de codificación, o revisiones formales del código, o una instancia informal de revisión del diseño... las posibilidades son infinitas. Tal vez algún comentarista con más experiencia en equipos XP pueda aportar un poco más sobre este punto.

Lo que queda claro es que la metodología es un sistema. Y, como a todo sistema, hay que conocerlo para modificarlo o adaptarlo, tomar esas modificaciones o adaptaciones con el debido cuidado, probarlas, etc... y no tomar frases sueltas para hacer mal lo que de todas maneras no había que hacer.

jueves, 21 de agosto de 2008

Pobre XML...

En los últimos días se le estuvo pegando bastante a XML en este blog.

Primero fue XML * Inconciencia, donde referenciaba un post de Lucas Ontivero con malas prácticas y delirios malos con XML.

Luego fue XML donde citaba "XML is like Violence, if it doesn't solve the problem, use some more".

Y encima estoy preparando un post sobre mi propio aprendizaje de XML, que se dio a través de la construcción de una aplicación web que almacenaba sus datos enteramente en XML... muchas frases en el estilo de "estaba aprendiendo" y un alto contenido de "mea culpa".

A ver, XML es una herramienta fabulosa, fácil de entender (casi intuitivo si uno viene del viejo mundo HTML), popular (con mucha documentación y herramientas disponibles), ampliamente utilizada (es *EL* estándar para intercambio de información entre aplicaciones) y sobre todo flexible.

Lo mismo que Javascript, ASP 3.0, PHP... antes de saltarme al cuello déjenme explicar qué les veo en común todos estos lenguajes: en todos ellos, sobre todo cuando se los ve junto a HTML o XML, es frecuente el abuso de alguna de sus características, sobre todo de aquellas que nos permiten esquivar rápidamente los tipos de datos o que tienen que ver con la ejecución de código generado "on the fly", o con el pasaje de datos del servidor al cliente, en divertidísimas combinaciones.

Creo que para muestra basta un botón. El ejemplo es una hermosa combinación de ASP 3.0, HTML y Javascript (¡qué lindos colores!). Lástima que no se me ocurrió generar XML embebido en la misma página.

El problema no está en la herramienta sino en cómo es utilizada, sobre todo en manos de un principiante (el código de ejemplo es mío, así que créanme que sé de lo que hablo). Como no me canso de repetir, ser un "junior" no implica solamente el manejo de una herramienta. Para el caso, en el momento en que escribí eso (que podemos llamar... un colorido desastre) tenía bastante idea de HTML, ASP y Javascript, pero no tenía la más mínima idea de cómo construir una capa de presentación en una aplicación web medianamente compleja, con lo cual terminé abusando de todo lo que sabía.

Uno puede saber todo sobre XML, pero se necesita bastante práctica para crear un documento coherente. Como la herramienta nos permite hacer casi cualquier cosa, estamos librados a nuestro criterio al momento de producir algo legible, que dependerá de nuestra comprensión teórica del modelo: ¿cuándo un dato es un atributo? ¿cuándo debe ser un nodo? ¿cuándo tengo que englobar varios nodos en un nuevo nivel?

También se necesita práctica para saber cuándo parar. Con XML podemos hacer de todo, pero eso no significa que debamos hacer de todo. En los post que mencionaba al principio se menciona el caso del sistema con una tabla única con dos campos del tipo "ID" y "XMLData" en el que se guardaban todos los datos de la aplicación. A ese tipo de cosas me refiero cuando menciono "saber cuándo parar".

Ésas no son preguntas fáciles de responder, y los programadores con poca experiencia tienden a subestimar las consecuencias, argumentando que son "bla bla bla teórico" y que "de cualquier manera funciona"... Algunos programadores con mucha experiencia piensan lo mismo, desgraciadamente. Son los que Rafael Gil en un momento de inspiración nombra "Programadores Romario" en su blog "Diario de un Director de sistemas".

Creo que el título XML * Inconciencia es perfecto. El problema es la inconciencia. De alguna manera todo el mundo reconoce que diseñar una base de datos es difícil, y que un error puede tener un serio impacto a futuro, así que en general se le presta la debida atención. Esto no sucede tan seguido con el XML (aunque diseñar un documento es prácticamente lo mismo que diseñar una base de datos), hay casos en los que se supone que es una herramienta sencilla y fácil de usar que nos puede sacar de apuros y que no merece mayor análisis. Termina siendo una navaja nueva para un monito aburrido.

En algún otro post comentaré con más detalle los casos en los que sí se utilizó XML razonablemente con muy buenos resultados, por ahora simplemente una lista:

  • Para archivos de configuración de la aplicación del tipo "web.config" o "app.config". Son el equivalente a los viejos archivos ".ini". La ventaja es que el XML documenta muy bien las secciones y los valores que puede tomar cada parámetro.
  • Para guardar datos que hacen a la estructura de la aplicación. Por ejemplo la relación entre página-controlador en un patrón MVC.
  • Para guardar parámetros por defecto que necesita la aplicación.
  • Como alternativa a los archivos de recursos (del tipo ID+Cadena) cuando se necesitan almacenar datos complejos.
  • Por supuesto, para intercambiar datos entre aplicaciones. Pero con cuidado, no puede ser gran cantidad de información (XML es muy ineficiente en cuanto a tamaño) y, sobre todo, que sea simple: descargo a un archivo la información (o cualquier equivalente) y punto.

Dos puntos importantes:

  • Mantener siempre actualizada la documentación sobre la estructura del archivo. Si es un XSD o un DTD, mejor. Si la aplicación lo valida al levantar los datos, perfecto.
  • Siempre encapsular el archivo en una clase que devuelva los datos tipados al resto de la aplicación. Es fácil, no cuesta nada, mucho más cómodo que buscar todo el tiempo en XML (por ejemplo utilizando XPath en todos lados) y encima ahorra un montón de problemas a futuro, permitiéndonos cambiar la estructura del archivo prácticamente sin impacto.

Como conclusión: XML es grandioso. Pero, como toda herramienta, no puede ser utilizada a la ligera. Es tan fácil y divertido como buscar un poco en Google antes de empezar.

miércoles, 20 de agosto de 2008

Más antipatrones.

José M. Aguilar publica un muy buen resumen de antipatrones en esta entrada de Variable Not Found. Por otro lado, hace un par de meses yo había traducido algunos que no encontraba en castellano (un poco más en joda) y los había posteado en Antipatrones de diseño.

Vía Cerebrado (muy despierto hoy, vamos a desenchufarlo un rato).

lunes, 18 de agosto de 2008

XML

Una frase rescatada de los comentarios de la entrada Worst Practices... del blog de Tom Kyte.

XML is like Violence, if it doesn't solve the problem, use some more.

No puede ser más cierto, y tiene mucho que ver con el contenido de la entrada XML * Inconciencia que publicaba acá hace unos días.

Actualización: pueden descargar la presentación de Tom Kyte a la que se refiere el post y que menciona el comentario de Improbable aquí (el link del post original está roto).

miércoles, 13 de agosto de 2008

¿De dónde sale ese olor?

En este preciso momento le estamos poniendo el moño a una versión de nuestra aplicación principal con vistas a una certificación bastante exigente, que incluye auditoría del código. Hay que imaginarse la situación del negocio: una vez certificada, cada corrección en la versión insumirá los $$$ correspondientes a las horas de laboratorio necesarias para aprobarla de forma que no se pierda el aval... y no regalan la hora, precisamente.

Cuestión que mi vida laboral en estos días ha sido un constante ping-pong entre un par de cuestiones amplias (de esas que llevan al menos unos días) y un millón de micro-incidentes que se van llevando 10 minutos, 15 minutos, 1 hora... más el tiempo necesario para cambiar de tarea.

Lo extraño es... soy más productivo así. Muchas veces, cuando me enfrento a tareas de largo tiro quedo "colgado" en la búsqueda de alguna idea que resuelva una cuestión que me impide seguir. Al tener un bonito stock de tareas de menor alcance (y también de menor exigencia de concentración), logro ese estado que describía en "Codificando... divagando... es lo mismo", al tiempo que combato la inevitable ansiedad que se produce al no estar codificando (por más experiencia que uno tenga, en algún punto del cerebro sigue encerrado ese tumor que dice "si no estás tecleando no estás trabajando").

No hay con qué darle. Por más tonto que parezca una buena cantidad de cuestiones menores (pero necesarias) resueltas en medio día levantan el ánimo y nos preparan para la hora de airear ese muerto maloliente que se está pudriendo debajo de la alfombra.

Y así tangencialmente, llego al centro de la cuestión, ponerle el moño a la aplicación. Como decía, es importante... un segundo, ¿de dónde sale ese olor?

  • Mmmm... necesito arreglar el incidente ése del ítem de menú que pertenece a más de un módulo... ¿Cómo definimos los menúes? Ah, si... para cada módulo varios menúes... psssss, qué olor.
  • Ah, en los ABM genéricos hay que desactivar las funcionalidades no permitidas de acuerdo a determinado estado del sistema. A ver... ah, es un componente independiente que actualiza directamente la base de datos... ¡cuántos gusanos!
  • Todo cumple con las especificaciones. Para borrar un cuestionario tengo que borrar a mano todas las preguntas asociadas, si no es peligroso. Pueden haber cientos de preguntas asociadas a un formulario... a ver... selecciono (sólo puedo una), click, detalle, eliminar, aceptar... selecciono otra, click, detalle, eliminar, aceptar... ¿levanto la perdiz o traigo la pala?
  • Bien, ahora sólo tengo que reutilizar esta clase, que por suerte está bien encapsula... ¿¡qué es este agujero!?
  • ¿Alguien sabe para qué sirve el método "object FactoryBackdoor(string className)"? (Respuesta: silencio)

Se entendió el punto. Toda aplicación tiene un cuartito con olor extraño y muchas moscas, (si no pregúntenle a Microsoft).

¿Cómo se define un muerto? Arriesgo una teoría:

  • Al menos uno del equipo sabe que está ahí.
  • La funcionalidad no es central.
  • El problema crece (se pudre) lenta pero ininterrumpidamente.
  • Se encuentra en un área del código que cae bajo la responsabilidad de más de una persona... o ninguna.
  • Pero por más encerrado que esté "en algo" (el olor) afecta al resto de la aplicación.
  • La corrección puede ser obvia pero muy trabajosa o peligrosa de implementar.

¿Y cuáles son los síntomas?

  • Algo se hace cada vez más grande, o algo se hace cada vez más lento.
  • En la reunión de avance tal tema se da como "implementado". Alguien está mirando al suelo. No hay comentarios.
  • Ciertas conversaciones se interrumpen o cambian rápidamente al aproximarse un analista o el líder de proyecto.
  • Alguien se queda sistemáticamente un rato más, sin que nadie se lo pida (probablemente esté moviendo el cadáver).
  • Surgen ideas locas para problemas aparentemente simples. Todos los programadores buscan la forma de no tocar "tal cosa".
  • Un incidente rebota como pelota de ping pong (a mí me rebota y a vos te explota).
  • Che, ¿cómo puedo hacer "tal cosa"? Cric-cric (grillos, todos muy concentrados en su trabajo).
  • Todos estamos tranquilos, pero alguien está muy nervioso.
  • Para alguna tarea sencilla alguien presupuesta un número desproporcionado de horas (o sabe lo que se va a encontrar, o piensa quemar el cadáver ocultándose en esas horas).
  • Intercambio de miradas cómplices, conversaciones en voz baja ("sé lo que hiciste la semana pasada").

¿Mas definiciones / ejemplos? Manden a los comentarios.

domingo, 10 de agosto de 2008

XML * Inconciencia

Quería destacar de la lista de "Lo que leo" este post en el blog de Lucas Ontivero con una pequeña pero detallada lista de delirios y cosas raras que se pueden hacer con XML.

Me llama mucho la creatividad con la que algunas personas reinventan la rueda (dejándola cuadrada).

miércoles, 6 de agosto de 2008

Implementando y manteniendo soluciones

Por soluciones entiendo aquello a lo que me refería en este post de hace unos días. Transcribo aquí lo mínimo para que no me tomen por las ramas, pero les recomiendo leerlo antes de seguir.

[...] puede pensarse en un parche y una solución para cada problema [...] El parche es la actividad que resuelve la situación puntual, mientras que la solución es un cambio en la metodología de trabajo o en el circuito administrativo dentro del equipo que torna imposible la situación que originó el error. [...]

Me quedé pensando en eso, llegando a relacionarlo con este otro, en el que divagaba sobre "El soporte del conocimiento". Hablaba sobre organizaciones en las que el conocimiento era soportado por los procesos y organizaciones en las que era soportado por las personas:

Si combinamos la "orientación a resultados" por parte de los jefes con la "obligación de acudir todos los días" por parte de los trabajadores, tenemos una organización en la cual el conocimiento está basado en el proceso. Lo asocié rápidamente con algunas las grandes consultoras de software, en las que los procesos están fuertemente establecidos y el trabajo es realizado por una pirámide de programadores [...]
En el otro extremo, si juntamos "orientación a las personas" por parte de los jefes y "realización personal" por parte de los trabajadores, podríamos suponer que el conocimiento está asentado en las personas. La imagen es la de un pequeño equipo de trabajo en el que las soluciones son discutidas entre iguales [...]

Juntando:

Los parches **provienen** del conocimiento almacenado en la organización, ¿de dónde si no? (acepto sugerencias). Si este conocimiento está soportado por procesos puede implicar, por ejemplo, la búsqueda de una serie de acciones a seguir en una "Knowledge Base" corporativa o el ingreso de un ticket a un sistema de incidencias. Si está soportado en las personas sería la típica situación en la que ante un problema alguien nos dice "preguntále a Fulano que es el que la tiene clara con eso".

En cambio las soluciones **aportan** al conocimiento en la organización. Nuevamente tenemos los dos extremos: este aporte puede estar materializado en un nuevo circuito administrativo comunicado formalmente mediante un memo o establecido en un sistema (conocimiento soportado en procesos), o en la mejor coordinación que surge en el equipo, mejores prácticas que se van comunicando, imitando y fortaleciendo entre y por sus integrantes (conocimiento soportado por las personas).

¿Qué pasa con esas soluciones a lo largo del tiempo? Pienso sobre todo en una pyme, en donde el conocimiento está esencialmente soportado por las personas.

Luego de incorporarme al equipo que ahora integro se sucedieron cambios de personal más o menos constantemente hasta ahora. Luego de casi dos años y medio sólo quedan dos personas del equipo original. Se fueron 5 y entraron 6 (algunos de los que entraron se fueron, se entiende) de un equipo que quedó más o menos formalmente establecido en 6 personas. Por suerte todos los que se han alejado lo han hecho en buenos términos y en forma más o menos espaciada en el tiempo (sólo por suerte). Conociendo por referencia casos de estampidas o reducciones masivas tengo que reconocer que todo se ha ido dado de una manera bastante tranquila, con apenas uno que otro sobresalto puntual.

Volvamos a la pregunta, ¿qué ha sido de aquel cúmulo de soluciones, de prácticas, de procedimientos, de relaciones de comunicación? Ha volado por los aires, por supuesto, y poco queda de ello.

Por un lado esta rotación, lenta pero continua, nos ha puesto en una senda de "formalización informal" (léase "paperless") creciente a tono con el perfil de los que fuimos entrando (se imaginarán sólo por el contenido de este blog cómo viene la mano por casa... y encima no soy el único).

No puedo decir que no hemos mejorado... pero esto es decir nada, ya que el conocimiento está basado en las personas, por lo que se produce una necesaria adaptación entre el equipo y cada uno. El que no se adapta se aleja o fuerza una adaptación o alejamiento por parte de los demás (dependerá de la relación de poder)... y los que queden siempre sentirán que fue para mejor, o por lo menos soportarán estoicos.

No se queden con la idea de que "para cada parche encontramos una solución" ni con que "cada solución fue consensuada e implementada exitosamente"... ni mucho menos. Para lograr algunos éxitos hay que pasar por un sinfín de pruebas, correcciones, errores, fracasos y vueltas atrás.

Pero lo interesante entonces es ver cómo se fueron dando los cambios que finalmente quedaron establecidos exitosamente, qué los diferenció del resto.

  • Fueron cambios pequeños, los intentos de "ponerse de acuerdo para ordenar todo el circuito" no funcionaron, incluso cuando estábamos todos de acuerdo.
  • Respondían a algún problema específico que se había repetido un par de veces. Si el problema no se repite tal vez no sea necesaria ninguna "solución". Por otro lado fue bueno "parchear la cosa" un par de veces para tener en claro de qué se trataba. Usualmente el origen del problema no está donde se presenta.
  • Propuestos e impulsados por pocos y llevados a consideración del resto. Ojo, no simplemente comunicados y mucho menos impuestos. Es mejor que una o dos personas presenten una propuesta -que puede "rebotar" un par de veces hasta llegar a una versión aceptada- que una eterna mesa redonda.
  • ...y muchas veces la comunicación fue simplemente "a ver, hagamos esto"... y es obvio cuando no funciona.
  • Siempre participaron los afectados. Una mirada de afuera está bien, pero tiene que ser solamente eso, una mirada de afuera.
  • Ninguna fue una solución óptima ni definitiva, sino simplemente un paso. Creo que la búsqueda de la perfección paraliza.

Probablemente me esté olvidando de algo (o pifiando en algo, veremos), espero no demasiado central. Quiero recalcar, sobre todo por esta última parte, que es mi experiencia, tal como yo la veo, y una generalización más bien en abstracto sobre eso. Es decir, en resumen, que como todas las cosas está puesta a prueba.

jueves, 31 de julio de 2008

Monitos con navaja

Leyendo este post en La pastilla roja me encontré con la descripción del siguiente experimento:

Uno de mis experimentos favoritos sobre el comportamiento es aquel que se hace con unos monos y un manojo de plátanos. Cada vez que un mono se acerca al manojo para coger un plátano se propina una descarga eléctrica al resto del grupo. Con el paso del tiempo los monos aprenden y se dedican disuadir por la fuerza a cualquiér congénere que trate de acercarse a la fruta.

Hasta aquí todo es muy lógico, lo curioso sucede cuando se van reemplazando los monos previamente electrocutados por otros que nunca sufrieron dicho castigo. Estos monos continúan propinando palizas a quienes se acercan a los plátanos a pesar de que ellos mismos nunca sufrieron los efectos de las descargas eléctricas hasta con que, con el paso del tiempo, se pega a cualquier mono que trate de acercarse a los plátanos sin que ninguno de ellos sepa porqué lo hacen.

La vida está llena de comportamientos que fueron útiles en un pasado lejano pero que han dejado de serlo largo tiempo atrás.

Es muy común encontrarse con este tipo de cosas en cualquier equipo de desarrollo. Un nuevo programador que se integra a un equipo suele sufrir mucho este tipo de situaciones. Al tener una mirada fresca sobre el código (y también sobre sus nuevos compañeros de trabajo), percibe claramente este conjunto de prácticas (algunas graciosas otras no tanto) que tienen más que ver con la historia o la cultura creada en el equipo que con cuestiones técnicas o lógicas. Prácticas que en algún momento tuvieron sentido pero ya no, y que nadie se ha molestado en cuestionar. Pecando con un poco de soberbia, el nuevo a veces tiende a pensar que sus compañeros no piensan demasiado (¡error!).

Si en este punto esperan comentarios sarcásticos sobre ese tipo de cosas, esta vez los voy a desilusionar. Si bien es claro que estas actitudes tienen sus vicios, son la otra cara de la moneda de lo más básico del proceso de desarrollo de software.

Porque esta repetición "sin sentido aparente" es consecuencia inevitable (y deseable) de la división por capas, el encapsulamiento y la división de tareas. A ver, seamos claros. Si tengo que programar la funcionalidad X y se que tengo que utilizar "MiClase"... ¿miro el código de "MiClase" para entender exactamente cómo funciona o miro código con funcionalidad parecida a la que tengo que hacer y que también utiliza "MiClase" para entender cómo se usa? ¿Hay algo de malo en esto?

Tal vez a alguno se le cruce por la cabeza "copiar y pegar sin pensar". No, no estoy hablando de esa situación (que también existe, pero esto es otra cosa). El programador mira el código, lo interpreta, lo entiende y lo encuentra razonable sin entrar en detalles. Entonces toma la referencia que necesita y la adapta.

Como programadores, tomamos mucho de lo que vemos "como está", sin cuestionarlo demasiado. Y cuanto más éxito tenemos en este camino, más reforzada se ve esta conducta. Podemos hacerlo si el proyecto está bien estructurado y el código es parejo en cada capa, que es lo esperable. Si el proyecto es una sopa de algoritmos ni siquiera encontremos qué copiar.

¿No les parece que hay algo como que está mal? Sí, las palabras. Si en vez de empezar este artículo hablando de monos pegándose unos a otros hubiese comenzado con "la documentación de referencia más importante es el código" todo sonaría mucho más lindo. ¿Por qué decimos que "el código es la referencia más importante" y utilizamos esa frase para obligarnos a respetar los estándares y las buenas prácticas hasta en las funciones más triviales? Porque todo el código, TODO, es pasible de ser utilizado como referencia, nos guste o no, de manera controlada o no.

Si dejamos una lógica medio enrevesada dando vueltas por ahí, o algún código comando, pensando "bueh, pero esto está encapsulado acá, y es algo sin relevancia"... volvemos dentro de tres o cuatro meses y lo vemos esparcido como un virus por todo el sistema... como TODO el resto del código, por otro lado. Sólo que cuando ese código "esparcido" no tiene nada de malo, prácticamente no nos damos cuenta.

Pero sí hay algo que está mal: volvamos al "nuevo". El tipo va y pregunta "¿por qué esto está hecho así?" Y le contestan "porque se hace así, siempre lo hicimos así". Esas no son razones para dar a nadie.

La respuesta más correcta sería "no sé, siempre lo hacemos así, pero si querés ver bien fijáte en tal lado". Es decir: obviamente nadie tiene en la cabeza el por qué de todo, pero si es indispensable que la estructura del proyecto permita inferir dónde está el por qué de todo. Yo no sé "por qué", pero sí sé que hay un por qué, y dónde buscarlo, por las dudas.

Y hay que estar abierto al cambio, a la mejora. Sigamos la anécdota. El nuevo va, mira, entiende, y como lo ve razonable se olvida de todo, no hay nada del otro mundo allí. Eso se repite un par de veces (digamos de paso que éstas son las "conductas observables" por las cuales se transfiere la cultura) mientras va aprendiendo un poco cómo se hace todo. Hasta que en una de esas sí encuentra algo que no tiene sentido.

¿Qué hacemos? Bueno, espero que haya quedado claro que la frase "dejálo y hacélo como siempre, siempre lo hacemos así" no tiene sentido, mucho menos ahora.

La opción de máxima sería corregir y corregir todos los lugares en donde esa incoherencia se ha "copiado y pegado", que es el equivalente a erradicarlo. Pero la realidad es que a menos que el proyecto esté infectado con ese tipo de cosas por todos lados (en tal caso está desahuciado), es más probable que el tema sea más o menos benigno. En este caso, alcanzará con cambiarlo de aquí en más y tal vez, de a poco el código corregido se distribuya tanto como el otro lo hizo en su momento.

Voy a por mi plátano, hasta el próximo post.