Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

18 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
jueves, 19 de julio de 2007
Hace tiempo ya, oí hablar sobre el libro The Mytical Man-Month, de Frederick P. Brooks, donde se asegura que los mejores programadores rinden hasta 10 veces más que los que se encuentran en el lado opuesto, los peores. Otras fuentes, como "Facts and Fallacies of Software Engineering" llegan a indicar que la diferencia puede ser incluso de 28 a 1.

Sin duda, la productividad en el desarrollo es algo más que tirar muchas líneas de código por día; ya lo comenta Charles Connell en su artículo It's not about lines of code, donde explica por qué la productividad no puede ser medida en esos términos, de hecho, ¿muchas líneas de código implican un trabajo bien hecho? ¿y si se trata de un nido de bugs?

Así, a lo largo de su artículo, Charles va definiendo y añadiendo características que debería presentar el código creado hasta llegar a una posible unidad de medida de la productividad, líneas de código limpio, simple, correcto y bien documentado por día, para finalmente llegar a la conclusión de que tampoco es del todo apropiado: ¿qué ocurre si un buen desarrollador es capaz de crear una función en 100 líneas de código perfecto y salir de la oficina a la hora habitual, mientras que otros realizan el mismo buen trabajo en 2000 líneas de código trabajando hasta altas horas de la madrugada? ¿quién es más productivo?

La conclusión de Charles es que la productividad de un desarrollador es justamente su habilidad para resolver problemas de forma rápida. La ingeniería del software trata precisamente de eso, de aportar soluciones a los usuarios que usarán el sistema desarrollado, todo lo demás sobra. Sin embargo, como él mismo indica, es realmente difícil medir estas capacidades utilizando indicadores habituales como número de líneas de código, bugs provocados o tiempo de trabajo en la oficina.

Partiendo de esto, en "10 Developers For The Price Of One", Phil Haack, cuyo apellido seguro que lo predestinó a dedicarse a la informática, escribe sobre este tema centrando la medida de la productividad de los desarrolladores en torno al concepto TCO (Total Cost of Ownership), o Coste Total de Propiedad (CTO), e introduce algunas características propias de los buenos desarrolladores que hace que este factor sea óptimo.

La primera de ellas es la asunción de un proyecto como propio, la autosuficiencia en la resolución de problemas, tomar el control, resolver y asumir el avance del mismo como un objetivo personal. De esta forma se libera a los responsables de estar tan pendientes de estos aspectos y se recurre a ellos sólo cuando surgen problemas de entidad y con objeto de plantear una solución. Un desarrollador que escribe código rápido no es productivo, pues requiere de tiempo de los demás, y sobre todo, de aquellos que por sus responsabilidades disponen de menos tiempo.

La segunda hace referencia a la escritura de código con pocos errores. Un mal programador que escriba código muy rápidamente es un generador de bugs a una velocidad proporcional, lo que provocaría un mayor gasto de tiempo del equipo de testeo y control de calidad, así como del propio equipo de desarrollo en la corrección de los errores. Como comenta Phil, de nada vale ir rápido hacia la dirección equivocada.

En la tercera, se introduce el concepto de la creación de código mantenible. Y no sólo pensando en el mantenimiento futuro del software, sino durante el propio desarrollo inicial. Me ha gustado mucho su visión sobre esto, textualmente, Tan pronto como una línea de código sale de la pantalla y volvemos a ella, estamos en modo mantenimiento de la misma". Un código bien escrito, comprensible y limpio puede ahorrar mucho tiempo en el presente y futuro.

En cuarto lugar, comenta que los buenos desarrolladores hacen más con menos código, son capaces de identificar cuándo deben y cuándo no deben escribir software y utilizar componentes o elementos existentes. El reinvento de la rueda, no es beneficioso para nadie, y los buenos programadores suelen y deben esquivarlo.

Teniendo todos estos aspectos en cuenta, Phil retoma el concepto TCO indicando que todos estos factores son importantes a la hora de evaluar la productividad de un desarrollador en tanto en cuanto que influyen en el coste total de tener a un programador en la empresa, y no sólo fijándose en el coste directo que representa su nómina. Por ello asegura que intenta contratar, aunque no siempre lo consigue, al mejor desarrollador que encuentra en cada momento puesto que si es capaz de hacer más con menos código, escribir de forma inteligible, fácilmente mantenible y con menos errores, incrementará la productividad de sus compañeros, directivos y colegas. Por el contrario, un mal desarrollador puede disminuir la productividad de su entorno por los motivos anteriormente expuestos. Por este motivo puede justificarse la relación de 28 a 1 en la productividad entre unos y otros.

Estoy absolutamente de acuerdo con estas apreciaciones, un desarrollador no puede ser evaluado únicamente teniendo en cuenta aspectos cuantitativos como la cantidad de líneas de código que es capaz de generar: si lo que buscas es velocidad a la hora de teclear, contrata a un mecanógrafo, leche. Y aunque para cerrar un proyecto hace falta escribir líneas, tanto o más importante es la calidad con que esto se haga o tener capacidad para decidir cuándo hay que reutilizar en vez de escribir.

Quizás, por poner alguna pega, echo en falta un par de factores que a mi entender son fundamentales para aumentar la productividad en el desarrollo, y están relacionadas con la visión global introducida en el artículo citado anteriomente.

En primer lugar, la capacidad de comunicación bidireccional, es decir, ser tanto capaz de entender los mensajes de los usuarios, de analistas, comerciales o cualquier otro grupo de interés, como transmitir claramente mensajes, problemas o cuestiones siempre adaptándose a su interlocutor. Esta es, en mi opinión, una habilidad difícil de encontrar y que puede repercutir de forma muy negativa en la productividad global de un equipo de trabajo. ¿Quién no ha tenido que desechar código por culpa de un malentendido?

En segundo lugar, es fundamental la facilidad de integración en equipos de trabajo. Los desarrolladores trabajando en islas son difíciles de ver, la complejidad del software actual hace que en casi cualquier proyecto tengan que intervenir varias personas colaborando de forma muy estrecha. Además, en una máquina perfecta de producción de software la información y conocimientos fluyen con facilidad, lo cual influye en la productividad de cada uno de los componentes de la misma.

Curiosamente, ninguna de estas dos habilidades son técnicas... Sin duda esto de la productividad es un tema tan interesante como complejo, ¿eh?

martes, 17 de julio de 2007
Como en internet hay de todo, a alguien se le ha ocurrido desarrollar una bonita web en Flash con un curioso jueguecillo: se nos van mostrando consecutivamente fotografías de personajes (concretamente diez), y debemos identificar cuál de ellos es un inventor de lenguajes de programación y cuál es un asesino en serie (!).

Y es que es verdad que algunos tienen unas pintas... Pero bueno, seguro que si en vez de hacerlo con informáticos lo hacen con cualquier otro tipo de profesionales les habría quedado igual de bien, aunque probablemente perdería el morbo que tienen los programadores y su fama de ser gente rara, muy rara, y con un físico acompañando a su presunta personalidad.

La dirección es: http://www.malevole.com/mv/misc/killerquiz.

He acertado 9 sobre 10, se ve que identifico bien a mis colegas... (me refiero a los programadores, claro ;-)). ¿Y tú? ¿Qué nota has conseguido?
viernes, 13 de julio de 2007
A partir de ayer mismo, por cortesía de Armonth (fundador de SigT), tengo el honor de compartir cartel con los grandes maestros en Planet Webdev, un agregador de blogs sobre programación e internet de lo más recomendable por la cantidad, y sobre todo la calidad, de los autores que colaboran en el proyecto.

Por citar sólo a algunos, podemos encontrar a Anieto2k, Javier Pérez, InKiLiNo, Boja, Xavier, y así hasta 30 figuras de este mundillo.

Espero contribuir desde Variable not found a difundir información y compartir conocimientos y experiencias sobre esta profesión que tanto nos apasiona.
lunes, 9 de julio de 2007
Después de celebrar el primer año de vida del blog le debía un regalito: tener su propio nombre de dominio, que no podía ser otro que http://www.variablenotfound.com/.

Y ya que estaba de obras, he aprovechado para incluir utilidades para feeds de mano de Feedburner, con un interesante conjunto de herramientas para la suscripción que espero faciliten la vida a más de uno.

En ambos casos el cambio ha resultado sencillísimo. Ha bastado la inclusión de un registro CNAME en el panel de control DNS del dominio para declararlo como alias de un servidor Google y la modificación en un parámetro de la configuración Blogger para que el servidor comenzara a responder al nuevo nombre. El procedimiento viene muy bien descrito, aunque en inglés, en la dirección http://help.blogger.com/bin/answer.py?answer=55373&hl=en&ctx=rosetta.

Feedburner, como servicio con solera en este mundillo, ofrece también una instalación de lo más sencilla. Una vez completado el registro como usuario, dispone de un generador de código HTML a través del cual podremos ir añadiendo los enlaces a los distintos tipos de suscripción disponibles. Por tanto, como viene siendo habitual en estos servicios, todo se reduce, a lo sumo, a una secuencia de copiar y pegar.

De todas formas estaré durante un tiempo alerta por si detecto algo que funcione mal; confío que me aviséis si véis algo raro, eh?

He dejado para más adelante otros cambios que tengo en mente, como pegar el salto a WordPress, o modificar totalmente el aspecto de la página. Pero esto será ya otra historia...
domingo, 8 de julio de 2007
Uno, que es inocente por naturaleza, asume que utilizar AJAX, acrónimo cuyas siglas corresponden con Asynchronous Javascript And XML, implica el uso de Javascript, comunicación asíncrona con el servidor y XML como formato de intercambio de información.

Lo primero es absolutamente cierto. Javascript es la base actual de AJAX; sin duda es el lenguaje de moda para la programación de funcionalidades avanzadas en cliente, está relativamente bien soportado por los navegadores modernos (o al menos son bien conocidas las particularidades de cada browser) y ofrece una potencia más que suficiente para lo que habitualmente pretendemos utilizarlo.

Lo segundo, la comunicación asíncrona con el servidor, es sólo relativamente cierto. Además de ser posible y útil la comuncación síncrona, hoy en día el término AJAX se utiliza con demasiada frecuencia; basta hacer una web tenga algún script para asegurar que estamos usando esa tecnología punta. Y no, señores, que los menús dinámicos ya se hacían con DHTML hace muuchos muuuchos años.

Sin embargo, hay librerías y frameworks AJAX que, entre otras características, incluyen funciones con efectos visuales realmente espectaculares, y esto cala muy rápidamente en los usuarios y desarrolladores al ser realmente sencillos de integrar y utilizar. De hecho, es fácil encontrar aplicaciones que utilizan de forma masiva estos componentes y no utilizan intercambio de datos alguno con el servidor.

Y por último, la gran decepción: no tiene por qué usarse XML. Lo que parecía tan obvio (de hecho, en un nuevo alarde de ignorancia y osadía lo aseguré en el post Llamar a servicios web con ASP.NET AJAX paso a paso), no es así la mayoría de las veces, y me explico.

XML, a pesar de su estandarización, interoperabilidad y claridad de lectura es lento a la hora de ser procesado. Si habéis probado a manejar un documento complejo usando XMLDOM o similares, habréis comprobado lo engorroso y lento que resulta recorrer o crear la estructura y acceder a sus elementos. Y claro, si se utiliza este lenguaje para comunicar cliente con servidor se supone que esta complejidad se produce en ambos extremos del intercambio de datos, lo cual no resulta agradable ni a la hora de desarrollarlo ni una vez puesto en explotación, puesto que se pretende que este intercambio sea rápido.

En su lugar se suelen utilizar formatos más ligeros, fácilmente procesables y manejables tanto desde cliente como desde servidor, y aquí la estrella es JSON (JavaScript Object Notation), un formato ligero para el intercambio de información basado, como XML, en texto plano, muy estructurado, de fácil lectura, con una gran difusión y, sobre todo, muy fácil de procesar tanto desde Javascript como desde software en servidor. Una prueba de su popularidad es que el propio Yahoo! adoptó JSON como formato de intercambio de datos con sus servicios, aunque sigue permitiendo XML.

Sin embargo, como siempre que existen distintas opciones para hacer lo mismo, hay un fuerte debate sobre la conveniencia de usar XML o JSON, con continuas luchas entre uno y otro bando en las que se aportan las ventajas de utilizar una opción y las debilidades de la opuesta. Vamos, lo de siempre (Windows/Linux, Internet Explorer/Firefox, PlayStation/Xbox, Burger King/Mc Donnald's...).

Como curiosidad, decir que se ha llegado a acuñar el término AJAJ para identificar a la tecnología que combina el Javascript Asíncrono con JSON (de ahí la "J" final), pero es obvio que el término no es tan atractivo como AJAX y ha sido descartado. Además, el uso de otros formatos de intercambios podría dar lugar a extrañas variaciones de las siglas que inundarían el ya colmado espacio mental reservado para estas aberraciones. Por ejemplo, si en vez de XML usamos HTML, la tecnología debería llamarse AJAH; si la complementamos con CSS podría ser AJACH; si usamos también comunicación síncrona necesitaríamos SAJACH. Y así hasta el infinito y más allá.

Por ello, y esto sí que es importante, parece que existe finalmente un gran consenso respecto a la utilización del término Ajax (mayúsculas la inicial, minúscula el resto), de forma que deje de ser un acrónimo y se convierta en un nombre propio que identifique a la filosofía, no al conjunto de tecnologías que se usan por debajo. Esto, además, supone un giro radical en su definición: mientras que AJAX es un término centrado en la tecnología, Ajax está centrado en el usuario, en lo que ve, en lo que obtiene, en su forma de relacionarse con el sistema, relegando los aspectos tecnológicos a un segundo plano.

Por cierto, otro día dedicaré un post en exclusiva a JSON, que creo que es lo suficientemente interesante como para dedicarle un ratito.

martes, 3 de julio de 2007

Sí, he de admitir que es una pregunta rara, pero me la hago desde que conocí hace ya muchos años que en lenguaje C podía incrementar una variable de tres formas, autoincrementando (var++), incrementando en uno (var+=1) o sumando la unidad (var=var+1)... ¿hay alguna diferencia entre ellas? Esta absurda inquietud la he mantenido durante lustros, viendo cómo estas construcciones se propagaban hacia lenguajes más actuales con sintaxis basada en C, como C++, C# o Java.

Claro está que desde el punto de vista semántico no existe diferencia alguna, pues todas comparten el mismo objetivo: incrementar en una unidad la variable indicada. Sin embargo, ¿existe diferencia en la forma en que el compilador las trata? ¿se genera código más eficiente utilizando una de ellas, o son absolutamente iguales?

Para responder a esta cuestión, he realizado una pequeña aplicación en varios lenguajes y plataformas, generado posteriormente un ejecutable y desensamblado el binario de salida con la herramienta correspondiente en cada caso. A continuación describo los resultados obtenidos.

En primer lugar, he atacado al lenguaje C, compilado bajo Linux con gcc y desensamblando con ndisasm.

La aplicación con la que he realizado las comprobaciones era la siguiente:

#include "stdio.h"
main()
{
int i;
i = 0x99f;
i++;
i += 1;
i = i + 1;
printf("Vale: %d", i);
}

Nota: el 0x99f con el que inicializo la variable "i" me sirve para buscar rápidamente en el código ensamblador dónde se encuentran las instrucciones a estudiar.

Bueno, a lo que vamos. Una vez compilado y desensamblado, el código que encuentro es:

...
mov word [di-0x8], 0x99f
add [bx+si], al
add word [di-0x8], byte +0x1
add word [di-0x8], byte +0x1
add word [di-0x8], byte +0x1
...

Según parece, el compilador gcc ha generado exactamente el mismo código en todos los casos. La verdad es que este resultado me ha sorprendido un poco, esperaba que se utilizaran en los primeros casos las instrucciones de incremento directo del procesador, optimizando el binario generado, pero no ha sido así. A la vista de esto, he preguntado a Google y parece ser que es un comportamiento recomendado para los compiladores de C, por lo que podemos dar por concluida esta línea de la investigación.

A continuación he pasado a C#, compilando tanto con .NET Framework de Microsoft como con Mono. La aplicación era similar a la anterior (traducida, obviamente), y el resultado en lenguaje intermedio (MSIL), obtenido tanto con ildasm como con su equivalente monodis es el mismo:

[...]
//000011: int i = 0x99f;
IL_0001: ldc.i4 0x99f
IL_0006: stloc.0
//000012: i++;
IL_0007: ldloc.0
IL_0008: ldc.i4.1
IL_0009: add
IL_000a: stloc.0
//000013: i += 1;
IL_000b: ldloc.0
IL_000c: ldc.i4.1
IL_000d: add
IL_000e: stloc.0
//000014: i = i + 1;
IL_000f: ldloc.0
IL_0010: ldc.i4.1
IL_0011: add
IL_0012: stloc.0
[...]

Podemos observar que, como en el caso anterior, el compilador no diferencia entre el tipo de incremento que utilicemos, da exactamente igual.

Por último, probamos con Java 5, utilizando el JDK de Sun. La aplicación es exactamente igual a las anteriores, con la correspondiente adaptación a este lenguaje, algo así como:

class Prueba
{
public static void main(String[] args)
{
int i = 0x99f;
i++;
i+=1;
i=i+1;
System.out.println("Vale: " + i);
}
}

El compilador de Java, en este caso, sí hace distinciones entre los dos primeros modelos de incremento y el tercero. El autoincremento e incremento los genera exactamente iguales, creando una instrucción bytecode de incremento en una unidad, mientras que el último lo crea como una suma; supongo que la primera será posible optimizarla y su ejecución será más rápida:

 0: sipush 2463
3: istore_1
// i++:
4: iinc 1, 1
// i+=1:
7: iinc 1, 1
// i=i+1:
10: iload_1
11: iconst_1
12: iadd
13: istore_1
// Resto...
[...]

En resumidas cuentas, podemos usar con toda tranquilidad cualquiera de los operadores de suma para incrementar una variable, puesto que el código será igual de eficiente (o poco eficiente, según se mire) y prácticamente no tendrá incidencia en la velocidad de ejecución, al menos con las opciones de compilación por defecto. Sólo Java parece estar adelantado en este sentido, pues es capaz de distinguir estos casos.

Y sí, era una inquietud de lo más absurda, lo dije desde el principio, pero me he quedado muy tranquilo, y con una duda menos en mi saco de ignorancia.