Cómo programar mal: La API de Windows (I)
Para mi más completa desgracia, últimamente me he tenido que pelear bastante con la API de Windows. No será la primera vez que digo que esta API tiene tantas cosas mal hechas que darían para escribir un libro. Y voy a comenzar por ahí.
Voy a utilizar la API pública de microsoft para explicar cosas que NUNCA deberían haberse hecho así. Si hay un millón de opciones, se ha elegido la peor.
Hoy tan sólo voy a analizar una función de esta API: FormatMessage .
Cuando programo en GNU/Linux y alguna función del sistema da error, lo habitual
es que se pueda consultar el error genérico preguntándole a errno
. En Windows
es exactamente igual, solo que hay que llamar a GetLastError()
.
Cuando en GNU/Linux queremos obtener una cadena de texto genérica que explique
el código de error, basta con llamar a strerror , que devuelve una cadena
constante (es decir, que no tenemos que liberar) con el mensaje de error. Si lo
preferimos, podemos usar strerror_r
, que nos copia la cadena a un buffer.
En la API de windows existe una función semejante. O debería decir una “aberración” semejante. El problema es que han juntado las dos funcionalidades en una.
Aberraciones
Aberración 1: una función con 7 parámetros
Algo tan simple como buscar en un vector de cadenas de texto y devolver una me obliga a llamar a una función con 7 parámetros.
Aberración 2: Números mágicos
El primer parámetro es una combinación de números mágicos que tengo que conocer
y saber cómo mezclar (mediante operaciones OR
).
Aberración 3: Decidir el modo de funcionamiento en función a un parámetro
El primero de los parámetros es un número que va a alterar el comportamiento de
toda la función. Una equivocación aquí y podré obtener un bonito Segmentation Fault
o me dejaré memoria sin liberar. Ideal para los amantes de los deportes
de riesgo.
Aberración 4: Cambiar el tipo de un dato en función a otro parámetro
Dependiendo de lo indicado en el primero de los parámetros (flags), se decide si se está utilizando un puntero a caracter o un puntero a puntero a caracter. Vamos, lo mismito.
Aberración 5: Mezclar parámetros de entrada con parámetros de salida
Es deseable evitar devoler datos mediante los parámetros, aunque en C hay muchas veces que no queda más remedio. Pero lo habitual es poner los de salida al final, de forma que quede una estructura lógica: primero entran datos y luego salen.
Como somos más chulos que un ocho y queremos amargarle la vida al que venga detrás, mezclamos los parámetros de entrada y los de salida que lo adivine el siguiente.
Aberración 6: Parámetros opcionales
Por si resulta fácil usar la función, haremos que algunos de los parámetros sean opcionales. Así ignoraremos lo que pongan aquí si se han equivocado en los “flags” iniciales.
Defender lo indefendible
¿Cómo puede haber una mente tan retorcida como para engendrar semejante cúmulo de malas prácticas? ¿Cómo puede defenderse que una función con estas características es “usable”?
Sinceramente, a veces me maravillo a mí mismo de las excusas que damos los programadores. Seguramente fue un intento de evitar tener que escribir diferentes funciones para “hacer lo mismo” (si una función reserva memoria y otra no, ya no hacen lo mismo).
O una manera de recordar fácilmente qué función hace lo que quiero (claro, con una función ya lo hago todo), frustrada por el hecho de que necesito consultar la ayuda para ver qué “flags” tengo que activar.
O una manera de poder incrementar la funcionalidad de la función sin tener que escribir funciones nuevas. Parece una gilipollez, pero esto lo he oído mucho más de lo que me gustaría.
En fin, que cada vez que una función de la API me da un error, me imprimo el código ya buscaré en la ayuda de Microsoft, que por lo menos estaré seguro de que mi programa no va a explotar.
Próximamente: imprimir un documento con la API de Windows.