jueves, 29 de mayo de 2008

Eficacia vs. eficiencia del programador.

El mataburros define programador como "Persona que elabora programas de ordenador." (segunda acepción, que es la que viene al caso). Si buscamos programa nos encontramos (entre otras, 12ava acepción) con "Conjunto unitario de instrucciones que permite a un ordenador realizar funciones diversas, como el tratamiento de textos, el diseño de gráficos, la resolución de problemas matemáticos, el manejo de bancos de datos, etc.".

Así que llegamos a la asombrosa conclusión de que un programador es una persona que elabora un conjunto unitario de instrucciones que permite a un ordenador realizar funciones diversas... etc.

Me voy a tomar la libertad de agregar una condición, que no por obvia es menos importante: "...que permite a un ordenador realizar funciones diversas en razonable concordancia con sus deseos..." Es decir, el ordenador tiene que realizar las funciones que el programador quiere y no otras, y esta igualdad debe ser "razonable" porque ya sabemos que todo software tiene errores.

Entramos en terreno escabroso, ya que "razonable" es un adjetivo muy subjetivo. Así que, en un acto de descarado libertinaje, modifico y agrego un tercer elemento: "...en razonable concordancia con los deseos de quien utiliza o requiere tal función...". Ha nacido el usuario o el cliente.

Bien. Llego entonces a la conclusión de que un programador es quien puede hacer que un ordenador haga razonablemente lo que el usuario o cliente desea, según la subjetiva evaluación de este último. Tengo que recordar en este punto que ya no se trata de una definición de diccionario sino de mi personalísima y discutible opinión, ya que la he modificado bastante. Pero es justamente esto lo que quiero expresar.

Decir que un programador es "eficaz" es una tautología (segunda acepción: "Repetición inútil y viciosa.", como estos links que ya me cansé de poner). Si no soy eficaz no soy programador.

Una empresa que desarrolla software contrata personal que se dice programador. Con el paso del tiempo esto queda demostrado: hace su trabajo entregando software que funciona razonablemente (es eficaz) o lo echan con justa causa, ya que la persona ha engañado a su contratista diciendo poder hacer lo que no puede.

Ahora, ¿qué parámetros se tienen en cuenta en la evaluación que toda empresa o equipo de trabajo hace de sus integrantes y que implica premios, ascensos, vacaciones o al menos renombre entre sus pares y respeto por parte de sus superiores? A veces, sólo la eficacia. Por ejemplo: se entrega un premio por proyecto completado (a secas, no "completado en tiempo" ni "completado y certificado por la norma xyz"). Es decir, se premia a una persona simplemente por hacer su trabajo, por hacer lo mínimo indispensable que define su puesto. Pero se supone que un premio o el renombre y el respeto van de la mano de una habilidad que está por encima de la línea base. Es como si en una facultad me dieran un premio o gozara de renombre académico por aprobar con 4 (el mínimo requerido). ¿Me recibo con un 4 en todas las materias? Sí. ¿Soy tan "Licenciado en Sistemas" como cualquier otro? Sí. Pero no es menos cierto que soy el "peor Licenciado en Sistemas" posible, ya que si tuviese menos de 4 no sería ni Licenciado (es sólo una analogía para graficar la cuestión, ya sé que luego en la vida profesional es donde se demuestran las verdaderas aptitudes, etc.).

Esto sucede porque a veces se comete el error de medir la calidad de un software solamente desde el punto de vista del cliente, interno o externo. Y esta falencia tiene que ver con el hecho de que incluso para un Líder de Proyecto es difícil obtener otras medidas sobre la calidad del producto de un programador y de su desempeño.

En resumen: un programador se define por su eficacia. Pero su desempeño debe medirse por su eficiencia. ¿Qué es la eficiencia, dentro del marco de este artículo? Lo uso como sinónimo de la suma de legibilidad, mantenibilidad, corrección, simpleza, ese tipo de cosas.

Es tan dificil para un no-programador (cliente, analista funcional, líder de proyecto) medir la eficiencia de una porción de código o de un sistema como fácil lo es para sus compañeros de equipo. Todos nos damos cuenta cuando "esta parte no te quedó muy bien", o cuando "ese sistema está podrido por dentro".

Hay otra cuestión sutil, que es muy interesante: el miembro más inexperto del equipo es el que tiene, a mi entender, la opinión más relevante. Si éste programador -que puede ser un junior en su primer desarrollo- entiende el código (obviamente con la tutela necesaria), le resulta claro y fácil de modificar o depurar, y muestra un claro progreso y adaptación espontáneos a medida que adquiere experiencia, es motivo de orgullo para el que lo escribió así sea el más experimentado programador del mundo. Mucho más que la opinión de otros compañeros más expertos, quienes a veces ni ven las ambigüedades por conocer bien el sistema, y ni que hablar del cliente, que sólo puede ver que hemos hecho nuestro trabajo, que es lo mínimo que él espera, o del Líder de Proyecto que a veces -remarco "a veces"- sólo evalúa los proyectos mediante "horas ejecutadas vs. horas presupuestadas".

¿Nunca se han sentido frustrados por la reacción de un cliente ante un software del cual el equipo está justificadamente orgulloso? Yo los consolaría diciendo (y me consolaría, porque también me pasa) "¿qué esperábamos?". El fruto de nuestro especial esfuerzo, de nuestro apego a rajatabla por los estándares y el buen diseño ha sido oculto por esa empaquetadora llamada compilador antes de llegar a sus manos.

El esfuerzo tiene su recompensa. El código es mantenible, los errores, muchos o pocos, se corrigen sin grandes problemas, el sistema es escalable y la nueva funcionalidad resulta más sencilla de desarrollar ya que tiene una base estable. Pero... muchas veces se premia más a quien se esfuerza por corregir errores y trabaja a deshoras que al que ha desarrollado código mantenible, y por ello logra resolver cada cuestión en un par de minutos, retirándose temprano. Incluso vemos que el que se fue temprano no ha tenido oportunidad de demostrar su "compromiso", y con suerte nunca se presente.

No soy un experto en medidas de la calidad interna del software, así que no puedo presentar el formulario de evaluación mágico que resuelve el problema del Líder de Proyecto, que a esta altura debe estar pensando "bueno, sé que esta situación existe ¿pero cómo evalúo en concreto el desempeño de cada uno?". Me quedo con esta pregunta, y con el plan de googlear un poco en busca de respuestas, que seguro que las hay.

Resumo, para finalizar, los conceptos centrales de todo este artículo:

  • Todos hacen, no todos hacen bien, y nadie hace bien siempre.
  • Todos los programadores somos eficaces. Es la eficacia (o al menos su apariencia, real o no) ante los superiores, clientes y compañeros lo que nos mantiene dentro del equipo. Nuestro esfuerzo debe concentrarse en ser cada vez más eficientes. Para esto no hay límites.
  • Necesitamos de la buena opinión de nuestros clientes (internos o externos) para sobrevivir. Condición necesaria, pero no suficiente.
  • Es la opinión de nuestros compañeros de equipo que conocen a fondo nuestro trabajo la que más debemos tener en cuenta para determinar si somos buenos en lo que hacemos o no, y es a ellos a quienes tenemos que acudir o prestar atención para ver qué es lo que se puede mejorar (si es que queremos hacerlo).

Cómo NO migrar una aplicación de ASP clásico a ASP.NET.

Hoy estoy un poco fiaca para la escritura, así que los dejo con este espectacular relato. Lectura recomendadísima, les paso los links:

Habrá que esperar por la tercera parte, que parece que la hay. Visto en Los senderos de .Net.

Boomerangs

Visto en Nulleando. ¡La relación con post anteriores es absolutamente intencional!

Jaja. Perdón, hoy tuve un día difícil y me salen chistes malos.

miércoles, 28 de mayo de 2008

Principios de diseño

Traducción de los principios que resumió Tim Peters según el BDFL Guido van Rossum en 20 aforismos, de los cuales sólo 19 han pasado a forma escrita (nota para procrastinantes: seguir los links de la frase anterior).

  • Hermoso es mejor que feo.
  • Explícito es mejor que implícito.
  • Simple es mejor que complejo.
  • Complejo es mejor que complicado.
  • Plano es mejor que anidado.
  • Disperso es mejor que denso.
  • La legibilidad cuenta.
  • Los casos especiales no son suficientemente especiales como para romper las reglas.
  • Aunque lo pragmático gana a la pureza.
  • Los errores nunca deberían dejarse pasar silenciosamente.
  • A menos que se silencien explícitamente.
  • Cuando te enfrentes a la ambigüedad, rechaza la tentación de adivinar.
  • Debería haber una -- y preferiblemente sólo una -- manera obvia de hacerlo.
  • Ahora es mejor que nunca.
  • Aunque muchas veces nunca es mejor que “ahora mismo”.
  • Si la implementación es difícil de explicar, es una mala idea.
  • Si la implementación es sencilla de explicar, puede que sea una buena idea.
  • Los espacios de nombres son una gran idea -- ¡tengamos más de esas!

Codificando... divagando... es lo mismo.

Hace un par de días (en realidad hoy pero no creo que postee esto hasta dentro de un par de días) tuve un amigable intercambio de opiniones con un muy respetado compañero de trabajo, mientras volvíamos a nuestros respectivos hogares. Sé que puede sonar irónico así que aclaro que no lo es, realmente fue un amigable intercambio de opiniones.

En general me cuesta bastante mantener el foco de una discusión amigable cuando no tengo un interés especial en ella y se me presenta como una típica charla inconducente entre amigos. Así que derivamos de aquí para allá hasta hablar de mujeres, tema final para cualquiera de estas situaciones.

Así que antes de hablar de mujeres, hablábamos alrededor de lo que es "programar" (mujeres y computadoras, mujeres y autos, mujeres y fútbol, qué típicos que somos), momento en el que divagué un poco acerca de lo que yo pienso cuando escribo código, tema que pasó pero que me quedó dando vueltas.

El hecho es que quisiera explayarme un poco sobre eso, no para adoctrinar ni para enunciar la verdad revelada -que no la es, realmente- sino porque me da curiosidad saber si es una forma rara de ver las cosas o si por el contrario alguna o mucha gente coincide conmigo.

Vamos primero por la negativa. Cuando programo:

  • No pienso en el problema, porque cuando estoy tecleando es que ya lo tengo resuelto (mi despliegue físico de resolución de problemas se acerca más a la imagen de un tipo tomando una siesta o vagueando por ahí que a la de uno trabajando).
  • Tampoco pienso demasiado en el código en sí mismo, porque ya hace casi dos años que programo en C# con el .Net 2.0 todos los santos días y tengo buena memoria para el lenguaje.

¡Caramba (por no decir mi...)! ¿Es que pienso en algo? Esto explicaría muchas cosas...

Y es que no, no estoy pensando si se entiende por ello el buscar una solución a un problema, o el buscar algo en la memoria. Más bien estoy en un estado parecido al de este mismo momento (ésa es la idea que me llamó la atención). Estoy escribiendo, como quien escribe un documento, una carta, o lo que sea. Y como todo autor, le escribo a un lector imaginario (¡en serio!).

Programo más o menos como escribo. Primero largo todo de una tirada, una especie de memory dump, y después la voy repasando y repasando y repasando, hasta que queda algo que me parece que se entiende. Después compilo, arreglando siempre errores de tipeo o causados por las sucesivas correcciones y pruebo. En general si la prueba no sale bien -sin contar detalles menores que de esos hay miles-, me doy cuenta de que me equivoqué en la resolución del problema (no en la codificación) y vuelvo a ese estado de somnoliencia o vagancia que mencioné antes, que es el de la resolución del problema (por ejemplo ahora que escribí un montón, voy a releer, y talvez borre esta misma frase... ya releí, se queda).

Esto me trae una serie de interesantes reflexiones sobre mí mismo, así que el lector aburrido o molesto por mi estado de brutal egocentrismo (por ahora es MI blog) puede abandonar en este punto, no sin antes comentar si le pasa lo mismo o no, o cómo es que le pasa.

Me cuesta horrores explicar cómo resolver un problema codificando porque yo no lo resuelvo de esa manera. Nunca llegué a entender esos métodos de resolución semi-automáticos que van desgranando la cosa mecánicamente. Uso el lenguaje, los gráficos y las herramientas para ayudarme a dividirlo en partes manejables e ir enfocándolas de a una, para ir anotando, pero no para resolverlo.

Sostengo que el código que no entiendo no sirve, porque me considero un buen lector de código. Creo que nos pasa a todos los que sabemos leer. Si uno lee y no encuentra el más mínimo sentido no dice "esto debe decir algo pero yo no lo entiendo", sino "esto no es castellano". Bueno, yo pienso "esto no es código". Tiendo a evaluarlo por su nivel de comprensión, no por su eficiencia u optimización (tengo que aclarar que usualmente trabajo con sistemas administrativos, en los cuales la optimización es requerida sólo en algunos procesos muy acotados).

A veces escribo (codifico) mal, lo sé porque hay veces que me leo y no me entiendo. Muchas de esas veces ni siquiera recuerdo haber escrito "esto" (y lanzo un par de amenazas del tipo "¿quién hizo tal cosa?" y quedo bien ridículo cuando el magnánimo control de código fuente me apunta con un dedo condenatorio). En general es cuando lo hago por obligación, y no por un deseo propio.

Bueno, ¿alguien llegó hasta acá? ¡Hey! ¡Ya es de día! ¡Hay que levantarse! Si alguien llegó hasta acá que se haga cargo y deje un comentario.

Saludos.

lunes, 26 de mayo de 2008

No digas "programita".

Pasa el Gerente de Desarrollo y dice "Acabo de salir de una demo y le vendí al cliente [alguna funcionalidad que no tenemos], pero es sencillo. Hay que hacer un programita que..." y a mí se me pone la piel de gallina.

"La otra vez estaba navegando por internet y vi el sitio de un flaco que estaba muy bueno, húngaro creo, había hecho un modulito que..." y me imagino que el pobre húngaro se atragantaba con la cena.

En la oficina ya es costumbre: "...ya sé cómo resolverlo. Lo que podríamos hacer es un sistemita que..." y unas dos o tres voces lo interrumpen al unísono: "No digas sistemita". El disertante se ríe un poco, se corrige "bueh, un sistema que...".

Y es que usualmente después de "-ita" viene algo por el estilo:

  • "... que dibuje sobre un plano del edificio, que podríamos importar de autocad, la información que tenemos sobre los componentes de la red en la base de datos."
  • "... que te marque en el mapa el mejor recorrido para ir a cobrar las facturas, como hacen ahora los gps."
  • "... que te muestre con semáforos, o mejor con un panel como el del auto, el estado financiero de la empresa."
  • "... que vos tengas acá al lado del reloj, y lo tocás y se despliega con las tareas que tenés asignadas y vas eligiendo qué es lo que estás haciendo. Tiene que actualizarse automáticamente, porque no lo vamos a ir instalando en los 2000 puestos de trabajo."
  • "... que te muestre esto mismo, pero en tres dimensiones y uno lo va rotando para ver mejor los datos (este viene acompañado por un '¡pero si los datos ya los tenés!')."

No quiero parecer quejoso, pero a los contadores no les dicen "¿Me firmaste el balancecito?", y nunca escuché a un abogado decir "Es cuestión de presentar una demandita."

Algunas profesiones gozan de la ternura del público en general, entre ellas las relacionadas con sistemas. También la música (supongo que muchos músicos profesionales habrán escuchado "¿por qué no te componés un temita para el cumpleaños de...?"), las artes plásticas, el diseño ("¿Qué es ese montón de dibujitos?" -el diagrama del sistema de logística sobre el que trabajamos hace meses-), la arquitectura ("¡Ay! Qué lindo, ¿no me lo regalás?" -el boceto de las Petronas-), sólo por dar algunos ejemplos fáciles.

De todas maneras, que "la gente" diga "programita", "temita", "dibujito" es generalmente simpático. Lo grave es cuando lo decimos nosotros. Por alguna razón creemos que algo es fácil. Lo fácil es demostrar que nada es fácil (con una pequeña "demostracioncita"):

Supongamos un proyecto de sistema bastante acotado (los que se reconozcan en las frases anteriores que vayan prestando atención a la terminología alternativa), con pocos usuarios y cuya funcionalidad sea similar a la de otros sistemas que ya hemos desarrollado. Tenemos que:

  • Relevar, así sea imprimir un mail con la propuesta.
  • Preparar la documentación de diseño, así sea una hoja con un párrafo diciendo cómo lo vamos a hacer.
  • Después codificarlo.
  • Probarlo y depurarlo.
  • Preparar la instalación.
  • Probar la instalación.
  • Generar la documentación o ayuda para el usuario.
  • Versionar absolutamente todo lo anterior.

Y como todo sistema, generará feedback, que debemos por lo menos rechazar cortésmente (es todo un trabajo), o prometerlo para futuras actualizaciones (que no tenemos en mente) condicionadas por factores improbables (pero que no se note, es todo un arte).

Una pavada, realmente. De acuerdo a mi humilde mi experiencia (experiencita) cuando uno escucha "-ita" en boca de alguien de sistemas (usualmente algún analista funcional o líder de proyecto, que me disculpen pero creo sinceramente que es así) es que sueña con saltearse no uno sino varios de los pasos mencionados anteriormente.

Con lo cual, cuando al sistema acotado se le suma otro sistema acotado y otro y otro, todos ellos sin la documentación o las pruebas necesarias, con un versionado al estilo "copiar en tal carpeta", tenemos un gran sistema de m... (y encima seguro que al cliente le encanta, con lo cual ahora es nuestro producto estrella).

O cuando la simple funcionalidad se quiere incluir en otro sistema (tarea por la cual presupuestamos... media hora, a lo más) y al hacerlo se rompe todo, tenemos un día de m...

No tiremos basura al patio del vecino (solamente). ¿Cuántas veces sub-presupuestamos horas, minimizando la complejidad de nuestra propia tarea, para la cual hemos estudiado tanto? ¿O cuántas veces dejamos "eso que es fácil" para el final, sin pensarlo demasiado, y nos pusimos a buscar imágenes para los botones? ¿O simplemente lo dejamos para mañana, o pasado?

Bueh, el tema da para reírse y llorar bastante más. A ver quién se juega con algún comentario sarcástico. Hasta lueguito.

P.D.: casi olvido dedicarlo a mis sufridos "compañeritos" de trabajo: ¿hace cuánto que no se nos escapa un "-ita"?

Fachada de negocios.

La correspondiente entrada en Wikipedia -Facade (patrón de diseño)- indica que

"El patrón de diseño facade o façade sirve para proveer de una interfaz unificada sencilla que haga de intermediaria entre un cliente y una interfaz o grupo de interfaces más complejas."

Para resumirlo un poco, la fachada de negocios es un concepto de diseño que nos hace pensar en varias "caras" (fachadas, justamente) para un sistema dependiendo del cliente que lo utiliza. Así, por ejemplo, un cajero y un gerente de banco tienen diferentes fachadas de acceso al mismo sistema.

A la inversa también funciona. Podemos tener varios sistemas independientes entre sí y presentarlos como uno sólo unificándolos en una misma fachada. Esto es común cuando se requiere la integración de sistemas tecnológicamente incompatibles.

Otro uso interesante -muy típico de Microsoft- es la renovación visual de un sistema sin cambios de fondo, que nos permite venderlo como si fuera un sistema nuevo.

Pero una imagen vale por mil palabras:

(Gracias a ud-ya-sabe-quién-es por el video)

Una clase sobre buenos modales.

De vez en cuando una clase llega exactamente a donde tenía que llegar en el momento preciso. La mayoría de las veces si uno quería dar clase sobre "A" termina dando sobre "a" que se le acerca bastante, pero no era lo que uno quería enfatizar.

Hoy llegué justo al centro de una de las cuestiones más importantes del desarrollo de software, y quiero aprovechar que tengo fresco el camino. Antes es obligado agradecer a los alumnos por las preguntas y comentarios precisos en el momento justo. Gracias.

Comenzamos desarrollando un ejercicio enunciado - diseño - codificación que venía de la semana pasada. Es un pequeño sistema de liquidación de sueldos. Diseñamos sistema con un gráfico (DFD nivel 1). Voy rumbeando hacia el diseño final, que era bastante elaborado, no por lo complejo sino justamente por su simpleza.

Así que luego de un largo rato tenemos el diseño completo y pasamos a la codificación.

Codificamos una parte de un procedimiento del sistema, casi un boceto. Cuando está más o menos terminado digo la típica y odiada frase "termínenlo para la semana que viene y vengan con las dudas y problemas que se les hayan presentado. Por ejemplo acá faltan datos, tienen que agregarlos de alguna manera. ¿Cómo harían para obtener los datos del empleado y mostrarlos en el recibo de sueldo?".

Momento de tensión. Surgieron dos posibilidades, creo que yo sugerí una (seguramente la que no me gustaba, viejo truco) y alguien tiró la otra. Lo importante es que ambas funcionaban y parecían simples. Impulso una votación.

Esto es lo importante: una de ellas implicaba un cambio en el diseño, mientras la otra lo seguía. Recordemos el momento: ya habíamos cerrado el diseño hacía bastante tiempo. Eligieron la que cambiaba el diseño. Suerte para mí, porque me dio pie para el sermón.

"¡¿Por qué eligieron esa?! Me rompieron el diseño, estaba tan bonito, tan cerrado, ¿no estábamos todos de acuerdo?".

Y ahí empezó el cierre final, que fue muy bueno. Voy a trasladar los conceptos centrales:

Obviamente en un ámbito académico todos estamos aprendiendo, así que en ese contexto es un error. En la vida profesional elegir esa opción no es un error, sino una falta grave que merece castigarse físicamente. ¿Por qué tanto?

Durante el desarrollo del software, en algún momento se establece un diseño. Su elaboración será más o menos participativa, más o menos consensuada entre los miembros del equipo, o será impuesto autoritariamente. Pero se establece. Y punto. Si no nos gusta, ése era el momento de dar pelea, y si la dimos y perdimos, perdimos. Luego taza taza cada uno a su casa y a codificar.

Cuando codificamos debemos seguir el diseño a rajatabla. En la práctica, eso indica básicamente que si el módulo que me ha tocado tiene determinadas entradas y salidas y ciertas formas establecidas de comunicación con "el exterior" tengo que respetarlos. Dentro de él soy amo y señor, pero ésos son mis límites.

La modularización, el encapsulamiento de la funcionalidad, es lo que permite distribuir tareas en un desarrollo, y aunque parezca raro, es lo que permite que cada uno codifique a su manera al establecer límites para la creatividad, evitando que lo que uno haga rompa el código del otro.

Así enunciado, parece una regla social al estilo de "mis derechos terminan donde empiezan los de los demás" y algunos programadores cometen el error de interpretarlo de esa manera, como una cuestión de "urbanidad" que puede estirarse un poco. No es así. No es una regla social, y no puede estirarse. Si no trabajamos de esta manera, no funciona. Simplemente, nuestro software se romperá en mil pedazos al intentar integrar partes que no encajan. Una computadora integrando partes de un sistema no "estirará" sus reglas para hacer que el sistema funcione, así que debemos ser tan estrictos como ella al respetarlas.

La regla básica que se aplica a un programador es la misma que se aplica a su código: debe hacer lo que tiene que hacer, o dar un error. Pero nunca, **nunca** hacer otra cosa, que será una respuesta inesperada. Tenemos que respetar el diseño o preguntar, avisar, invocar una reunión, hablar con el diseñador, lo que corresponda en cada caso. Pero nunca, **nunca** hacerlo de otra manera.

Si el programador avisa, se tomarán decisiones. Que pueden ser del tipo "rompamos con todas las reglas y hagamos que esto funcione, después vemos". Pero en alguna medida se evaluará el impacto sobre otras áreas del sistema, y se guardarán precauciones (o no), pero la instancia de comunicación es imprescindible. El programador debe saber cuándo lo que hace **puede** afectar al resto del sistema, aunque no sepa en qué manera lo hará o si lo hará realmente. Esto lo vuelve confiable.

Y llegamos al nudo central, que veo que se viene repitiendo en varios post relacionados con equipos de desarrollo. La comunicación y la confianza.

Viniendo de un programador con cierta experiencia, una mala decisión de este tipo es un error grave, y es más grave si de alguna manera denota que no es consciente de cómo sus acciones afectan al sistema que desarrolla junto con otros. Este tipo de "malas decisiones" generan desconfianza sobre el trabajo que se le puede asignar a un colaborador, porque nos indican que no podemos estar seguros de que lo haga en una forma que sea útil desde el punto de vista del sistema completo. De nada sirve que el código funcione bien si no puede integrarse al resto del sistema.

El momento de las integraciones es uno de los momentos finales en el desarrollo y es en general un momento de nerviosismo, de apuro, donde si no estamos sobre la fecha es que ya se nos ha pasado. Es un **muy** mal momento para enterarse de que una parte importante del producto genera errores al ubicarse con las demás, porque para el "integrador", que ve a los módulos como piezas que deben encajar unas con otras, este tipo de errores genera una infinidad de problemas que no puede resolver porque no conoce el contenido de cada módulo. Y si el error es grave puede que no haya forma de "encajarlo" en los tiempos requeridos.

Es en este momento donde alguno de los responsables del conflicto dirá una de las siguientes frases:

  • "Es que no se podía hacer de otra manera. El diseño estaba mal." El momento de disparar la alarma era cuando no se podía codificar la funcionalidad. Ahora vemos que no fue válido hacerlo de otra manera, y que se ha malgastado el tiempo que debía haberse dedicado a corregir el diseño. Tiempo perdido que genera más tiempo perdido, ya que necesariamente hay que hacer una adaptación para poder seguir integrando.
  • "Pero esta forma es mucho mejor". Puede ser. Pero ahora tenemos una porción del sistema que no encaja con las demás. Está mucho mejor que las demás, pero no encaja. Supongamos que tengo 10 módulos y uno está "mejor". ¿Hay que ajustar los otros nueve? ¿Cuándo? ¿Con qué tiempos y presupuesto?
  • "El módulo funciona, yo terminé mi tarea a tiempo y correctamente". Esta es una variación de la conocida frase multiuso "En mi máquina funciona". Justamente estamos en la situación en la que vemos que el módulo no funciona en **este** sistema, y el hecho de que funcione en **otro** sistema (parecido a este) no es relevante.
  • "Es que no entendí. Yo pensé que el diseño decía esto." Esta es la única respuesta válida, si es sincera. Y revela no una falta del programador, sino probablemente del equipo en su conjunto. ¿Por qué se mal interpretó? ¿Era confuso? ¿Cómo no nos dimos cuenta antes? ¿Faltaron puntos de control? ¿Faltó hablar más entre nosotros?

domingo, 25 de mayo de 2008

Off topic: Muto

Esto no tiene nada que ver con sistemas, pero bien vale una entrada:

Más info aquí. Es muy bueno.

Def: Sistema

Imperdonable no haber comenzado las definiciones con la más básica de todas.

Sistema: Conjunto de partes o elementos organizadas y relacionadas que interactúan entre sí para lograr un objetivo. Los sistemas reciben (entrada) datos, energía o materia del ambiente y proveen (salida) información, energía o materia.

Extracto de la entrada para sistema del diccionario de Alegsa. Les recomiendo darle una leída a la entrada completa.

sábado, 24 de mayo de 2008

El avance de los ordenadores.

Otra frase de esas que aparecen en un millon de páginas y ahora en un millón y una.

“Si la industria automovilística hubiera seguido el mismo desarrollo que los ordenadores, un Rolls-Royce costaría hoy 100 dólares, circularía un millón de millas con 3,7 litros y explotaría una vez al año, eliminando a todo el que estuviera dentro en ese momento”

— Robert X. Cringely

¡Hey! Eso de que no explote no estaba en los requerimientos.

viernes, 23 de mayo de 2008

Puertas que se abren

Todo lo que un sistema hace debería estar justificado por un requerimiento del cliente. Lo que falte será un incumplimiento, y lo que sobre horas de trabajo perdido. Por lo menos así reza la teoría.

En muchos casos el equipo de desarrollo no tiene contacto directo con el cliente final, sino con un analista funcional, o un líder de proyecto que conoce el negocio, o alguien que cumple una función por el estilo. En este caso el cliente, desde el punto de vista del equipo, será esa persona.

Siguiendo con la teoría, el cliente presenta un requerimiento, el equipo lo evalúa, lo presupuesta en horas y el cliente decide. La negociación económica -cuando corresponde- debe enfocarse en el precio de la hora, no en la cantidad. Pensémoslo de esta manera: si quiero pintar mi casa, necesito tantos litros de pintura y puedo buscar el mejor precio, pero no comprar menos, y no tiene sentido discutir este punto. Pero el software no es pintar una casa, y hay sutilezas. Hay muchas, muchísimas variables internas del proveedor de software que hacen que uno tarde significativamente más o menos que otro en hacer prácticamente lo mismo. De todas maneras, el punto importante aquí es que es el equipo el que determina cuántas horas requiere para el proyecto. Sé de equipos en los que la parte funcional no entiende esto y es motivo de discusión. Porque -si han evaluado honestamente- no hay forma de que el requerimiento se cumpla en menos tiempo, así tengan una pistola en la cabeza. Tengo que reconocer que por suerte no he sufrido esto en carne propia.

Concentrémonos en el tema de las variables internas, pensando en un sistema informático que soporta un sistema administrativo (sistemas de venta, de facturación, de marketing, etc.). Más específicamente, en la interfaz con el usuario (IU). En este tipo de sistemas, la IU es por lejos el subsistema más complicado. ¿Por qué? Porque hace de interfaz entre dos lógicas completamente diferentes. Una cuestión es una interfaz entre dos sistemas, en donde las cosas están bien definidas en un momento dado, de mejor o peor manera. Con las personas -los usuarios- es imposible. Lo que una persona ve con claridad, a otra le parece incomprensible. Uno quiere trabajar así, otro quiere trabajar asá, y el área funcional quiere satisfacerlos a todos -con razón, ya que ellos son los que pagan-. Tratamos de promediar, de establecer métodos, estándares, pero el problema con los promedios es que no representan a nadie, y cada cliente viene con sus pequeñas variaciones. Si tenemos un sistema que vendemos a varios clientes, esas "pequeñas variaciones" acumuladas generan el clásico infierno de las pantallas de "opciones" o "configuración general" con miles de variantes, que son típicas en este tipo de software.

Así que es en la IU donde como desarrolladores tenemos que esforzarnos en buscar los puntos realmente importantes para concentrarnos en ellos. Es decir, aquel subconjunto de pantallas más utilizadas y poner todos los "chiches" ahí, y dejar el resto del sistema en la forma más simple posible que sea funcional al usuario.

Hay que tener en cuenta que, por suerte, es en la IU donde el proveedor tiene más poder de decisión. En general el cliente tomará la primera propuesta y pedirá modificaciones siguiendo la línea que se le presenta. Es raro que un usuario venga con un boceto de una pantalla, más bien tiene una idea de la funcionalidad que quiere agrupar en cada una, pero no más que eso. El resto lo tomará de lo que nosotros le presentemos.

La típica frase gira alrededor de "¿no se podría poner en la pantalla de facturación un ayudante como el que está en la de presupuesto?". Así que más vale que el "ayudante" que pusimos en la pantalla de presupuesto no haya sido el producto de un rato de ocio o el exceso de creatividad de algún programador, porque ahora se ha convertido en un estándar para el usuario, que probablemente termine queriéndolo en todos lados.

Y ahora viene el párrafo donde aparece el título: "No abras esa puerta" (la frase no es mía, si el autor quiere crédito no tiene más que mandarme un mail, él sabe quién es). Es decir, ojo con ofrecer espontáneamente funcionalidad en la UI que luego nos cueste mantener o replicar, o que genere demasiada complejidad, o que incluso se aparte demasiado del estilo del resto del sistema.

Un ejemplo. Empecé a jugar con la técnica que mucho después terminaría siendo "Ajax" en una pantalla bastante simple de ingreso de CV a una base de datos. Lo típico en ese momento era una tablita al estilo:

TítuloEstablecimientoAño de ingreso Año de egreso

(bueno, con más estilo, pero la idea se entiende)

Así que hice una grilla que editaba por "Ajax" (no tenía ninguna utilidad que lo hiciera, era puro javascript a mano) un objeto guardado en sesión, del lado del servidor. Transformé la tabla en un ABM clásico, con ventanas pop-up que editaban los datos de cada fila. Claro, estaba jugando, experimentando. No había encapsulado nada, y no era nada prolijo por adentro. Incluso habían graves cuestiones no resueltas (recuerdo por ejemplo que las llamadas al servidor eran asincrónicas, sólo porque no sabía que se podía hacer sincrónico).

Había varias listas parecidas en la pantalla: "Idiomas", "Experiencia"... y claro, no se podía hacer unas de una manera y otras de otra. Copié y pegué hasta reproducirlo en todas las listas. ¿En qué terminó todo esto? En una pantalla lenta, pesada y tosca, con problemas de redibujado en el Internet Explorer, que ni siquiera se mostraba decentemente en otros navegadores y que cumplía la misma funcionalidad que la anterior, pero que obligaba al usuario a utilizar intensivamente el mouse... un asco. Y yo tratando de explicar que no, que había sido un experimento, que ahora ya está en esa pantalla pero que no tiene por qué extenderse a todas las demás, que eso del redibujado era grave, que no tengo tiempo para hacer todo prolijo de vuelta, que emprolijarlo a partir de lo que está es casi imposible, etc., etc... es decir, terminé tratando desesperadamente de cerrar esa maldita puerta.

Años después, trabajando en base a un framework en javascript estilo Ajax, con ventanas, llamadas sincrónicas al servidor, y un montón de temas ya resueltos y con el Internet Explorer 7, la cuestión se volvió moneda corriente. Por supuesto gran parte del framework fue desarrollado y mejorado prolijamente a lo largo de **mucho tiempo** por el que ahora es algo así como el "Team Leader" en donde trabajo (repito lo de los créditos).

Resumen. Las puertas pueden y deben abrirse... a su debido tiempo, o nunca.

jueves, 22 de mayo de 2008

Etapas de un proyecto.

No conocía la fuente, parece que era de Murphy, nomás:

  1. Ilusión.
  2. Desilusión.
  3. Pánico.
  4. Búsqueda del culpable.
  5. Castigo a los inocentes.
  6. Alabanzas a los no participantes.

(Traducido del libro: La ley de Murphy).

Comprendiendo gráficamente la tecnología informática

¡Hasta que lo encontré! Estaba perdido, pero me acordé de la frase que le da título a la imagen, y el oráculo google me dió lo que estaba buscando.

Pero por favor sigan leyendo.

miércoles, 21 de mayo de 2008

El costo del cambio (parte I)

Hace un par de entradas recomendé el libro de Kent Beck, "Extreme Programming Explained". Tuve que releer los primeros capítulos en vistas de una clase que tenía que dar sobre "Modelos de desarrollo", en el marco de la Materia "Construcción de Aplicaciones Informáticas" de la Facultad de Ciencias Económicas (UBA).

Lo de arriba no es sólo autobombo (que hay algo de eso, por qué no), sino que quiero subrayar que, dado que el marco es el de las ciencias económicas, me centré exclusivamente en esos aspectos de las bases de la metodología que plantea Kent Beck.

Tuve al releerlo la misma impresión que cuando lo hice por primera vez. Comencé un poco distraído, pero el libro fue atrayendo toda mi atención hasta llegar al capítulo 5, "Cost of Change", después del cual tuve que dejar de leer. Para cualquiera (no demasiado joven) dentro del ambiente de desarrollo de sistemas, ese capítulo se siente como un mazazo que rompe con todo lo aprendido hasta el momento. Voy a comentarlo.

Empieza con un grafiquito muy simple y simpático que todos los que transitaron por alguna facultad recordarán:

Es decir, lo que todos sabemos: el costo de un cambio (actualización, corrección, mejora, lo que sea) crece desde el diseño hasta la puesta en marcha y desde allí se dispara dramáticamente.

Claro, si estoy en diseño y veo la nececidad de cambiar la relación entre dos tablas de la base de datos, el costo de corregirlo será el de un par de minutos con el programa de diseño que esté utilzando para crear el modelo. Si tengo la misma necesidad, pero la base de datos está en producción, llena de registros vitales para el cliente, talvez geográficamente muy lejana, los costos en tiempo y dinero son incomparables.

Por eso la obsesión por la perfección en las primeras etapas del desarrollo, muy marcada en las metodologías tradicionales: los requerimientos deben ser completos, el modelo debe ser perfecto, los programadores deben seguirlo al pie de la letra, tratando de arruinarlo lo menos posible. Como en general no son (somos) gente muy capaz, cometerán (cometeremos) un sinnúmero de errores que nos (les) costarán (¡a uds.!) muchísimo dinero. Así que hay que gastar mucho (pero menos que muchísmo) en testers, control de calidad posterior al desarrollo, y también en estrictos métodos formales de control de la "producción" (la codificación)... me pregunto por qué nunca se puso de moda "debemos gastar mucho dinero en prestaciones para atraer a los mejores prospectos, formación para tener a los mejores programadores y en sueldos altísimos para que se queden con nosotros" si el principio es el mismo (aunque hay que reconocer que estamos mucho mejor que antes).

Se nos ha enseñado que el software se degrada naturalmente con el mantenimiento y las modificaciones, que nuestro esfuerzo de buenas prácticas, claridad, simplicidad y código mantenible es una utopía a la que debemos tender para maximizar el rendimento pero irrealizable por definción, y que el software, como cualquier otro producto, se gasta con el uso y muere.

Pero ese dibujito es largo más viejo que yo. Está basado, me imagino (aunque no lo sé realmente), en los sistemas de producción fabril de donde se derivaron las primeras metodologías para el desarrollo de software. En un principio el desarrollo de software se encuadró en el modelo de desarrollo de cualquier producto, por ser el único que existía: la planificación de la producción, alegoría para la modelización de un sistema, es más valorado (personal de cuello blanco) que la construcción física del producto (obreros de cuello azul), la fábrica, la cadena de montaje, Tiempos modernos y todo eso, alegoría de la codificación del sistema.

Kent Beck plantea (y yo estoy de acuerdo, con matices) que si alguna vez eso fue cierto ya no lo es. Para ponerlo en sus propias palabras:

The software development community has spent enormous resources in recent decades trying to reduce the cost of change—better languages, better database technology, better programming practices, better environments and tools, new notations. What would we do if all that investment paid off? What if all that work [...] actually got somewhere?

Tenemos computadoras con las que podemos compilar enormes sistemas cuantas veces querramos sin costo, programación orientada a objetos, administradores de bases de datos, entornos que nos ayudan a modificar dramáticamente la estructura del sistema con relativa facilidad. Tenemos redes de altísima velocidad, administración remota de equipos, podemos trabajar prácticamente en cualquier lugar del planeta sin movernos de casa.

De hecho esas técnicas ya ni siquiera pueden calificarse de novedosas. Son las que han difundido la computadora fuera de los ámbitos específicos de la profesión y la han convertido en una herramienta de uso común para cualquiera, al permitir una complejización del software inimaginada hace un par de décadas.

¿Y si de repente nos diésemos cuenta de que aquellas teorías sobre las que descansa nuestra forma de pensar el desarrollo de software en realidad son producto de una mirada obsoleta sobre la tecnología y nuestras propias capacidades? ¿Y si este gráfico estuviese al alcance de nuestras manos?

Termino con algunas preguntas: si pudiesemos cambiar el rumbo del desarrollo de un sistema a medida que avanza sin costos exorbitantes, ¿cómo desarrollaríamos? ¿qué factores tendríamos en cuenta en nuestras decisiones? ¿cómo diseñaríamos?

Hasta la segunda parte.

Actualización: segunda parte.

martes, 20 de mayo de 2008

Def: Procrastinación

Más que en cualquier otro ámbito en el nuestro es necesario conocer las palabras que transmiten sin ambigüedades los complejos conceptos que conforman nuestro saber. Inauguro entonces una sección (etiqueta, bah) para ayudarnos con aquellos más comunes, difíciles de aprehender o mal utilizados.

"Procrastinación es la acción de procrastinar (del latín procrastinare) es decir, de postergar actividades o situaciones que uno debe atender, por otras situaciones más irrelevantes y agradables. Este término proviene del latín pro- (adelante) y crastinus (relacionado con el mañana)."

Colaboradores de Wikipedia. Procrastinación [en línea]. Wikipedia, La enciclopedia libre, 2008 [fecha de consulta: 4 de mayo del 2008]. Disponible aquí.

lunes, 19 de mayo de 2008

Proyecto de software típico.

Me acordé de esta secuencia, y estuve un buen rato buscándola por internet. No hay mucho mas que decir.

La autopista del desarrollo

De la misma manera en que necesitamos imágenes o alegorías para comprender los sistemas o alguna de sus partes necesitamos una buena imagen de cómo es el proceso de desarrollo. Un concepto más fácil de atrapar y de entender que un paper de buenas prácticas o un libro acerca de alguna nueva metodología. Me tomo muy en serio las frases graciosas al estilo

"Codifica siempre como si la persona que finalmente mantendrá tu código fuera un psicópata violento que sabe dónde vives." (Martin Golding)
porque son más fuertes que un aburrido sermón de media hora sobra por qué tenemos que ser prolijos y claros y etc. etc. etc..

Para el desarrollo de software, la clásica es "la fábrica". El equipo de desarrollo es una "fabrica de software". Entonces entran los requerimientos, vienen los analistas que hacen algo con ellos, se lo pasan a los programadores que hacen otra cosa, que se la pasan a los testers que la prueban y a los de soporte o como-se-llamen que la instalan y el cliente que la usa. Una línea de montaje. Si bien no está tan mal, no me gusta del todo.

Me gusta la idea del desarrollo de software como un viaje en auto. Lo leí por primera vez en "Extreme Programming Explained" de Kent Beck (que recomiendo sobremanera), y siempre me ha quedado dando vueltas en la cabeza. El libro está lleno de imágenes poderosas y es por eso que los conceptos centrales son inolvidables, más allá de que uno esté de acuerdo o no con ellos.

La idea es: todo el equipo de desarrollo está viajando junto con el cliente desde los requerimientos hasta la implementación. Algunos en su propio auto, otros van de a dos o tres, unos van más rápido y otros más lento, pero tenemos que llegar todos.

Primero está el deseo de ir a algún lado. Requerimientos.

Después pensamos "¿podemos ir?". Yo quiero ir a Madrid el mes que viene, me gusta mucho Madrid. Pero desgraciadamente no lo veo muy posible, por lo menos para el mes que viene. Tenemos entonces el estudio de factibilidad.

Después pensamos qué necesito para llegar. No alcanza con decir "salimos mañana". Necesito un auto, dinero, combustible, tal vez un mapa, tengo que hacer la valija, cosas comunes para cualquier viaje. Quiero saber cuándo salimos y cuándo llegamos, y también cuánto me va a costar la gracia. Así que planeamos.

Entonces nos ponemos a pensar en la ruta. Un poco de eso lo hicimos en la etapa anterior, pero ahora agarramos el mapa y nos ponemos a ver en detalle por dónde vamos a ir, si nos conviene tal o cual camino, cómo nos distribuimos en los autos, etc. Diseñamos.

Y llega el día de la partida. Alguno se queda dormido, y llega justo para salir. Otro tuvo un contratiempo y nos alcanza a mitad de camino. Otro decidió que no, que mejor me quedo en casa. Los demás estamos ahí con las valijas en la mano, y los motores en marcha. Miro la valija de mi muy presentable compañera de viaje (¿ven que la planeamiento y el diseño son importantes?). Está muy preparada y me empiezo a dar cuenta de todo lo que me falta. Mejor no pensar en eso. De alguna manera voy a llegar... a algún lado.

Y empieza el viaje y empiezan los problemas. Porque hay un atasco por allá, así que hay que decidirse, ¿nos abrimos o aguantamos? ¿y si cortamos por ese descampado, no iremos más rápido? Que no que mejor vamos por acá, sigamos la ruta, que es lo más seguro.

Que pinchamos, suerte que tenemos rueda de repuesto... te dije que necesitábamos una rueda de repuesto, me dijiste que la conseguías, ¿cómo que había que abaratar? ¿cómo que para mañana? Al final gastamos más y tenemos que esperar.

Que tengo hambre, calor, frío, sueño. Yo así no sigo. No importa, conductores hay por todos lados. Sí, pero ninguno va a querer viajar así. Que vas a ver que alguno que recién aprende se muere de ganas de manejar. Bueno...

Obviamente las cosas no son como las planeamos y diseñamos. Pero no lo hicimos mal, simplemente las cosas nunca son como las planeamos. Por suerte planeamos pensando en eso, ¿no? Ah, ¿no? Ups...

Y el viaje sigue. Algunos manejan mejor y otros peor. Pensemos un poco en eso. Hay distintos tipos de conductores. Están los que respetan a rajatabla todas las normas y carteles. Son capaces de desbarrancarse por hacerle caso a un cartel que estaba dado vuelta. Están los temerarios que zigzaguean entre los vehículos a toda velocidad. Expertos conductores, siempre les sale bien. Está el que habla por celular, escucha música a todo lo que da, mira el paisaje y cada tanto le presta un ojo a la ruta. Está el que va atento a todo, esperando lo inesperado.

Que cada uno valore positiva o negativamente a cada tipo de conductor según su propio criterio. Yo sigo presentando mi opinión, abierto al debate:

Al manejar hay que confiar en ciertas reglas básicas. Cada uno debería seguirlas y confiar en que los demás las siguen también. No puedo frenar siempre por las dudas, aunque el semáforo está en verde. Tengo que creer que el que lo tiene en rojo va a frenar. Sin embargo hay que estar atento en los cruces. Hago señales, que todo el mundo sepa qué es lo que voy a hacer. Sin embargo, alguien más puede estar distraído, así que me aseguro de que me hayan visto. Y así con todo.

En un equipo de desarrollo, el que no sigue las reglas se vuelve peligroso, para él y para los demás. Todos cometemos errores, e incluso todos violamos alguna norma de vez en cuando, a sabiendas. Pero es una cuestión de grados. No es lo mismo el que deja código medio enrevesado dentro de un módulo, sabiendo que no está muy bien, pero que por lo menos está encerrado ahí, que el que para resolver un problema te pone 20 variables globales y hace un nudo que madre de dios. Y no es lo mismo hacerlo y avisar que hacerlo y ocultarlo. Hay cuestiones en un integrante de un equipo de trabajo que lo vuelven extremadamente peligroso, por ejemplo:

  • No respetar los acuerdos sin avisar. Vamos a hacer esto de esta manera, ¿ok? Éste es el momento de estar en desacuerdo, o de plantear problemas. Luego, hay que hacerlo así, o avisar que no podemos, pero no hacerlo de otra manera, o no hacerlo en lo absoluto.
  • No utilizar el mismo lenguaje que el resto. Claro, si uno quiere decir "A" pero dijo "a" es parecido, pero no es lo mismo, y los malentendidos son terribles. No hay que tener vergüenza de usar el dedo. Cuando no sabemos el nombre de algo, lo apuntamos con el dedo y decimos "esto", pero no lo cambiamos por otro nombre.
  • El individualismo llevado al extremo. Yo hago las cosas a mi manera ¿ok? Y lo que a mí me importa es que mi trabajo esté a tiempo y forma, me pongo las anteojeras (como la de los caballos, ésas para no ver a los costados) y le doy para adelante. No está tan mal, salvo que se combine con el primer punto ("digo a todo que sí y después hago lo que quiero"). Hay que defender lo que uno cree, estamos de acuerdo, pero si los demás no lo ven a nuestro modo, hay que adaptarse, con quejas, malhumor, lo que sea, pero adaptarse. Y si no nos podemos adaptar, hay que irse. Seguramente hay otras personas que harán las cosas a mi manera o que se adapten a mí, es cuestión de encontrarlas. Pero si me quedo me vuelvo peligroso.
  • Encubrir los problemas, por cualquier motivo.

No se me ocurren más por ahora. Acepto sugerencias. Pero notemos que son cuestiones que no hacen a la idoneidad. Hasta el más principiante desarrollador puede evitar esas actitudes. Son temas que giran alrededor de lo más importante en un equipo de desarrollo: la comunicación. Digo lo que voy a hacer, hago lo que dije que iba a hacer. Las reglas básicas del desarrollo de software tienen que ver con facilitar la buena comunicación entre los miembros del equipo, o por lo menos con no bloquearla.

Cuando la comunicación es buena, surge algo que es maravilloso en un equipo: la confianza. No confianza en que "todo va a salir bien" ni en que "fulano podrá resolverlo". Confianza en saber qué es lo que está pasando, y en saber, o enterarme a tiempo, cómo es que van a reaccionar los demás. Confianza en que no me va a caer un piano en la cabeza (a menos que pase por donde dice "no pasar"). Si X es un apurado que quiere resolver todo de cualquier manera, pero lo dice, y sobre todo acepta cuando se le dice que no lo haga, está ok. Muchas veces es necesario resolver las cosas de cualquier manera. Si a Y no le interesa demasiado el proyecto, y sólo quiere que suene la hora para irse, pero lo dice, perfecto. Sé qué es lo que puedo esperar de él. Y tiene algo invalorable, la sinceridad. Si Z no puede con este problema, pero avisa a tiempo, vemos qué es lo que hacemos.

Tenemos que convivir con los temerarios y con los que van a contramano. Y encima tenemos que vivir con nuestros propios errores, miserias, días malos y demás. Como en un viaje, desgraciadamente no alcanza con manejar bien y estar atento, porque siempre puede venir un loco a 200 por hora, y eso es inevitable. Pero podemos prever y controlar los daños. Siempre hay uno que puede introducir un virus mirando pornografía en el trabajo. Pero si tenemos antivirus sería más raro que eso suceda. Hasta el administrador más avezado puede borrar una carpeta sin querer. Pero si él es el único que tiene permisos para hacerlo, y aparte hay backups periódicos, sería raro perder mucha información. Puede haber alguno al que lo único que le importa es decir que él llegó a tiempo, o que los retrasos no son su culpa, y ocultar el hecho de que para llegar antes entorpeció a todos los demás. Pero si el proyecto está bien armado cada uno trabaja sin poder molestar demasiado al resto (por más que quiera). Y así con todo.

La conclusión es que la imagen de manejar y el viaje es muy buena, y nos brinda directivas de conducta para cuando no sabemos qué hacer. Yo la uso, veo las cosas de esa manera, y funciona. Prueben.

domingo, 18 de mayo de 2008

Frases

Fuera del perro, un libro es probablemente el mejor amigo del hombre, y dentro del perro probablemente está demasiado oscuro para leer.

-Groucho Marx

Otras frases de Groucho y muchas más buscando en Google.

Sobre los errores

"La mayoría de expertos está de acuerdo en que la causa más probable de destrucción del mundo sería por accidente; y aquí es donde entramos nosotros: somos profesionales de la informática, causamos accidentes" -- Nathaniel Borenstein

Ok. Desarrollamos software y cometemos errores. Muchos errores. Creo que el inventó "pato criollo" (cada paso una cag...) estaba pensando en nosotros. Y es verdad.

Desarrollo software profesionalmente desde hace... 10 años. Desarrollo software (por diversión o porque sí) desde hace 16 (saquen sus cuentas). Todavía no puedo decir que le haya puesto el moño a nada. Es decir nada de lo que hice anda 100% bien.

El software es "buggy". Todo software no trivial tiene errores, y algunos triviales también. Cuando digo todo es todo. Por ejemplo... los sistemas de control de las plantas nucleares, los que administran el tráfico aéreo, el de trenes... los que controlan piezas de hardware como ascensores, máquinas utilizadas en medicina, armas nucleares... sí, tienen errores. Yo duermo como un bebé cuando viajo en avión, incluso cuando me subo al ascensor de un rascacielos (a veces termino apoyado en el hombro de un desconocido).

Es obvio que el software sirve y funciona a pesar de los errores. Los sistemas críticos que mencioné arriba funcionan porque su funcionalidad principal ha sido probada y corregida, y también porque son constantemente supervisados. A nadie se le ocurriría dejar que un programa controle un avión sin supervisión. Tenemos pilotos automáticos, pero al lado hay un piloto de carne y hueso. Y si el día de mañana la tecnología permite que ese humano no esté físicamente en la cabina, estoy seguro que su función será cumplida por otro en otro lado.

Cuando el software no es crítico (de vida o muerte, quiero decir) la cosa se pone más complicada. Sobre todo si nos arriesgamos un par de veces y nos sale bien. Nos volvemos temerarios. Algunos ejemplos de los más graves en los que he participado de primera mano:

  • Corregir un bug directamente en una página web en producción (con el cliente al teléfono), y después hacerlo en desarrollo.
  • Implementar una funcionalidad "a prueba y error". Es decir, introduciendo casos que la rompen y corrigiéndolos.
  • Modificar funcionalmente un sistema a partir de requerimientos verbales, sin anotar nada en ningún lado.
  • Hacer que un sistema haga algo para lo que no fue pensado, tocando por afuera sus datos de entrada.
  • No hacer backups.
  • No llevar versiones.
  • Dejar algo a medio hacer pero que aparentemente funciona e irme (síndrome de "mañana sigo").
  • Implementar código específico para clientes o usuarios en particular.

Por suerte, si bien pocas veces tuve "accidentes" catastróficos, fui merecidamente castigado por el destino, tarde o temprano. Todo vuelve.

Si no probé ese caso delirante porque era muy difícil de reproducir y al fin y al cabo bastante simple, se rompió un sábado.

Si no versioné me tuve que quedar después de hora porque para corregir una tontería hubo que actualizar todo a la última versión.

Si metí un "if usuario=4" después me pasé horas tratando de entender por qué cuando el tipo creó un usuario nuevo porque se le olvidó la password (y no se le ocurrió restablecerla) se rompió todo.

Y así con todo... tarde o temprano.

¿Por qué no aprendemos? Porque somos humanos, nos olvidamos de lo que salió mal y nos acordamos de lo que salió bien. Porque en algún punto, por más que no me guste, la teoría conductista se aplica también a nosotros. Si el estímulo negativo (quedarse hasta tarde) está separado temporalmente de la causa (hace dos meses dejé algo a medio hacer y me fui a comer) el acto reflejo (si me voy a comer dejo una marca o algo para que no compile) tarda en establecerse... como los perritos, yo no tengo pero un amigo me dijo que cuando reta a la perra lo hace en el lugar en el que hizo la macana.

En realidad sí aprendemos. Terminamos aprendiendo, a lo largo de varios años. Pero trabajamos en equipos con gente que está aprendiendo y que todavía no se quemó lo suficiente. O con gente con mucha suerte (que la hay) o con gente extremadamente hábil para sortear algunos problemas (por ejemplo con una memoria extraordinaria) y que no tiene en cuenta al resto.

O... con situaciones "sistémicas" que hacen que convenga hacer las cosas mal. ¿Cómo? Sí, a veces conviene hacer las cosas mal. Y ahí tenemos (o no) un problema. Voy a inventar algo. Lo juro, esto es puro invento.

Trabajo en una consultora, mis requerimientos son de mínimo alcance, cada uno tardará en implementarse a lo más dos semanas. Soy un junior, me interesa más aprender a usar la nueva herramienta que hacer el software. No conozco el "negocio" y no me interesa, creo que es algo que tiene que ver con facturación. Solamente tengo que sacar un reporte, sumar esta columna, dividir por ésta otra. Así que... lo pienso un ratito, prueba y error, veo los ayudantes, las opciones, voy toqueteando... hasta que cumplo con el ejemplo que me pasaron. Listo. Cierro. Grabo. Sale.

Obviamente no pasa las pruebas. Se levanta un incidente que ¿vuelve a nuestro amigo junior? no, no vuelve, le cae a cualquier otro. Más o menos misma situación. Otro programador resuelve exclusivamente el caso reportado en el incidente. Listo. Cierra. Sale.

Y así hasta que luego de un par de meses la cosa sale, funcionando más o menos bien, se producen un par de errores en producción, se solucionan, listo.

El reporte es, por adentro, un asco. Inentendible, intocable. Cada tanto se corrige un error, aparece otro, y otro y otro... ¿Qué está mal? A mi entender, nada. Repasemos. El junior de la historia aprendió a usar la herramienta, se fue de la consultora a trabajar independiente. Bien por él. En la consultora le hacen una fiesta de despedida. Entra otro junior que cobra un poco menos o un poco más. El cliente utiliza el reporte, sabe que de vez en cuando tiene un problema, pero está contento porque en la consultora lo atienden y se lo corrigen. Paga las horas de mantenimiento. La consultora cobra las horas de mantenimiento y destina una milésima de eso al pago de sueldos. Todos tenemos trabajo, todos cobramos, todos contentos.

Volvamos al ex-junior, ahora semi-senior. Tiene sus primeros clientes, trabajos chicos, pero gana más que en la consultora. Tiene más clientes. Se junta con un amigo, y ya somos dos. Hacen su primer sistema completo. Entregan a tiempo y en forma, algunos meses de mantenimiento intensivo, luego baja la carga de trabajo, siguen con otra cosa.

En algún momento el cliente quiere algo más. Parece fácil, presupuestan y el cliente compra. Manos a la obra... y... pum. Toca acá, se rompe allá, ¿de dónde saco este dato...? ¿cómo era esto...? ¿por qué si esta variable está bien no se muestra en...? Che, apurá que tenemos que ir a ver a fulano o mengano... Perá todavía ni empecé con esto... ¿Pero no era fácil?

El final es abierto. Puede que lo "saquen arando", y bien. Puede que todo vaya mal, puede que el cliente termine contento o puede que termine pensando que es algo demasiado grande y complicado para dos programadores independientes. Lo que es seguro es que en algún momento el semi-senior se convierte en senior. ¿Cuándo? Entre otras cosas, cuando se da cuenta de que tiene que diseñar, reutilizar, organizar, encapsular, hacer arquitectura, llevar versiones, backups, documentos. Si le va bien se convierte en un experto. ¿Cuándo? Entre otras cosas, cuando logra ubicarse en cada situación, y hacer las cosas como más convenga, teniendo en cuenta el presente y el futuro. Cuando pueda sacar las cosas arando cuando corresponde y también ser estricto y prolijo con las normas, cuando corresponde. Y será más experto en la medida en que mejor se ubique, porque cada situación será parecida a otras, pero única en si misma, y el éxito nunca estará asegurado.

Puedo dar fe de que es así hasta el punto de que el junior se convierte en senior... luego diría que es algo que he visto pero no experimentado. Ser "experto" en el sentido que le doy a la palabra en este artículo... sólo puedo decir que hacen falta **más** de 10 años de experiencia profesional.

sábado, 17 de mayo de 2008

Libros recomendados: Kent Beck. Extreme Programming Explained.

Extreme Programming Explained: Embrace Change. Addison-Wesley, 2000. ISBN 0-201-61641-6. Second edition 2005 with Cynthia Andres. ISBN 0-321-27865-8.

La biblia acerca de las metodologías "ágiles" de programación, tanto para desarrolladores como para líderes de proyecto, analistas, o cualquier interesado. Sus postulados rompen los axiomas más establecidos de las metodologías de desarrollo tradicionales. Estemos de acuerdo o no con sus postulados, es imprescindible conocerlos. El libro está excelentemente estructurado, es corto y muy ameno.

El desarrollo de software como sistema, y nosotros adentro.

Un emprendimiento de desarrollo de sistemas puede encuadrarse en infinidad de teorías, modelos, directivas, recetas. La teoría de sistemas ofrece la gran ventaja de ser conocida por la mayoría de los involucrados (o por lo menos debería serlo). Al fin y al cabo, en un emprendimiento de desarrollo de sistemas estamos desarrollando exactamente eso. El emprendimiento es un sistema (administrativo) que desarrolla sistemas (de computadora).

Ok. Este sistema es una secuencia E-P-S-R: Entrada-Proceso-Salida-Retroalimentación. ¿Les suena? En informática describimos casi todo de esta manera: algoritmos, software, hardware, negocios. ¿Por qué no describir así el proceso de desarrollo? ¿No es acaso un "negocio" como cualquier otro?

Utilizamos entonces la misma secuencia de que utilizaríamos para analizar cualquier requerimiento: establecer la salida (qué es lo que el sistema debe hacer), la entrada (qué necesita para hacerlo), y luego abrir esa caja negra llamada proceso (cómo lo hace).

En nuestro caso la salida (del sistema de desarrollo de software) es un sistema compuesto por piezas de software, hardware y documentos orientados a una tarea específica. En la entrada del sistema tenemos los requerimientos del usuario, palabra santa. Y en el proceso tenemos todos los subsistemas necesarios para transformar una lista de requerimientos en software, hardware y documentación: analistas, programadores, líderes de equipo, líderes de proyecto, testers, expertos en base de datos, expertos en infraestructura... Pero también, y esto es algo que en general no se tiene muy en cuenta: personal de ventas, de atención al cliente, de facturación, de recursos humanos. Tenemos computadoras, redes, software de desarrollo de todo tipo (para el análisis, entornos de programación, compiladores, versionado), software de administración de base de datos... Pero también tenemos software de administración de todo tipo (ventas, facturación, atención al cliente, pago de sueldos), un lugar físico, escritorios, cafeteras (espero), plantas (donde yo trabajo no), baños (sí, eso sí tenemos, pero...), personal de limpieza... la lista es interminable, pero la idea final ya tiene que haberse entendido: tenemos una empresa, grande o chica, miles de empleados o dos amigos programadores con un cliente ocasional, con todo lo que ello representa.

Para la descripción del proceso de desarrollo se han escrito selvas enteras de papeles, y llenado varios gigas de información. Las teorías y procesos tradicionales pueden resumirse en una secuencia de: análisis, diseño, construcción y pruebas (todo en uno), implementación. Con sus variantes, por supuesto. Luego tenemos una infinidad de variantes iterativas: en esperial, escalonadas en tirabuzón o calesita, todas ellas repiten de alguna manera la secuencia arrojando porciones del producto final en cada iteración.

Pero falta algo... dijimos entrada, proceso, salida... retroalimentación. ¿Dónde está la realimentación en un sistema de desarrollo de sistemas? Empezemos por el principio: ¿Qué es la retroalimentación en este contexto? Voy a tratar de atrapar la idea: una vez que un proceso de desarrollo alcanza cierta madurez, puedo examinar el resultado con el ánimo de mejorar el proceso. Retroalimentación implica que la salida de un sistema lo modifica. En todo desarrollo se examina el resultado (el software, por ejemplo, o los documentos) y se habla de control de calidad, excelencia, 0 defectos... pero no es esto de lo que hablamos aquí. Podemos tener un producto excelente en tiempo y forma y clientes satisfechos, pero al mirar hacia atrás nos damos cuenta de que hemos atravesado un infierno para llegar a ello: requerimientos contradictorios, problemas con los equipos, tiempos muertos, personal inexperto... ¿Qué importa, si al fin y al cabo el producto es bueno y el cliente está contento? Dirección por resultados, que le dicen.

Ok. Los resultados son indispensables. Sin resultados no hay desarrollo... pensemos un poco en esto. Si no hay desarrollo sin resultados entonces no hay empresa de desarrollo sin resultados... entonces... Todas las empresas y emprendimientos existentes brindan resultados. Algunas brindan mejores con mayor frecuencia. Pero si no lo hicieran no sobrevivirían. Es la lógica darwiniana de cualquier mercado. Así que tenemos que mejorar el proceso para competir.

Pero lo más importante: nosotros como personas somos parte del proceso, estamos dentro de él. Digo, nuestro trabajo (analista, programador, administrador de base de datos, el que sea) ocupa buena parte de nuestro tiempo, y no es sostenible sólo por los resultados. Puedo ganar buen dinero y estar contento con las felicitaciones de mi cliente... mientras me repongo de mi pico de estrés, de mi ataque cardíaco, o simplemente mientras duermo las 72 horas que tengo atrasadas o trato de recordar el nombre de alguien de mi familia, etc.

Muchas veces, cuando al final "todo" sale bien tendemos a creer que hicimos bien las cosas, y puede estar pasando una de dos: los problemas están por venir (muy probable) o en algún momento alguien lo hará mejor. Pero incluso si eso no se da y todo sigue bien... podríamos hacerlo con menos esfuerzo que y dedicarlo a cualquier cosa que nos guste (no necesariamente trabajar).

Conclusión: como profesionales, como personas, nuestro interés está en la retroalimentación positiva a partir no sólo de los resultados sino de examinar cómo hemos atravesado el proceso. El buen producto mejorará más o menos la vida del cliente, pero la retroalimentación mejorará la nuestra.