martes, 13 de junio de 2017

¿Cuál es el error de programación más difícil que has tenido que resolver?



Hola estimados lectores, hace unos días en Quora me encontré con una pregunta interesante, y al entrar a leer las respuestas me encontré una respuesta que considero motivante para todos aquellos que estamos inmersos en el área del desarrollo de software. A continuación traduzco la respuesta de Dave Bagget un talentoso programador y emprendedor. Como dato interesante, hace unos meses Google compró por 700 millones de dólares una de las empresas que Dave fundó. Los dejo con la traducción.

Es un poco doloroso revivir esto. Como programador aprendes a culpar en primer lugar a tu código, en segundo también y en tercero también... y en algún momento al rededor del lugar número diez mil, culpas al compilador. Y sólo hasta el final de las lista, culpas al hardware.


Esta es mi historia de un error de hardware.


Entre otras cosas, escribí el código (para cargar y guardar) de la tarjeta de memoria para el juego Crash Bandicoot. Para un fanfarrón programador de videojuegos, esto es como dar un paseo por el parque; yo esperaba que ese trabajo me tomara unos pocos días. Terminé depurando el código por seis semanas. Hice otras cosas durante ese tiempo, pero seguía volviendo a ese error--unas pocas horas cada pocos días. Era agonizante.


El síntoma era que cuando ibas a guardar tu progreso se accedía a la tarjeta de memoria, y casi todo el tiempo, funcionaba normalmente... Pero de vez en cuando, la escritura o la lectura se detenían... sin razón aparente. Un escritura corta podría a menudo corromper la tarjeta de memoria. El jugador podría intentar guardar, y no solamente no podríamos guardar su partida, sino que borraríamos su tarjeta de memoria. D'oH.


Después de un tiempo, nuestro productor en Sony, Connie Both, comenzó a entrar en pánico. Obviamente no podíamos enviar el juego con ese error, y después de seis semanas yo aun no tenía pistas de qué ocasionaba el problema. Vía Connie dimos a conocer la noticia a otros desarrolladores de PlayStation -- ¿alguien ha visto algo parecido? Nop. Absolutamente nadie tuvo problemas con el sistema de tarjeta de memoria.


La única cosa que puedes hacer cuando te quedas sin ideas depurando código es

'dividir y vencer': continuar removiendo más y más código del programa erróneo hasta que te quedas con algo relativamente pequeño que exhiba el problema. Continuas removiendo partes hasta que el único elemento que queda es aquella donde el error se encuentra.

El reto con este nuevo contexto, por así decirlo, es que en un videojuego es muy difícil remover piezas. ¿Cómo mantienes el juego en ejecución si removiste el código que simula la gravedad en el juego? o el que renderiza los personajes.


Lo que tienes que hacer es reemplazar modulos enteros con trozos que pretendan hacer lo que hace el código verdadero, pero que en realidad hacen algo completamente trivial que no puede tener errores. Luego, tienes que escribir código escalafonado solamente para que las cosas vayan funcionando bien. Es un proceso lento y doloroso.


Acortando la historia: Hice eso. Estuve removiendo más y más partes de código hasta finalizar, hasta quedar casi con nada más que solamente el código de arranque -- sólo el código que prepara el sistema para ejecutar el juego, inicializa el hardware de renderizado, etc. Por supuesto, en este punto yo no podía poner el menú de cargar/guardar porque me había desecho todos los códigos para gráficos. Pero podría fingir que el usuario utilizaba una invisible pantalla de cargar/guardar y preguntar para guardar, entonces escribir en la tarjeta


Por último terminé con una cantidad muy pequeña de código que exhibía el problema -- pero aleatoriamente. La mayor parte del tiempo, podría trabajar, pero de vez en cuando, podría fallar. Casi todo del código actual de Crash Bandicoot ha sido removido, pero el error seguía sucediendo. Esto era realmente desconcertante: el código que quedaba realmente no estaba haciendo nada.


En algún momento -- probablemente a las 3 am -- un pensamiento llegó a mi mente. La lectura y escritura (I/O) involucra un tiempo preciso. Si has trabajado a fondo con un disco duro, una memoria flash o un transmisor de Bluetooth -- lo que sea -- el código de bajo nivel que lee y escribe tiene que hacer algo de acuerdo a un reloj.


El reloj permite que el dispositivo -- el cual no está directamente conectado al CPU -- se mantenga en sincronía con el código que el CPU está ejecutando. El reloj determina la tasa de baudios -- la tasa a la cual los datos son enviados de un lado a otro. Si el tiempo se descontrola, el hardware o el software -- o ambos -- se confunden. Esto es muy, muy malo en verdad, y por lo regular resulta en una corrupción de los datos.


¿Qué tal si algo en nuestro código de configuración estaba estropeando el tiempo de algún modo? Miré el código una vez en el programa de prueba que había reescrito en busca de algo relacionado con el código, y noté que configuramos el temporizador programable del PlaySatation 1 en 1kHz (1000 ticks por segundo). Esto es relativamente rápido; cuando el Plasy Station 1 arrancó estaba corriendo en algo como 100 Hz que es su estado por default. La mayoría de los juegos, por lo tanto, deberían tener este temporizador ejecutando a 100 Hz.

Andy,  el desarrollador líder del juego, colocó el temporizador a 1 kHz para que los cálculos de movimiento en Crash Bandicoot fueran más precisos. Andy es muy excesivo, y si íbamos a simular la gravedad ¡debíamos hacerlo con la mayor precisión posible!

Pero qué tal si al incrementar este temporizador de algún modo se interfería con el tiempo total del programa, y por lo tanto con el reloj utilizado para establecer la tasa de baudios de la tarjeta de memoria.

Comenté el código del temporizador. No podía hacer que el error se repitiera de nuevo. Pero esto no significaba que el problema estuviera resuelto; el problema sólo sucedía aleatoriamente. ¿Qué tal si solamente estaba teniendo suerte?

Conforme pasaban los días, seguía jugando con mi programa de prueba. El error no se presentó de nuevo. Regresé al código base completo de Crash Bandicoot, y modifiqué el código de cargar/guardar para restablecer el temporizador programable a su configuración inicial de 100 Hz antes de acceder a la tarjeta de memoria. Posteriormente se volvía a establecer en 1 kHz. Nunca vimos los problemas de lectura/escritura de nuevo.

¿Pero por qué?

Volví varías veces al programa de prueba tratando de detectar algún patrón en los errores que ocurrían cuando el temporizador estaba configurado a 1kHz. Eventualmente, me dí cuenta que los errores ocurrían cuando alguien estaba jugando con el control del PlayStation 1. Debido a que raramente hago eso (¿por qué jugaría con el control cuando probaba el código de cargar/guardar?) no me percaté de ese detalle. Pero un día uno de los artistas estaba esperando a que yo terminara una prueba-- estoy seguro de que en ese momento yo estaba maldiciendo -- y él estaba jugueteando nerviosamente con el control. Hubo uno falla. "Espera, ¿qué? ¡Hey, haz eso de nuevo!".

Una vez que tenía la idea que las dos cosas estaban relacionadas, fue fácil de reproducir: iniciar escribiendo en la tarjeta de memoria, se manipula el control, se daña la tarjeta de memoria. Estaba seguro que se trataba de un problema de hardware.

Regresé con Connie y le comenté lo que había encontrado. Ella transmitió esto a uno de los ingenieros de hardware que habían diseñado el PlayStation 1. "Imposible", le dijeron. "No puede ser un problema de hardware". Le dije a ella que preguntara si yo podía hablar con él.

Él me llamó a mí y, en su inglés roto y en mi (extremadamente) japones roto, discutimos. Finalmente dije, "sólo déjeme enviarle un programa de prueba de 30 líneas de código que ejecuta lo que sucede cuando se manipula el control." Él cedió. Me aseguró que podría ser una perdida de tiempo y que estaba extremadamente ocupado con un nuevo proyecto, pero estaba obligado porque nosotros eramos un importante desarrollador para Sony. Limpie mi pequeño programa de prueba y se lo envié.

La noche siguiente (nosotros estábamos en Los Ángeles y él en Tokio) me llamó y se disculpó tímidamente. Era un problema de hardware.

No tuve muy en claro sobre qué era lo que en realidad ocasionaba el problema, pero mi impresión según lo que escuche de Sony era que ajustando el temporizador programable a una tasa suficientemente alta en el reloj podría interferir con cosas en la tarjeta madre cerca del cristal del temporizador. Una de esas era el controlador de la tasa de baudios para la tarjeta de memoria, el cual también configuraba la tasa de baudios para los controladores. No soy un chico del hardware, así es que estoy muy confuso en cuanto a los detalles.

Pero la esencia de eso fue la relación entre las partes individuales de la tarjeta madre, y la combinación de enviar datos entre puerto del controlador y el puerto de la tarjeta de memoria mientras el temporizador se está ejecutando a 1kHz podría causar que los bits se desbordaran... y los datos se perdieran... y la tarjeta se dañara.

Ese fue el único momento en toda mi vida como programador que he resuelto un problema causado por la mecánica cuántica.



Popular Posts

Recent Posts

Unordered List

Text Widget

Blog Archive

Scroll To Top