miércoles, abril 15, 2009

Una decepción y un rayo de esperanza

La decepción

Apartaos de este libro cuanto podáis: Essential LINQ (Microsoft .NET Development Series). Ni se me ocurriría comprar un libro de Calvert (ya he tenido la mala experiencia), pero pensé que al estar Dinesh Kulkarni en el potaje, la cosa cambiaría. ¡Qué error!:
  • Las dos terceras partes del libro son las típicas obviedades sobre LINQ for Objects que puede encontrar en Intuitive C# gratuitamente, o en el libro de Octavio sobre LINQ por una fracción del precio. Es el tipo de énfasis que hace un autor que odia las bases de datos y sólo le interesa hacer trinos y gorgoritos con el lenguaje.
  • El contenido sobre LINQ to SQL (un sistema ya condenado) es el doble o el triple (me niego a contar páginas) que el contenido sobre el Entity Framework.
  • ... pero ni siquiera el contenido sobre LINQ to SQL es medianamente funcional, así que ya puede imaginar lo que hay sobre el EF.
  • Charlie Calvert nos obsequia con sus mañas características de escritor: apéndices sobre todo lo humano y divino (para engordar el libro y encarecerlo), incluyendo una tabla de seis páginas sobre los atajos de teclados en Visual Studio 2008 (que usted puede encontrar perfectamente en la ayuda de VS).

El rayo de esperanza

Este otro libro, Programming Entity Framework, de Julia Lerman, es harina de otro costal. Para empezar, tiene 792 páginas con un tipo de letra legible, pero compacto. Nada de trucos sucios para engordar artificialmente el contenido.
En segundo lugar, se tratan todos los temas necesarios: ESQL, los puñeteros formatos de bajo nivel para crear un esquema conceptual y mapearlo a una base de datos, el uso avanzado de procedimientos almacenados, los problemas actuales al intentar trabajar en múltiples capas (¡sinceridad, por una vez en la vida!), cómo usar EF desde ASP.NET y Windows Forms, y los problemas y soluciones en cada plataforma...
Además, y esto es muy importante, la autora escribe bien. No he terminado el libro, y me va a llevar un par de semanas, pero hasta donde he llegado, me siento satisfecho.

Etiquetas: , , ,

sábado, abril 04, 2009

Perestroika

¡Gloria eterna al marxismo-fowlerismo!El funcionario de la calva brillante con la mancha como un mapamundi se levantó y se dirigió hacia los micrófonos. Carraspeó y comenzó a hablar cansinamente, como hablaban los funcionarios de la extinta Unión Soviética:
- Daraguíe tavarischi - es decir, "hola, troncos" - El Soviet Supremo me ha encargado la honrosa tarea de comunicaros dos noticias. Una buena y una mala. La buena es que hoy ya es viernes.
Un murmullo de satisfacción teñida de falsa sorpresa recorrió la sala.
- La mala - titubeó, aunque sólo un momento - la mala es que lo nuestro no funciona.
Los ecos del murmullo cesaron abruptamente.
- ... y no me refiero a lo de enfriar en una nevera las semillas de patata antes de sembrarlas, para aclimatarlas al frío - el anciano hijo de Trofim Lysenko se levantó airado y abandonó la asamblea - sino a este invento del comunismo.
Una mosca atravesó la enorme sala zumbando. Nadie la detuvo.
- Sí, coño, hemos estado haciendo el panoli durante setenta años. Y para nada. Hemos matado de hambre a media Ucrania. Hemos jodido a conciencia a polacos, húngaros y checos, y a buena parte de Alemania. ¿Y todo para qué? Para que nuestros obreros pasen hambre y frío, para fabricar estos horribles coches y esos espantosos sintetizadores alemanes democráticos que se funden antes de terminar la primera estrofa de la Kalinka. Esto, maí vesyolye rebyata, no firula...
Los murmullos se reanudaron. El delegado de Dirkadirkastán alzó tímidamente la mano y preguntó:
- Y ahora, ¿qué?
- Ahora - el calvo hizo una pausa teatral - ahora... ¡perestroika!

En Redmond parecen estar también algo revueltos y perestroikos:
Y ya era hora, coño. Ya era hora de que alguien se diese cuenta de que todo este invento del POJO, del POCO y del MOJO POCO no funciona cuando se trata de escribir aplicaciones multicapas. La vanguardia del proletariado, por supuesto, pondrá el grito en el cielo, pero de momento andan callados. Puede que no hayan comprendido lo que hay en juego. En realidad, los fundamentalistas javalinos suelen comprender muy pocas cosas.
Es verdad que los de Microsoft se asemejan más a los chinos que a los rusos: cada cierto tiempo se inventan una Revolución Cultural y no son muy ortodoxos en lo tocante al martinismo-fowlerismo. Además, acaban de perder al Gran Timonel. Y tienen una misma palabra para crisis y oportunidad: suena parecido a crisistunidad.

Etiquetas: , , ,

viernes, marzo 06, 2009

Mientras tanto...

... y porque no solo de pan vive el hombre, un poco de rock instrumental, hecho en casa:
Dedicado a todos los que tienen que enfrentarse día a día con su correspondiente Mr. Butters.

Etiquetas:

lunes, marzo 02, 2009

Mr. Butters (I)

Mr. Butters es un "experto" imaginario, que trabaja en una empresa imaginaria, y que "controla mogollón" sobre bases de datos, aunque la única base de datos con la que ha trabajado en su puñetera vida es Oracle 9, utilizando sólo los trucos que aprendió para Oracle 7. Es un tipo que desconfía de las foreign keys, que considera peligrosos los triggers y los procedimientos almacenados, y que prefiere que el acceso a datos se haga con ODBC... sobre todo por compatibilidad, coño, que somos una empresa seria.
Mr. Butters, Database Expert, Lucky You!
Mr. Butters, por supuesto, es sólo un producto de mi febril imaginación. Cualquier coincidencia con la realidad, es un mero resbalón de mis neuronas.
The Waste Brain

Mr. Butters is the silliest dork, breeding
Incompetence out from the dead land, mixing
Idiocy and arrogance, stirring
Foolishness with an amazing lack of common sense.

Visual Basic kept us warm, covering
Bugs in forgetful snow, feeding...
(etc, etc)

Etiquetas:

sábado, febrero 28, 2009

Ajedrez

Hyperbolic surfaces, ambient occlusion, diffuse reflections, area lights, focal blur

Etiquetas:

miércoles, febrero 18, 2009

Otra seta, perdón, libro sobre LINQ

Cuando comparo este libro con una seta (y la seta sale ganando al final) no es sólo por la capacidad de propagación por esporas de los libros sobre LINQ sino, principalmente, por su potencial alucinógeno. Leo un par de páginas y alucino. Luego viene la resaca. Pasa un par de horas y siento el mono de volver a comprobar cuán malo es el libro. Y así, entre risas y risas, me lo he leído. Pero las setas tienen fibra y son buenas para el colon.
Vale, me he pasado. Si a usted le cuesta leer en pantalla, este libro puede sustituir a la ayuda en línea, siempre que renuncie al índice, a las búsquedas y a ese estilo seco de los documentos de Microsoft que tanto gusta a los amantes del dolor. De todos modos, supongo que tengo que justificarme. Ahí va eso...
El principal problema de (joder, qué pedazo de título)... bueno, de este título, es la bisoñez del autor, acompañada de un exceso de entusiasmo, buenrrollismo y grandes dosis de soberbia injustificada. Este es un libro de apenas 380 páginas, con los típicos listados sin abreviar y con un tipo de letra más grande que la del texto. A pesar de todo esto, el autor se permite escribir un ditirambo de cuarenta páginas en honor a los ORM... demostrando de paso que no tiene ni pajolera idea del asunto. Ahí va un sabroso "tip" (página 5):
Note: Writing stored procedures does not equate to bad design. On the contrary, stored procedures if managed correctly are an excellent alternative to dynamic SQL. If you use a code generator to create your CRUD stored procedures, or if you develop them by hand and have good oversight, in many cases you will be able to use them in conjunction with an ORM tool.
¡Gracias, gran Vijay (así se llama el pavo), por perdonar nuestras viles existencias! Pero siento interrumpir: usted, ¿ha entendido algo? ¿Son buenos o no los procedimientos almacenados? ¿Sólo si se escriben a mano, o si los crea una herramienta? Ah, ¿en ambos casos? Entonces, ¿para qué mencionar que mañana lloverá o no? El problema está en que el Gran Vijay "sabe" que los procedimientos almacenados sólo son buenos si sirven a los propósitos del Gran ORM. Pero soltar tal chorrada es peligroso. Te puede enemistar con esa bestia cejijunta del DBA (en cristiano, el Administrador de Bases de Datos). Los DBA's, cuando se enfadan, te dejan sin índices secundarios y te echan sal en el café.
"Claro, Marteens, cabronazo, pero nos has ocultado el contexto de la parida". Bien aquí tiene el contexto: el señor Mehta nos explica que la compañía X ha escrito software para un fabricante de comida para perros. ¿Y sabe qué?, pues que usaron procedimientos almacenados. La cosa se les escapa de las manos (claro, porque son unos pecadores relacionales). Y de repente, llega la gran oportunidad: pueden vender la aplicación a un fabricante de comida para gatos. Aquí viene la Segunda Parida:
With the increased development costs, Company X won't be making enough money to justify this deal [...] so they hire a consulting company to help reduce their overhead.
Vijay, hermanito, que nunca se te ocurra montar una empresa con los ahorros de papá, que te los vas a fundir. La consultoría, evidentemente, les endiña un ORM a la Compañía X, y según palabrita del niño Vijay, (they) optimize and normalize the company database. Lamento señalar que:
  • Lo de "optimizar y normalizar" suele resultar bastante costoso. Es como empezar de cero. Para que resulte viable, es obligatorio que la consultoría subcontrate programadores en algún país remoto del Tercer Mundo. Quizás los tiros vayan por ahí.
  • Ah, de repente la base de datos carece de "normalización". ¿Esa es una consecuencia de utilizar procedimientos almacenados?
Pero la diversión continúa:
Company X is able to eliminate the thousands of stored procedures (que ya funcionaban) and instead use "automagic" mapping features to generate its SQL. Development costs go down, profits go up and everyone is happy [...]
... especialmente el niño Vijay, que ya tiene el ejemplo canónico que siempre se escribe en los primeros capítulos. Menos mal que enseguida nos aclara que "this is an oversimplified example". Menos mal. Porque cuando la magia entra por la puerta, la inteligencia salta corriendo por la ventana.
Vale, reconozco que los escritores solemos rellenar los primeros capítulos con la misma alegría con la que los chinos echaban melamina en la leche para bebés. El problema es que los problemas continúan a lo largo del libro... excepto en las páginas que contienen información irrelevante, o en las que se limitan a tirar de la ayuda. Para no hacer esta masacre demasiado larga, aquí tiene un botón de muestra, sumamente divertido y revelador. El hermanito Vijay intenta explicarnos por qué prefiere no usar var para declarar variables locales con tipo implícito (p. 149):
The reason to be explicit with the types is the same reason that you strongly type variables in the world of software development: to make it easier to understand and gain a negligible performance increase.
Heeeelp meeee!Las negritas son mías, por supuesto: resulta que este señor no comprende un sencillísimo truco del lenguaje en que programa, y sin embargo, le recomienda pasar a un sistema que exige un conocimiento en profundidad de ese mismo lenguaje y de su modelo de objetos.
Claro, que si usted se siente molesto conmigo puede dar ejemplo de solidaridad y comprarse el engendro. Pero recuerde que, cada vez que alguien compra un libro malo, el Diablo aparece y mata un cachorrito.

La verdad es que me extrañó un poco el ejemplo de la comida para perros. Pero luego recordé que son los musulmanes quienes consideran que el perro es un animal impuro. Los hindúes, en realidad... bueno, no recuerdo si los consideran seres divinos o si se los comen.
Hat tip to Alfredo Novoa: se casan con ellos.

Etiquetas: , , , ,

lunes, febrero 09, 2009

Garantías

Dorothy se enfrenta a la familia política del León CobardeLa Programación no es trabajo ni para cobardes ni para desmemoriados. La máquina es una bestia salvaje atada por una cadena: si queremos ganarnos la vida con ella, tenemos que despojarnos del miedo irracional. Pero también tenemos que recordar, en todo momento, cuál es la longitud de la puñetera cadena.
Cuando hablo de "cadena", usted debe entender "contrato": cada pieza de software debe dejar bien claro qué es lo que hace por nosotros, siempre que le proporcionemos lo que especifica el contrato. Math.Sqrt nos calculará la raíz cuadrada de un número, siempre que le proporcionemos un número no negativo. El indexador de la clase genérica Dictionary nos devolverá el valor asociado a una clave, aunque sólo cuando la clave se haya almacenado antes. Ignorar la existencia de estos contratos nos puede llevar a uno de dos problemas:
  1. Pedimos la raíz cuadrada de menos uno, y el león nos come una oreja.
  2. El problema anterior suele pasar una sola vez. El aprendiz de domador suele quedar aterrorizado, y de ahí en adelante no se acerca al león, excepto cuando su abogado está presente (para que se coma al león en caso necesario). El abogado, por desgracia, termina siendo un problema mayor que el propio león.
A continuación, voy a presentarle varias joyas que muestran los problemas que se pueden presentar cuando el programador decide ignorar, por excesivo terror, las garantías que le ofrecen los contratos. El problema con estas "joyas" es que, cuando uno se las encuentra, pierde un tiempo valioso intentando decidir si:
  1. Se trata de una genialidad.
  2. O se trata de una simple cagada.
El 99% de los casos corresponde a la segunda opción, pero uno se niega a perder tan pronto la fe en el género humano.
La primera perla negra tiene que ver, como no podía ser de otro modo, con la ya mencionada clase Dictionary. Estoy harto de ver este fragmento de código en el software de cierta empresa imaginaria:
if (dict.ContainsKey(key))
dict[key] = value;
else
dict.Add(key, value);
Esto podría pasar como buena programación en Ankh-Morpork, pero aquí solemos ser un poco más exigentes. Un buen día, uno de los leones, el método Add, se adelantó al gato y le comió la lengua al programador, cuando éste intentó insertar una clave duplicada en un diccionario. De ese día en adelante, el programador pincha primero el diccionario con una vara larga, para ver si ya existe la clave. En caso afirmativo, actualiza el valor asociado a la clave; de lo contrario, inserta el nuevo par clave/valor. El problema es que el mismo resultado se obtiene con menos charla:
dict[key] = value;
En efecto, cuando se realiza una asignación sobre el indizador un diccionario, si exista la clave, se actualiza el valor; de lo contrario, se inserta. Hay dos posibilidades: o el programador lo sabía, y se le olvidó... o nunca se tomó la molestia de leerse la documentación. Prefiero pensar lo primero. Al fin y al cabo, la memoria viene genéticamente determinada, y uno no debe reñirle al prójimo por sus genes.
Por cierto, y si me permite el paréntesis, ¿sabía usted que podemos inicializar un diccionario genérico como si se tratase de una vulgar colección? ¡Es que un diccionario genérico es una colección! El quid está en saber qué tipo de colección: sus elementos son instancias de la clase genérica KeyValuePar. Esta es la técnica:
private Dictionary<int, string> d =
new Dictionary<int, string>()
{
{1, "Uno"},
{2, "Dos"},
{3, "Tres"},
};
Preste atención a la coma, aparentemente superflua, que sigue al tercer par de valores. Se trata de un sencillo, pero poco conocido, truco sintáctico que permite añadir o quitar pares, en cualquier momento, sin preocuparnos por el carácter especial del último par. Este mismo truco se aplica a los inicializadores de objetos, e incluso a la declaración de tipos enumerativos. Si le parece una barbaridad y una concesión (hay gente para todo), recuerde que en C# el punto y coma es un terminador, no un separador. ¿Qué hay de malo en querer usar la coma también como terminador, en estos casos?
Vamos ahora a otra garantía que solemos olvidar... o simplemente desconocer. Esta vez, la garantía tiene que ver con el propio lenguaje:
double d = 0.0;
if (cond)
d = 1.0;
else
d = 2.0;
Naturalmente, la inicialización de la variable local sobra:
double d;
if (cond)
d = 1.0;
else
d = 2.0;
No pasa nada porque se deje d sin inicializar... aparentemente. La instrucción que sigue lo garantiza, sin importar cuál de sus ramas se ejecute. Por supuesto, en este caso sencillo, habría sido más fácil escribir todo el código de esta manera:
double d = cond ? 1.0 : 2.0;
El programador que escribió el primer fragmento ha olvidado la sección de la especificación de C# que explica el concepto de asignación definida. La ha olvidado, o nunca se ha tomado la molestia de leerla.
Otro disparate frecuente debido al temor a lo desconocido:
private double f()
{
double d = 0.0;
OpenXXX();
try {
if (cond)
d = f1();
else
d = f2();
}
finally {
CloseXXX();
}
return d;
}
En realidad, el código anterior combina varios disparates debido al olvido o desconocimiento de las garantías de los contratos. Para empezar, vuelve a sobrarnos la inicialización de la variable local: la rama try del bloque try/finally nos garantiza la asignación definida de la variable, y la rama finally es irrelevante, si no utilizamos d en su interior. Tenga en cuenta que, si se ejecuta el finally, nunca llegaremos a la instrucción return.
Pero la zarpa que realmente aterra al programador del ejemplo es la posibilidad de ejecutar un return dentro de la rama try, por desconocimiento (u olvido) del funcionamiento de esta instrucción. Podemos ejecutar ese return sin problemas, y el código se simplifica entonces enormemente:
private double f()
{
OpenXXX();
try {
return cond ? f1() : f2();
}
finally {
CloseXXX();
}
}
El código simplificado es más corto, más comprensible y, probablemente, algo más eficiente, y ya no hablemos de la elegancia. ¿Moraleja? Conozca sus deberes y derechos, tal y como los especifican los contratos de su software, y así será mejor programador. O, mejor aún: RTFM (again).

Etiquetas: , ,