Archivo del Autor: xcubo

Historia de la informática II – Las tarjetas perforadas e IBM

En el anterior artículo, nos quedamos a finales del siglo XIX, con los fracasos a la hora de construir la máquina analítica ideada por Babbage. Sin embargo, las calculadoras mecánicas basadas en las ideas de Pascal y Leibniz se habían llegado ya a comercializar de forma exitosa como los aritmómetros y los comptómetros. Las ideas de Babbage eran demasiado visonarias para la tecnología de la época y es por eso que hasta bien entrado el siguiente siglo no se tomarían en serio.

Con este escenario, y las necesidades de computación de datos en aumento (sobretodo en campos como la demografía) se llegó a finales del siglo XIX.

Es por esto que el siguiente paso para la aparición de la informática como la conocemos hoy en día, fue la invención a finales de la década de 1880 de las tarjetas perforadas como soporte de almacenamiento de información. Esta nueva idea llegó de la mano de Herman Hollerith (1860-1929). Hollertih era un inventor y estadístico norteamericano y se dice que desarrolló su idea al observar a los revisores del ferrocarril codificar características de los viajeros, marcando con agujeros sus billetes.

Para poder trabajar con las tarjetas, diseño y construyó dos máquinas, la tabuladora, y la perforadora. Estas máquinas utilizaban ya sistemas electromecánicos (relés y solenoides) para ir incrementando contadores mecánicos. La construcción de las máquinas ya fue realizada bajo la tutela de la oficina del censo de Estados Unidos que vio su potencial muy pronto. Su éxito se pudo calibrar en 1890, cuando mediante estas máquinas se realizó el censo en solo un año (el censo anterior, el de 1880 tardó 8 años en ser completado). Esto hizo que Hollerith decidiera fundar su propia empresa, la Tabulating Machine Company en 1896 para explotar el invento, y vaya si lo hizo.

Continuó mejorando el sistema (y ganando dinero) vendiendo sus máquinas para el censo de otros países como Inglaterra, Alemania, Italia, Francia, Noruega, Rusia… El sistema era abiertamente un éxito y allá por el año 1911, la compañía de Hollertih se unió con otras 2, la International Time Recording Company (1900) y la Computing Scale Company (1901). La nueva compañía se llamó Computing Tabulating Recording (CTR) Company.

CTR

Probablemente no te suene de nada, pero si te digo que 13 años más tarde, en 1924 se cambió el nombre por el de la International Business Machines (IBM), quizás ya te suene un poco más.

IBM

Así las cosas, entramos en el siglo XX con una empresa de éxito en el campo de las máquinas de calcular, y que se ha desarrollado una tecnología para la “programación” (proto-programación, claro está) de las mismas. Por estas fechas ya viene el periodo de guerras donde como veremos en el próximo artículo, la cosa se aceleró bastante, y es que lamentablemente la historia de la informática tiene mucho que ver con las guerras.

Hasta la próxima entrada.

Patrones de diseño I – Introducción

Recientemente, un compañero de trabajo nos ha realizado una workshop acerca de diseño por capas y patrones, al que hemos asistido un grupo de 7 desarrolladores. Se han comentado bastantes cosas que desconocía pero en líneas generales eran ideas muy genéricas que está bien refrescar. En cualquier caso, me ha sorprendido enormemente que gran parte de los compañeros ni tan siquiera habían oído hablar de patrones de diseño de software. Cierto es que no somos una empresa dedicada al desarrollo como tal, pero aún así me sorprende que ni tan siquiera se hubiera oído acerca de su existencia.

Es por esto que me he decidido a escribir una serie de entradas acerca de patrones de diseño de software. Mi objetivo es publicar los patrones de diseño más habituales explicando los casos en los que puede ser útil su uso, apoyándome en ejemplos.

En primer lugar, la pregunta: ¿que es un patrón de diseño (dessign pattern)? Los patrones son soluciones a problemas comunes en el diseño de software, que ya han sido resueltos por otros programadores anteriormente (habitualmente más sabios) y en los que nos podemos apoyar a la hora de afrontar problemas similares.

Conocer estos patrones puede ayudar a los desarrolladores dado que facilita el aprendizaje y constituye una herramienta muy útil para estandarizar el modo de afrontar este tipo de retos. Los patrones de diseño se suelen clasificar en tres categorías: patrones de creación, patrones de estructura y patrones de comportamiento.

Vamos a comenzar viendo los patrones de creación. Los patrones de creación son planteamientos acerca del modo de construir nuevos objetos en la aplicación. Los más conocidos que se engloban en esta categoría son los siguientes:

  • Abstract factory
  • Factory method
  • Singleton
  • Prototype
  • Builder

Los patrones de estructura se postulan como soluciones para estructurar las clases. Los que se suelen incluir en esta categoría son:

  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Facade
  • Flyweight
  • Proxy

Por último los patrones de comportamiento se centran en resolver problemas relacionados con el comportamiento del software. En esta última categoría se engloba:

  • Chain of responsibility
  • Command
  • Interpreter
  • Iterator
  • Mediator
  • Memento
  • Observer
  • State
  • Strategy
  • Template method
  • Visitor

En los próximos días, publicaré el primer post acerca de patrones de creación. Espero que os sea útil.

Hasta pronto

Historia informática I – De Pascal a Babbage

Este será el primero de una serie de artículos destinados a ofrecer una visión global, sin profundizar en exceso, de la increíble y no menos afortunada historia de la informática. Este campo tiene la ventaja de ser relativamente nuevo, ya que allá por el siglo XVII todavía no se tenía ni la más remota idea de porqué alguien iba a necesitar una “calculadora” en su casa (hasta 1960 se seguía pensando lo mismo), pero el recorrido es realmente divertido y da ha dado para más de una película.

En este primer artículo, hablaremos de la prehistoria informática. Como se llegó al que es hoy considerado el primer ordenador mecánico es una historia que empieza en los orígenes de la humanidad. Desde la prehistoria, el ser humano ha tratado de desarrollar herramientas que le ayuden a realizar tareas. Y desde que existen las herramientas, se ha tratado de desarrollar máquinas que ayuden a realizar las tareas más tediosas, y el cálculo desde luego es una de ellas.

Antes de Pascal (1623-1662), existían máquinas capaces de realizar cálculos concretos sobre algún campo (conteo de pasos, cálculo astronómico, cálculos de navegación, cálculo temporal…) pero el señor Pascal no estaba contento con esto ya que era matemático, y él quería realizar cálculos matemáticos genéricos. Así que ni corto ni perezoso se puso a diseñar una máquina capaz de realizar sumas y restas allá por 1642, la Pascaline (pascalina en castellano). No es necesaria una de sus máquinas para restar 1642 con el año de nacimiento que he puesto arriba (1623) y darse cuenta de que lo hizo con ¡19 años! Aunque no pudo construirla hasta tres años más tarde en 1645. En el enlace se puede observar su primitivo (pero original), planteamiento.

Casi portátil Fuente: wikimedia.org

Entre 1645 y 1655 no perdió el tiempo y construyó 20 de estas y a día de hoy sobreviven 9. El diseño era muy simple, mediante unos engranajes accionados por las ruletas que se pueden ver en la foto, se iban acumulando cantidades, y cuando en una ruleta se llegaba al cero de nuevo, la siguiente giraba para poner un uno. Así sucesivamente. En el siguiente enlace se puede ver un simulador de funcionamiento (requiere Flash Player en el navegador).

Por ese tiempo nacía en Leipzig (Alemania) un señor llamado Leibniz (1646-1716). Y aunque obviamente esta máquina es una maravilla para su época (además de una preciosidad), sus opciones se te pueden antojar escasas, sobre todo si eres uno de los dos co-inventores del cálculo infinitesimal. Así que empezó diseñando una máquina que interactuara directamente con la pascalina para ejecutar multiplicaciones y divisiones como sumas y restas sucesivas, pero la máquina de Pascal se le quedaba corta para sus propósitos por lo que acabó rediseñando una máquina nueva por completo en 1674: la Stepped Reckoner.

Para ello rediseñó los engranajes utilizando ruedas de Leibniz (también inventadas por él, obviamente) y terminó de fabricar la primera en 1686. Como él mismo decía al describir su máquina, se trata de realizar cálculos: “leicht, geschwind, gewiß” (fácil, rápido y seguro). También le pertenece la cita siguiente:

Es indigno de hombres excelentes perder horas como esclavos en el trabajo de cálculo que con seguridad podría ser relegado a alguien más si se utilizan máquinas.

Esta imagen es tan bonita porque es una réplica. No es la máquina original Fuente: wikimedia.org

El siglo XVII terminó en lo que a nuestro artículo se refiere, creando modelos que mejoraban o modificaban los de Pascal o Leibniz, pero no realizaban ninguna función adicional. Y es que lo que faltaba para poder automatizar estas operaciones era la gestión del tiempo. Introducir el preciso mecanismo de un reloj en una máquina de estas características se antojaba como algo realmente complicado para la época aunque hubo intentos muy dignos que a punto estuvieron de conseguirlo.

El siglo XVIII fue un siglo de mejoras en los diseños y ya en 1709, el primero en poder realizar una máquina con reloj fue el italiano Giovanni Poleni (1683-1761). En 1727 Antonius Braun regaló al emperador de Viena un modelo que integraba las cuatro operaciones y utilizaba el diseño de Poleni con reloj. Esto motivó que el propio Poleni destruyera su invento. Pero como digo, se trataba de mejoras sobre las máquinas originales del siglo anterior. ¿Que podía hacer más una máquina a parte de operaciones básicas? La respuesta no llegó hasta 1786 en que el ingeniero alemán Johann Helfrich von Müller (1746-1830) publicó el diseño de una máquina diferencial.

Ya en el siglo XIX, concretamente en 1822 un tal Charles Babbage (1791-1871) trabajó en un diseño similar al de von Müller. Su máquina era capaz de obtener series de resultados de funciones polinómicas en base a sucesiones aritméticas. De hecho la máquina devolvía las funciones en formato tabulado y utilizaba para ello el método de las diferencias finitas.

Reproducción de lo que hubiera sido la máquina de Babbage Fuente: wikimedia.org

Babbage, que había ingresado en el Trinity College de Cambridge consiguió atraer el interés del gobierno británico que invirtió más de £17,000 en el proyecto, aunque nunca obtuvo una máquina funcional, lo cual mató la financiación y por extensión, el proyecto. Esto se debió entre otras cosas, a que mientras diseñaba la máquina diferencial, Babbage se dio cuenta de que podía dar un paso más en el diseño de su máquina. El interés de Babbage iba mucho más allá de una máquina capaz de realizar cálculos predeterminados. Él buscaba construir una máquina analítica.

Hasta ahora, hemos estado comentado ingenios mecánicos más o menos complejos pero que han sido diseñados para realizar una u otra operación concreta. Sumas y restas, multiplicaciones y divisiones, solución de funciones polinómicas,… Lo que planteaba Babbage era distinto e introducía conceptos que hoy se siguen utilizando. Buscaba una máquina que no tuviera un propósito concreto (propósito general), donde la máquina realizara lo que un operador le dijera (programación). Basándose en la programación del telar programable de Joseph Marie Jacquard (1752-1834), decidió utilizar en su diseño el sistema de tarjetas perforadas. Sistema que se utilizó hasta el principio del siglo XX.

Visto desde el punto de vista de hoy nos podrá parecer un visionario, pero en aquella época no se le veía sentido a esa idea por lo que le fue imposible encontrar fondos para financiar su construcción, que nunca llegó a realizarse.

Existe cierta controversia acerca de si Ada Lovelace(1815-1852) diseño o no el primer programa para la máquina analítica (un algoritmo para obtener la secuencia de los números de Bernoulli) aunque en efecto, se le suele atribuir el logro. Lo que desde luego sí hizo fue traducir, completar e incluso corregir las famosas notas “Sketch of the Analytical Engine” de Federico Luigi, Conde de Menabrea.

La máquina de Babbage (la diferencial, no la analítica) fue construida en 1843 por Per Georg Scheutz (1785-1873) y su hijo Edward, y fue vendida a los gobiernos tanto británcio como americano siendo utilizadas con éxito en la producción de tablas logarítmicas. La máquina analítica en cambio nunca fue construida, aunque Henry, el hijo de Babbage reportó en 1910 haber construido una parte de la máquina (no programable y sin almacenamiento) y haber calculado una serie de decimales de pi (aunque parece ser que contenía errores).

Como dije al inicio del post esto es la prehistoria de la informática, y con ella cerramos este artículo para adentrarnos en el próximo en el siglo XX que es el que marcó el devenir de los acontecimientos de esta nueva disciplina.

Mantenibilidad en proyectos

Esta semana, me he visto obligado a trabajar en uno de esos proyectos zombie, donde da igual las veces que acabes con ellos porque siempre vuelven para perseguirte. En algunos casos como el que me ocupa hoy, el código es ajeno y no puedo contactar con el ***** que lo engendró. Y es que existe una práctica muy común en las ingenierías (sobretodo en empresas pequeñas) donde se tiende a subestimar los recursos necesarios para llevar a cabo un proyecto (en muchas ocasiones esta sub-estimación es forzosa, claro), pero a medida que la empresa crece, las malas costumbres suelen persistir.

El caso es que lidiar con ese código infame me ha permitido recordar ciertas rutinas consideradas “buenas prácticas” en la universidad, pero que yo considero reglas inquebrantables cuando nos movemos en entornos más profesionales.

Leyes de la mantenibilidad de código:

  1. Comentar sí, pero sin pasarse. Citando a Steve McConnell (autor de grandes biblias como  “Code Complete”) “Good code is its own best documentation. As you’re about to add a comment, ask yourself, ‘How can I improve the code so that this comment isn’t needed?’”
  2. Modularidad. Si un método, función o rutina se va a alargar tanto que se puede perder el hilo al leerla, es buena idea separarla en varias. En general, no se me ocurren casos donde un método deba ocupar más de 200 líneas. Aumentar la modularidad, ayuda también a cumplir la siguiente regla.
  3. Límite de parámetros. No generar rutinas donde la cabecera sea ilegible. Algunos autores afirma que 7 debería de ser el número máximo de parámetros por el límite a la capacidad cognitiva que enunció Miller (1956).
  4. Tamaño de línea. Se considera que superar la longitud de 80 columnas por fila es una falta de estilo. Esto es debido a que 80 son las columnas que caben en un folio impreso. Además, facilita la lectura.
  5. Notificación al usuario. Cuando se notifique de algún error, o evento de traza para debug, se debe aportar la información justa y en ningún caso alarmar al usuario. Caso de estudio la BSOD de Microsoft.
  6. Tiempos de vida cortos. Las variables se declaran cuando van a utilizarse, y se destruyen lo antes posible. De forma que su ciclo de vida sea lo más corto (en líneas de código) posible. Nada de declarar al inicio del programa todas las variables necesarias.
  7. Excepciones. Catch vacío es mal. Distintos catches para distintas excepciones dentro del mismo try es bien.
  8. Análisis. Dedicar tiempo de análisis al inicio puede ahorrar muchas horas después. Es bueno diseñar el software con todas las armas que nos dé el lenguaje concreto para evitar pérdidas de tiempo más adelante. Desglose en clases (en POO), funciones, rutinas…
  9. No abusar de las líneas en blanco. Un número de líneas en blanco elevado (mayor al 10-20% del código) es absolutamente contraproducente. Dificulta la lectura y reduce la cohesión del código.
  10. Documentación. Quizás la parte más importante. Se suele aceptar como motivo de aplauso y regocijo general encontrar un software con documentación, tanto generada automáticamente (como doxygen, por ejemplo) como redactada por el propio programador (manuales, tutoriales, guías, screenshots …). El hecho de utilizar herramientas para documentar ya hace que se deba seguir cierto protocolo en los comentarios (Javadoc, por ejemplo), lo que enriquece el estilo. Escuchar que tal proyecto no necesita documentación (sea cual sea la excusa) es razón suficiente para abandonar una conversación.

Bueno, esto es lo que para mí (y muchos otros autores) es fundamental a la hora de desarrollar algo que el simple hecho de contemplarlo no produzca una sensación de querer matar morir. Me despido con una cita muy acorde con el tema:

“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.”
– Martin Golding

Voy a seguir a mi tarea de mantener este engendro. Entre tanto, puede que me sirva de ayuda un poco de relajación. Os paso el link que voy a utilizar para ello.

Enlaces:

Gestión del tiempo en el desarrollo de videojuegos

Leo en CyberHades que ya hace un año de la reaparición del código fuente del Prince of Persia por parte de Jordan Mechner, que fue el videojuego que me hizo tocar por primera vez un ordenador :cry:. Esto de por sí ya merece una serie de entradas, tanto el juego y su desarrollo (no prometo poder resistirme a escribir sobre él en el futuro) como la odisea de la recuperación posterior de dicho código de formatos físicos maltratados por el tiempo (traducción más o menos libre de éste artículo de wired).

El motivo de esta entrada, es porque leo que el gran Fabien Sanglard ha publicado las tres primeras partes de una de sus clásicas reviews de código de Prince of Persia. Para quien no lo conozca, Sanglard es un tipo que gusta de leer el código fuente de videojuegos clásicos antes de almorzar. Lecturas muy recomendables que merecen otro post.

Esto me ha hecho volver a leer algunos de sus fantásticos posts, entre los cuales he dado con uno que me gustaría comentar, más que nada porque cuando desarrollas videojuegos (a cualquier nivel) antes o después vas a topar con este problema, la gestión del tiempo en el bucle principal.

Es habitual, sobretodo entre los clásicos (yo siempre lo he hecho así) utilizar el paradigma de actualización siguiente:

  1. Obtener el lapso de tiempo entre la última actualización del juego y el momento actual
  2. Actualizar el mundo en función de ese valor y el valor de las entradas
  3. Renderizar (pintar) el mundo

Sirva como ejemplo el bucle principal de Quake (1996, idSoftware):

WinMain
{
	while (1)
	{
		newtime = Sys_DoubleTime ();
		time = newtime - oldtime;
		Host_Frame (time)
		{
			setjmp
			Sys_SendKeyEvents
			IN_Commands
			Cbuf_Execute
			/* Network */
			CL_ReadPackets
			CL_SendCmd
			/* Prediction//Collision */
			CL_SetUpPlayerPrediction(false)
			CL_PredictMove
			CL_SetUpPlayerPrediction(true)
			CL_EmitEntities
			/* Rendition */
			SCR_UpdateScreen
		}
		oldtime = newtime;
	}
}

Como vemos, se obtiene el tiempo actual del sistema, y se obtiene la diferencia con el momento de actualización anterior. En función de eso se actualiza el estado del juego. Como digo, es la forma habitual de hacerlo y habitualmente funciona a la perfección, pero en algunos casos introduce una problemática adicional. ¿Que ocurre si ese lapso de tiempo se agranda?

Actualización temporal en videojuegos (Imagen de Fabien Sanglard)

Si el tiempo de actualización se hace más grande, significa que ocurrirán más cosas en el juego que nosotros tardaremos en saber. Si este efecto se lleva al extremo, podemos llegar a perder cosas importantes como la detección de colisiones. Un ejemplo:

Progresión de movimiento en una colisión (Imagen Fabien Sanglard)

En este ejemplo, si hacemos una actualización en el instante 0, y el tiempo de actualización se demora 12 o más milisegundos no habríamos detectado la colisión de los objetos A y B, por lo que el usuario habría visto que ambos objetos se atraviesan.

El problema en realidad no es que se alargue o no el tiempo de actualización, sino su variabilidad. Existen algoritmos que solucionan el problema, uno sencillo podría ser utilizar lapsos de tiempo constantes para actualizar.

int gameOn = 1
int simulationTime = 0;

while (1){

int realTime = Gettime();

while (simulationTime < realTime){ simulationTime += 16; //Timeslice is ALWAYS 16ms. UpdateWorld(16); } RenderWorld(); } [/code] [caption id="" align="aligncenter" width="619"] Actualización en periodos constantes (Imagen Fabien Sanglard)[/caption]

Como vemos, de este modo separamos lo que es la actualización del renderizado. Pudiendo detectar situaciones que de otro modo se nos escaparían. Este paradigma es el que se utiliza en la industria del videojuego actual.

Así que como dice el señor Sanglard:

No website is as good as a good book. And no good book is as good as a disassembly output.

Por lo que os enlazo un blog y un libro sobre el tema:

Salud!

New look & feel !

Hola,

dado el poco tiempo del que dispongo, se me hace imposible mantener mi propio gestor de contenido, por lo que voy a migrar a WordPress. Espero que el cambio me haga la vida un poco más fácil, y de paso me permita tener un poco más actualizado esto 😉

Un Saludo