Haciendo que el código defectuoso se vea defectuoso

From The Joel on Software Translation Project

Jump to: navigation, search

Por Joel Spolsky
11 de mayo del 2005
Artículo original: [http://www.joelonsoftware.com/articles/Wrong.html
Traducido originalmente por: Laurens Rodriguez


Contents

Introducción

Mucho tiempo atrás en septiembre de 1983, empecé mi primer verdadero empleo, trabajando en Oranim, una gran fabrica de pan en Israel que hacia algo como 100,000 piezas de pan cada noche en seis hornos gigantes del tamaño de transportadores de avión.

La primera vez que caminé dentro de la panadería no podía creer el desorden que era. Los costados de los hornos estaban amarillentos, las maquinas se estaban oxidando, había grasa por todo sitio.

  • “¿Es siempre así de desordenado?” Pregunté.
  • “¿Qué? ¿De que estas hablando?” me dijo el administrador. “Acabamos justo de limpiar. Es lo mas limpio que hemos estado en varias semanas.”

Oh chico.

Me tomo un par de meses de limpiar la panadería cada mañana antes de que pudiera darme cuenta a que se referían. En la panadería, limpio significa no masa en las maquinas. Limpio significa no masa fermentada en la basura. Limpio significa no masa en el suelo.

Limpio no significa que la pintura en los hornos sea blanca y brillante. Pintar los hornos es algo que haces cada década, no cada día. Limpio no significa no grasa. De hecho había un montón de maquinas que necesitaban ser engrasadas o aceitadas regularmente y una delgada capa de aceite era usualmente la señal de que una maquina había sido limpiada recientemente.

This is what a dough rounder looks like.El concepto entero de limpieza en la panadería era algo que tenias que aprender. Para un extraño, era imposible caminar dentro y juzgar si el lugar estaba limpio o no. A un extraño nunca se le ocurriría mirar las superficies internas del dough rounder (una maquina que hace rodar bloques cuadrados de masa en bolas, mostrado en la fotografía de a la derecha) para ver si han sido raspados hasta estar limpios. Un extraño se obsesiona con el hecho de que el viejo horno tiene paneles decolorados, porque esos paneles son enormes. Pero a un panadero le importa poco si la pintura exterior de su horno se esta empezando a poner un poco amarillenta. El pan aun sabe tan bien como siempre.

Después de dos meses en la panadería, aprendes a “ver” lo que es limpio.

El código es igual.

Cuando recién empiezas como un programador principiante o tratas de leer código en un nuevo lenguaje todo se ve igual de inescrutable. Hasta que entiendes el lenguaje en si no puedes ver aun los obvios errores de sintaxis.

Durante la primera fase del aprendizaje, empiezas a reconocer las cosas a las que nosotros los programadores usualmente nos referimos como “estilo de programación.” De modo que comienzas a notar código que no toma en cuenta estándares de indentación o extrañas variables escritas todo en mayúsculas.

Es en este punto cuando típicamente dirás, “Recorcholis Batman!, necesitamos implementar algunas convenciones de código sensatas aquí!” y entonces te pasas el resto del día escribiendo convenciones de código para tu equipo y los próximos seis días discutiendo acerca del Verdadero y Único Estilo de Poner Llaves y las próximas tres semanas reescribiendo código antiguo para que este de acuerdo al Verdadero y Único Estilo de Poner Llaves hasta que alguien de arriba te atrapa y te regaña por gastar el tiempo en algo que nunca hará dinero, y decides que no es tan mala cosa reformatear el código solo cuando tengas que revisitarlo, así que te quedas con casi la mitad de código en el Verdadero y Único Estilo de Poner Llaves y bastante pronto te olvidas acerca de todo esto y empiezas a obsesionarte acerca de otra cosa irrelevante a lo de hacer dinero como reemplazar un tipo de clase de cadena con otro tipo de clase de cadena.

A medida que te vuelves más experto en escribir código en determinado entorno, comienzas a aprender a ver otras cosas. Cosas que pueden ser perfectamente legales y estar perfectamente OK de acuerdo a las convenciones de código, pero que te hacen preocuparte.

Por ejemplo, en C:

char* dest, src;

Esto es código legal; puede estar de acuerdo a tus convenciones de código, y puede ser aun lo que se quería que fuera, pero cuando tienes suficiente experiencia escribiendo código en C, te darás cuenta que esto declara dest como un puntero a char mientras declara src meramente como un char, y aun puede ser que sea esto lo que tu querías, aunque probablemente no lo sea. Este código huele un poco mal. Aun más sutil:

if (i != 0)
   foo(i);

En este caso el código es 100% correcto; es conforme con la mayoría de convenciones de código y no hay nada de malo con el, pero el hecho de que la única instrucción del cuerpo del if no este encerrado en llaves puede ser que te este molestando, debido a que puedes estar pensando en el fondo de tu cabeza, zanbomba, alguien podría insertar otra línea de código aquí

if (i != 0)
   bar(i);
   foo(i);

… y olvidar agregar las llaves, ¡Y accidentalmente hacer entonces foo(i) incondicional! Es por eso que cuando ves bloques de código que no están entre llaves, te parece sentir una pequeñísima, minúscula, pizca de suciedad que te hace sentir intranquilo.

OK, hasta aquí he mencionado tres niveles de realización como programador:

1) No distingues lo limpio de lo sucio.

2) Tienes una idea superficial de lo que es limpio, mayormente al nivel de acatar las convenciones de código.

3) Empiezas a oler sutiles pistas de suciedad debajo de la superficie y te fastidian lo suficiente como para corregir el código.

Aunque aún hay un nivel superior, del cual es el que yo quiero hablar:

4) Deliberadamente diseñas tu código de tal forma que tu olfato por la suciedad hace que tu código sea probablemente correcto.

Este es el verdadero arte: hacer el código robusto a través de literalmente inventar convenciones que hagan que los errores sobresalgan en la pantalla.

Así que ahora te encaminaré a través de un pequeño ejemplo, y después te mostrare una regla general que puedes usar para inventar esas convenciones de código seguro, lo que al final nos conducirá a una defensa de cierto tipo de notación Húngara, aunque probablemente no del tipo que hace a la gente sentir nauseas, y a una critica de las excepciones en ciertas circunstancias, aunque probablemente no del tipo de circunstancias que encuentras la mayor parte del tiempo.

Sin embargo si estas convencido que la notación Húngara es La Peor Cosa y que las excepciones son la mejor invención desde el batido de chocolate y no quieres ni oír otra opinión, bien, ve de frente a lo de Rory y lee su excelente comic en vez de esto; de cualquier modo no te estarás perdiendo de mucho aquí; de hecho en un minuto voy a poner ejemplos de código reales los cuales probablemente te pondrán a dormir aun antes de que tengas oportunidad de enojarte. Sip. Pienso que el plan será arrullarte hasta que estés casi dormido y entonces inadvertidamente, mandarte la “Húngara = Bueno”, “Excepciones = Malo” idea en ti cuando estés todo soñoliento y no des mucha batalla.

Un Ejemplo

Correcto. Vamos con el ejemplo. Pretendamos que estas construyendo algún tipo de aplicación web, dado que parece estar en todo su furor para los chicos de ahora.

Ahora, hay una vulnerabilidad de seguridad llamada Cross Site Scripting Vulnerability, alias XSS. No entrare en detalles aquí: todo lo que hay que saber es que cuando construyas una aplicación web tienes que ser lo suficientemente cuidadoso de nunca devolver cualquier cadena que el usuario ingrese en los formularios.

Así que por ejemplo si una pagina web dice “¿Cual es tu nombre?” con una campo de texto y después de enviar la pagina te lleva a otra pagina que dice, “Hola, Elmer!” (asumiendo que el nombre de usuario es Elmer), bien, esa es una vulnerabilidad de seguridad, debido a que el usuario podría ingresar todo tipo de bizarro HTML y JavaScript en ves de “Elmer” y ese bizarro JavaScript podría hacer cosas sucias, y esas cosas sucias podrían parecer venir de ti, así que por ejemplo ellos podría leer cookies que pusiste allí y reenviarlos al maligno sitio del Dr. Maligno.

Pongámoslo en seudo código. Imagina que

s = Request("name")

lee la entrada (un argumento POST) del formulario HTML. Si alguna vez escribiste este tipo de código:

Write "Hola, " & Request("name")

Tu sitio ya es vulnerable a ataques XSS. Es todo lo que se necesita.

En ves de ello tienes que “codificarlo” antes de volverlo a copiar de regreso dentro del HTML. Codificarlo significa remplazar " con ", remplazar > con >, y así. De tal modo que

Write "Hola, " & Encode(Request("name")) 

Es perfectamente seguro.

Todas las cadenas que se originan del usuario son inseguras. Cualquier cadena insegura no debería ser enviada a la salida sin ser codificada.

Tratemos de idear una convención de código que asegurara que si alguna vez cometes este error, el código se verá evidentemente erróneo. Si el código erróneo, al menos, luce erróneo, entonces tiene una alta probabilidad de ser atrapado por alguien trabajando en ese código o revisándolo.

Posible Solución #1

Una solución es codificar todas las cadenas inmediatamente, al instante que vienen del usuario:

s = Encode(Request("name"))

Entonces nuestra convención dice esto: si alguna vez encuentras un Request que no esta rodeado por un Encode, el código debe estar mal.

Y empiezas a entrenar tus ojos para buscar solitarios Request, debido a que ellos violan la convención.

Esto funciona, en el sentido de que si sigues esta convención nunca tendrás un bug XSS, pero esto no es necesariamente la mejor arquitectura. Por ejemplo puede ser que desees almacenar estas cadenas de usuario en una base de datos en algún sitio, y no tiene sentido tenerlos almacenado codificados en HTML dentro de la base de datos, porque podrían ir a algún lugar que no sea una pagina HTML, como una aplicación que procesa tarjetas de crédito y serian confundidas si están codificadas en HTML. La mayoría de aplicaciones web son desarrolladas bajo el principio que internamente todas las cadenas no son codificadas hasta el último instante antes de ser enviadas a la página HTML, y esa es probablemente la arquitectura correcta.

Realmente necesitamos ser capaces de mantener las cosas alrededor en un formato inseguro por un rato.

OK. Lo intentaré de nuevo.

Posible Solución #2

¿Que tal si hacemos una convención de código que dice que cuando debamos escribir por salida una cadena debemos codificarla?

s = Request("name")
// mucho después:
Write Encode(s)

Ahora cuando quiera que veas un solitario Write sin el Encode sabes que algo esta fuera de lugar.

Bueno, esto no trabaja muy bien… a veces tienes pequeños bits de HTML alrededor en tu código y no puedes codificarlos:

If mode = "lineBreak" Then prefix = "<br>"
// mucho después:
Write prefix

Esto se ve mal de acuerdo a nuestra convención, la cual nos requiere codificar las cadenas en la salida:

Write Encode(prefix)

Pero ahora el "<br>", el cual se supone debe empezar una nueva línea, es codificada a “&lt;br&gt;” y se le aparece al usuario como un literal “< b r >”. Lo que no esta bien tampoco.

Así que, a veces no puedes codificar las cadenas cuando las lees como entrada, y a veces no puedes codificarlas cuando las escribes como salida, así que ninguna de estas propuestas funciona. Y sin una convención, aun estamos corriendo el riesgo de hacer esto:

s = Request("name")
//...paginas después:
name = s
//...paginas después:
recordset("name") = name // guardar nombre en base de datos
//...días después:
theName = recordset("name")
//...meses después:
Write theName

¿Recordamos codificar la cadena? No hay un solo lugar donde se puede buscar el bug. No hay un sitio donde hurgar. Si tienes un montón de código como este, toma un enorme trabajo detectivesco trazar el origen de cada cadena que es alguna vez escrita como salida para asegurarse de que ha sido codificada.

La Verdadera Solución

Así que déjame sugerir una convención de código que funciona. Tendremos solo una regla:

Todas las cadenas que vienen del usuario deben ser almacenadas en variables (o columnas de una base de datos) con un nombre que empieza con el prefijo "us" (por Unsafe String – Cadena Insegura). Todas las cadenas que han sido codificadas en HTML o que vienen de una fuente segura bien conocida deben ser almacenadas en variables con un nombre que empieza con el prefijo "s" (por Safe string – cadena Segura).

Déjame reescribir el mismo código, cambiando nada excepto los nombres de las variables para cumplir nuestra nueva convención.

 us = Request("name")
 
 //...paginas después:
 usName = us
 //...paginas después:
 recordset("usName") = usName // guardar nombre en base de datos

 //...días después:
 sName = Encode(recordset("usName"))

 //...meses después:
 Write sName

La cosa que quiero te percates de la nueva convención es que ahora, si cometes un error con una cadena insegura, siempre puedes verlo en una simple línea de código, siempre y cuando la convención de código sea respetada:

s = Request("name")

es a primera vista incorrecto, debido a que ves el resultado de Request siendo asignado a una variable cuyo nombre comienza con s, lo cual va contra las reglas. El resultado de Request es siempre inseguro así que debe ser asignado siempre a una variable cuyo nombre comienza con “us”.

us = Request("name")

es siempre correcto.

usName = us

es siempre correcto.

sName = us

es ciertamente incorrecto.

sName = Encode(us)

es ciertamente correcto.

Write usName

Es ciertamente incorrecto.

Write sName

Es correcto, como lo es

Write Encode(usName)

Cada línea de código puede ser inspeccionada por si misma, y si cada línea de código es correcta, el cuerpo entero de código es correcto.

Eventualmente, bajo esta convención de código, tus ojos son entrenados a ver Write usXXX y saber que es incorrecto, y también sabes como corregirlo instantáneamente. Ya se, es un poco difícil ver el código incorrecto al principio, pero haz esto por tres semanas, y tus ojos se adaptarán, del mismo modo que el de los panaderos quienes aprenden a dar un solo vistazo a una gigantesca fabrica de pan y ya pueden proferir gritos instantáneamente para que alguien limpie la suciedad reinante.

De hecho podemos extender la regla un poquito, y renombrar (o envolver) las funciones Request y Encode para ser UsRequest y SEncode... en otras palabras, funciones que retornan una cadena insegura o una cadena segura deben empezar con Us y S respectivamente, al igual que las variables. Ahora mira el código:

us = UsRequest("name")
usName = us
recordset("usName") = usName
sName = SEncode(recordset("usName"))
Write sName

¿Ves lo que yo? Ahora puedes ver a ambos lados de la igualdad que empiecen con el mismo prefijo para encontrar errores.

us = UsRequest("name") // ok, ambos lados empiezan con US
s = UsRequest("name") // error
usName = us // ok
sName = us // ciertamente mal
sName = SEncode(us) // ciertamente correcto

De hecho, puedo ir paso más allá, y renombrar Write a WriteS y SEncode a SFromUs:

us = UsRequest("name")
usName = us
recordset("usName") = usName
sName = SFromUs(recordset("usName"))
WriteS sName

Esto hace a los errores aun más visibles. Tus ojos aprenderán a “ver” código maloliente, y esto te ayudara a encontrar escondidos errores de seguridad simplemente a través del proceso normal de escribir y leer código.

Hacer que el código defectuoso se vea defectuoso está bien, pero no es necesariamente la mejor solución posible para todo problema de seguridad. No atrapa cada posible bug o equivocación, debido a que bien podrías no mirar cada línea de código. Pero seguramente es un montón mejor que nada, y yo preferiría tener una convención de código donde el código defectuoso se vea, al menos, defectazo. Además ganas instantáneamente el beneficio incremental de que cada vez que los ojos de un programador pasan sobre una línea de código, ese particular bug es chequeado y prevenido.

Una Regla General

El negocio de hacer que el código defectuoso se vea defectuoso depende de tener las cosas necesarias juntas en un solo lugar de la pantalla. Cuando estoy mirando una cadena, si quiero que el código sea correcto, necesito saber, dondequiera que vea esa cadena, si es segura o insegura. No quiero que esa información este en otro archivo o en otra pagina a la cual tengo que desplazarme. Tengo que ser capaz de ver justo allí y eso significa una convención para nombrar variables.

Hay un montón de otras maneras como puedes mejorar el código por el simple hecho de mover las cosas unas cerca de otras. La mayoría de convenciones de código incluyen reglas como:

  • Mantén las funciones cortas.
  • Declara tus variables lo mas cerca posible al lugar donde las vas a usar.
  • No uses macros para crear tu propio lenguaje de programación personal.
  • No uses goto.
  • No pongas la llave final más allá de una pantalla lejos de la correspondiente llave inicial.

Lo que todas esas reglas tienen en común es que están tratando de de mantener la información relevante acerca de lo que hace realmente cierta línea de código lo mas cerca posible. Esto mejora las oportunidades de que tus pupilas sean capaces de comprender lo que verdaderamente esta sucediendo.

En general, debo admitir que me siento un poco asustado de las características del lenguaje que esconden cosas. Cuando ves el código

i = j * 5;

en C sabes, al menos, que j esta siendo multiplicada por cinco y el resultado es almacenado en i. Pero si ves el mismo pedazo de código en C++, no sabes nada. Nada. El único modo de saber lo que realmente esta sucediendo en C++ es encontrar de que tipos son i y j, algo que puede estar declarado en un lugar completamente inesperado. Esto es debido a que j puede ser de un tipo que tiene sobrecargado el operador * y hace algo totalmente jocoso cuando tratas de multiplicarlo. Además i puede ser de un tipo que tiene el operador = sobrecargado, y los tipos pueden no ser compatibles así que una función de conversión automática terminará siendo llamada. Y el único modo de descubrirlo es no sólo chequear el tipo de las variables, sino encontrar también el código que implementa aquellos tipos, y que Dios te ayude si hay herencia por algún lado, porque ahora tendrás que vagar por todo el camino de la jerarquía de clases por ti mismo tratando de encontrar donde esta realmente el código, y si hay polimorfismo por algún lado, estas en serios aprietos porque ahora no es suficiente saber de que tipo han sido i y j declarados, sino que tienes que saber de que tipo son ellos justo ahora, lo cual puede significar inspeccionar una cantidad arbitraria de código y puede que nunca estés seguro si has revisado o no en todos lo sitios gracias al famoso problema de la parada (fiu!).

Cuando ves i=j*5 en C++ estas, realmente, echado a tu suerte, coleguilla, y eso, a mi manera de ver, reduce tu habilidad para detectar posibles problemas de código mirando simplemente el código.

Nada de esto se suponía que importara, claro. Cuando haces cosas inteligentes de chico-listo como redefinir el operador *, se supone que es con la finalidad de proveerte de una abstracción a prueba de balas. Rayos, j es de tipo Cadena Unicode, y multiplicar una Cadena Unicode por un entero es obviamente una buena abstracción para convertir Chino Tradicional a Chino Estándar, correcto?

El problema es, claro, que las abstracciones a prueba de balas no lo son. Ya he hablado largamente de esto en La ley de las abstracciones defectuosas así que no me reiterare aquí. Scott Meyers ha hecho toda una carrera de solo enseñarte todas las formas en que dichas abstracciones fallan y te muerden, al menos en C++. (Hablando de eso, la tercera edición del libro de Scott Effective C++ acaba justo de salir y esta completamente reescrito; consigue tu copia ya!)

Ok.

Estoy perdiendo la pista. Mejor resumo la historia hasta aquí:

Busca convenciones de código que hagan que el código defectuoso se vea defectuoso. Haciendo que toda la información pertinente esté colocada toda junta en un solo lugar de la pantalla en tu código te permitirá ver ciertos tipos de problemas y corregirlos al instante.

Soy Húngaro

Así que ahora volvamos a la infame notación Húngara.

La notación Húngara fue inventada por el programador de Microsoft Charles Simonyi. Uno de los mas importante proyectos donde Simonyi trabajo en Microsoft fue Word; de hecho él lideró el proyecto para crear el primer procesador de palabras WYSIWYG, algo llamado Bravo en Xerox Parc.

Con el procesamiento de palabras WYSIWYG, tienes ventanas desplazables, así que cada coordenada tiene que ser interpretada como relativa a la ventana o relativa a la página, y eso hace una gran diferencia, y usarlos apropiadamente es muy importante.

Lo cual, supongo, es una de las muchas buenas razones por la cual Simonyi empezó usando algo que vino a ser llamada notación Húngara. Se veía como Húngaro, y Simonyi era de Hungría, de allí el nombre. En la versión de notación Húngara de Simonyi, cada variable tenía como prefijo un rótulo en minúsculas que indicaba que clase de cosa era lo que la variable contenía.

Por ejemplo, si el nombre de la variable es rwCol, rw es el prefijo.

Estoy usando la palabra clase a propósito, aquí, porque Simonyi erróneamente uso la palabra tipo en su informe, y generaciones de programadores malentendieron lo que el quería decir.

Si lees el informe de Simonyi detenidamente, a lo que el se estaba refiriendo era al mismo tipo de convención para nombrar variables que yo he usado en mi ejemplo de arriba donde decidimos que us significa “cadena insegura” y s significa “cadena segura.” Ambos son del tipo string. El compilador no te ayudara si asignas uno por otro e Intellisense no dirá ni pío. Pero ellas son semánticamente diferentes; necesitan ser interpretadas y tratadas de manera diferente y algún tipo de función conversora necesitara ser llamada si asignas una a otra o tendrás un error en tiempo de ejecución. Si tienes suerte.

El concepto original de Simonyi para la notación Húngara fue llamado, dentro de Microsoft, Húngaro para Aplicaciones, debido a que era usado en la división de Aplicaciones, es decir, Word y Excel. En el código fuente de Excel ves un montón de rw y col y cuando los ves sabes que se refieren a filas (rows) y columnas (columns). Sip, ambos son enteros, pero no tiene sentido asignarlos entre si. En Word, te dije, ves un montón de xl y xw, donde xl significa “coordenadas horizontales relativas a la página” y xw significa “coordenadas horizontales relativas a la ventana.” Ambos enteros. No intercambiables. En ambas aplicaciones ves un montón de cb que significan “contador de bytes.” Sip, es un entero de nuevo, pero sabes mucho mas acerca de el simplemente mirando el nombre de la variable. Es un contador de bytes: el tamaño de un buffer. Y si ves xl = cb, bueno, Bam! la Sirena del Código Defectuoso, eso es obviamente código erróneo, debido a que aunque xl y cb son ambos enteros, es completamente descabellado establecer el valor de un desplazamiento horizontal en píxeles a un contador de bytes.

En el Húngaro para Aplicaciones los prefijos son usados para funciones, así como variables. Aunque, para decirte la verdad, yo nunca he visto el código de Word, te apuesto dólares por donas a que hay una función llamada YlFromYw la cual convierte de coordenada verticales de ventana a coordenadas verticales de pagina. El Húngaro para Aplicaciones requiere la notación TypeFromType en vez de la más tradicional TypeToType de modo que cada nombre de función pueda empezar con el tipo de cosa que ella retorna, justo como hice anteriormente cuando renombre Encode a SFromUs. De hecho en correcto Húngaro para Aplicaciones la función Encode debería haber sido llamada SFromUs. El Húngaro para Aplicaciones no te dará realmente ninguna otra opción en como nombrar esta función. Eso es algo bueno, porque es una cosa menos que necesitas recordar, y no tendrás que preguntarte a que tipo de codificación se refiere la palabra Encode: tienes algo mucho mas preciso.

El Húngaro para Aplicaciones fue algo extremadamente valioso, especialmente en los días de programación C donde el compilador no te daba una muy útil verificación de tipos.

Pero entonces algo verdaderamente grave sucedió.

El lado oscuro se apodero de la notación Húngara.

Nadie sabe como o porque, pero parece que los escritores de documentación del equipo de Windows inadvertidamente inventaron lo que ha venido a ser conocido como el Húngaro de los de Sistemas.

Alguien, en algún lugar, leyó el informe de Simonyi, donde el usaba la palabra “tipo,” y pensó que él quería decir tipo, como clase, como tipo de dato de sistema, como del tipo de validación que el compilador hace. Él no dijo eso. Él explico muy cuidadosamente y detalladamente a lo que se refería con la palabra “tipo,” pero no sirvió de nada. El daño ya estaba hecho.

El Húngaro para Aplicaciones había sido muy útil, tenia prefijos llenos de significado como “ix” para indicar un índice dentro de un array, “c” para indicar un contador, “d” para indicar la diferencia entre dos números (por ejemplo “dx” significa “ancho”), y así.

El Húngaro de los de Sistemas tenia de lejos prefijos mucho menos útiles como “l” para un entero largo y “ul” para un entero largo sin signo y “dw” para una palabra doble, la cual es, realmente, bah, un entero largo sin signo. En el Húngaro de los de Sistemas, la única cosa que el prefijo te decía era el tipo actual de la variable.

Esto era una sutil pero completa mal interpretación de la intención y práctica de Simonyi, y esto va a demostrarte que si escribes densa y compleja prosa académica nadie te va a entender y tus ideas serán malinterpretadas y luego esas ideas malinterpretadas serán ridiculizadas aun cuando no fueron tus ideas. así que en el Húngaro de los de Sistemas te quedas con un montón de ulFoo significando “entero largo sin signo foo,” y claro está, el hecho de que una variable sea un entero largo sin signo no te dice maldita cosa útil. así que no es de sorprenderse que la gente se rebelara contra el Húngaro de los de Sistemas.

El Húngaro de los de Sistemas fue promulgado a lo largo y ancho; es el estándar a todo lo largo de la documentación de la programación en Windows; fue difundida extensivamente en libros como Charles Petzold’s Programming Windows, la biblia para aprender a programar en Windows, y rápidamente se convirtió en la forma dominante de Húngaro, aun dentro de Microsoft, donde muy pocos programadores fuera de los equipos de Word y Excel entendían que tal error se había cometido.

Y entonces vino La Gran Rebelión. Eventualmente, programadores que nunca entendieron Húngaro para comenzar, notaron que la malinterpretada convención que estaban usando era Bastante Pesadamente Molesta y Muy buena Para Nada, y se rebelaron contra ella. Ahora, existen aun algunas buenas cualidades en el Húngaro de los de Sistemas, lo cual te ayuda a ver errores. Como mínimo, si la usas, sabrás el tipo de variable en el mismo lugar donde usas esa variable. Pero esto no es ni cercanamente útil como el Húngaro para Aplicaciones.

La Gran Rebelión alcanzo su pico con la primera entrega de .NET. Microsoft finalmente comenzó a decir a la gente, “La notación Húngara No Es Recomendada.” Vaya que hubo un gran regocijo. No creo que se hayan molestado siquiera en decir porque. Se dirigieron justo a la sección de indicaciones para nombrar variables del documento y escribieron, “No Usar notación Húngara” en cada tema. La notación Húngara era tan terriblemente impopular para ese punto que nadie se quejo realmente, y todos en el mundo fuera del equipo de Excel y Word se sintieron aliviados de no tener que usar una convención de nombres tan anticuada que, pensaban, era innecesaria en estos días de poderosa validación de tipos e Intellisense.

Pero hay aun un tremendo valor en el Húngaro para Aplicaciones, en que incrementa el factor de colocación del código, hace que sea fácil de leer, escribir, depurar, y mantener, y, más importante aún, hace que el código defectuoso se vea defectuoso.

Antes de continuar, hay una cosa más que prometí hacer, la cual es meterme con las excepciones una vez más. La última vez que lo hice me metí en un montón de problemas. En una frase algo fuera de tono en la pagina de “Joel on Software”, escribí que no me gustan las excepciones porque ellas son, verdaderamente, un goto invisible, lo cual, razoné, es aun peor que un goto que puedes ver. Claro está decir que millones de personas se abalanzaron por mi garganta. La única persona en el mundo que salto en mi defensa fue, claro está, Raymond Chen, quien es, de paso, el mejor programador del mundo, así que tiene algo que decir, no?

Esto es lo que pasa con las excepciones, en el contexto de este artículo. Tus ojos aprenden a ver lo que esta mal, siempre y cuando haya algo que ver, y eso evita los errores. Si queremos hacer código real, realmente robusto, a la hora de la revisión de código, necesitamos convenciones que permitan ver las cosas lo mas junto posible, a mas información acerca del código que esta en frente de ti, mejor será el trabajo que harás encontrando errores. Cuando veas código que dice

dosomething();       // haz algo
cleanup();           // limpieza

tus ojos te dirán, ¿Que hay de malo con esto? Siempre limpiamos! Pero la posibilidad que dosomething pueda lanzar una excepción significa que cleanup puede no ser llamada. Y eso claro es fácilmente corregible, usando finally o lo que sea, pero ese no es mi punto: mi punto es que el único modo de saber que cleanup esta siendo definitivamente llamado es investigar el árbol entero de llamadas de dosomething para ver si hay algo, en algún lugar, que pueda lanzar una excepción, y eso puede estar bien, y hay cosas como las excepciones controladas para hacerlo menos doloroso, pero el real punto es que las excepciones eliminan el factor de colocación del código. Tienes que buscar en algún lugar diferente para responder a la pregunta de si el código esta haciendo las cosas correctamente o no, así que no serás capaz de tomar ventaja de la habilidad aprendida por tus ojos de ver código defectuoso, debido a que no hay nada que ver.

Ahora, cuando estoy escribiendo un sucio script para resumir un montón de data e imprimirla una vez al día, Rayos si, excepciones son lo máximo. Nada es mas gustoso que ignorar todas las cosas que pueden salir mal y envolver simplemente el maldito programa en un grande y venerable try/catch que me mandará un correo electrónico si algo alguna vez algo sale mal. Las excepciones son buenas para código sucio-y-rápido, para scripts, y para código que no sea de misión crítica o tenga que mantener la vida de pacientes. Pero si estas escribiendo un sistema operativo, o una planta nuclear, o el software para controlar la sierra de alta velocidad usada para una cirugía a corazón abierto, las excepciones son extremadamente peligrosas.

Se que mucha gente asumirá que soy un programador sin experiencia o bastante tonto por no entender las excepciones adecuadamente y no ser capaz de comprender todas las diferentes maneras en que ellas pueden mejorar mi vida si solo estuviera deseoso de permitirles entrar en mi corazón, bueno pues, que mal. El único modo de escribir código realmente fiable es tratar de usar herramientas sencillas que tomen en cuenta la típica fragilidad humana, no complejas herramientas con escondidos efectos colaterales y abstracciones imperfectas que asumen la existencia de programadores infalibles.

Para leer más

Si estás aun todo empecinado acerca de las excepciones, te recomiendo leer el ensayo de Raymond Chen Cleaner, more elegant, and harder to recognize. "Es extraordinariamente difícil ver la diferencia entre código erróneo basado en excepciones y código correcto basado en excepciones... las excepciones son tan difíciles y yo no soy lo suficiente inteligente como para manejarlas."

La queja de Raymond acerca de la Muerte por Macros, A rant against flow control macros, es otro caso en donde no ser capaz de tener toda la información en un solo lugar hace que el código sea inmantenible. "Cuando ves código que usa macros, tienes que bucear a través de los archivos de cabecera para ser capaz de entender que es lo que hacen."

Para más información acerca de la historia de la notación Húngara, comienza con el informe original de Simonyi, Hungarian Notation. Doug Klunder lo presentó al equipo de Excel de una manera algo más clara. Para mas historias acerca de la notación Húngara y cómo fue arruinada por los escritores de documentación, lee el post de Larry Osterman, especialmente el comentario de Scott Ludwig, o el post de Rick Schaut.

Personal tools