Como dicen, si no te avergüenzas de tu antiguo código, entonces no creces como programador, y estoy de acuerdo con esta opinión. Comencé a programar para el entretenimiento hace más de 40 años, y hace 30 años profesionalmente, así que tuve
muchos errores. Como profesor de informática, les enseño a mis alumnos a aprender de los errores: los suyos, los míos, los extraños. Creo que es hora de hablar sobre mis errores para no perder la modestia. Espero que alguien lo encuentre útil.
Tercer lugar: compilador de Microsoft C
Mi maestra de escuela creía que "Romeo y Julieta" no puede considerarse una tragedia, porque los héroes no tenían una culpa trágica, simplemente se comportaron estúpidamente, como deberían hacerlo los adolescentes. Entonces no estaba de acuerdo con él, pero ahora veo en su opinión un núcleo racional, especialmente en relación con la programación.
Cuando terminé mi segundo año en el MIT, era joven e inexperto, tanto en la vida como en la programación. En el verano, practiqué en Microsoft, en el equipo del compilador de C. Al principio, me involucré en una rutina como el soporte de creación de perfiles, y luego me encargaron el trabajo en la parte más divertida (como pensaba) del compilador: la optimización del backend. En particular, tuve que mejorar el código x86 para las declaraciones de ramificación.
Decidida a escribir el código de máquina óptimo para cada caso posible, me apresuré a la piscina con la cabeza. Si la densidad de distribución de valores era alta, los ingresaba en la
tabla de transición . Si tenían un divisor común, lo usaba para hacer la tabla más densa (pero solo si la división se podía hacer usando un
poco de desplazamiento ). Cuando todos los valores eran potencias de dos, realicé otra optimización. Si el conjunto de valores no satisfacía mis condiciones, lo dividí en varios casos optimizables y usé el código ya optimizado.
Fue una pesadilla. Después de muchos años, me dijeron que el programador que heredó mi código me odiaba.
Leccion aprendida
Como David Patterson y John Hennessy escriben en el libro Computer Architecture and Computer Systems Design, uno de los principios fundamentales de la arquitectura y el desarrollo es que, en general, todo funciona lo más rápido posible.
La aceleración de casos comunes aumentará la productividad de manera más eficiente que la optimización de casos raros. Irónicamente, los casos comunes son a menudo más simples que raros. Este consejo lógico implica que usted sabe qué caso considerar común, y esto solo es posible a través de pruebas y mediciones cuidadosas.
En mi defensa, puedo decir que traté de averiguar cómo se veían los operadores de sucursales en la práctica (por ejemplo, cuántas ramas existían y cómo se distribuían las constantes), pero en 1988 esta información no estaba disponible. Sin embargo, no debería haber agregado casos especiales siempre que el compilador actual no pudiera generar el código óptimo para el ejemplo artificial que se me ocurrió.
Necesitaba llamar a un desarrollador experimentado y con él para pensar cuáles eran los casos comunes y tratar específicamente con ellos. Escribiría menos código, pero eso es bueno. Como escribió el fundador de Stack Overflow, Jeff Atwood, el peor enemigo del programador es el programador:
Sé que tienes las mejores intenciones, como todos tenemos. Creamos programas y nos encanta escribir código. Entonces estamos dispuestos. Creemos que cualquier problema puede resolverse con cinta, una muleta casera y una pizca de código. No importa cuán doloroso sea para los codificadores admitir esto, el mejor código es ese código que no existe. Cada nueva línea necesita depuración y soporte, debe entenderse. Al agregar un nuevo código, debe hacerlo con reticencia y disgusto, porque todas las demás opciones se han agotado. Muchos programadores escriben demasiado código, convirtiéndolo en nuestro enemigo.
Si escribiera un código más simple que cubriera casos comunes, entonces sería mucho más fácil actualizar si fuera necesario. Dejé un desastre con el que nadie quería meterse.
Segundo lugar: publicidad en redes sociales
Cuando trabajé en Google en publicidad en redes sociales (¿recuerdas Myspace?), Escribí en C ++ algo como esto:
for (int i = 0; i < user->interests->length(); i++) { for (int j = 0; j < user->interests(i)->keywords.length(); j++) { keywords->add(user->interests(i)->keywords(i)) { } }
Los programadores pueden ver inmediatamente el error: el último argumento debe ser j, no i. Las pruebas unitarias no revelaron un error, ni mi revisor lo notó. Se realizó un lanzamiento, y una noche mi código fue al servidor y bloqueó todas las computadoras en el centro de datos.
Nada terrible sucedió. Ninguno de ellos se rompió, porque antes del lanzamiento global, el código se probó dentro del mismo centro de datos. A menos que los ingenieros de SRE dejen de jugar al billar por un corto tiempo e hicieron una pequeña reversión. A la mañana siguiente recibí un correo electrónico con un volcado de memoria, arreglé el código y agregué pruebas unitarias que revelarían un error. Como seguí el protocolo, de lo contrario, mi código simplemente no se hubiera ejecutado, no hubo otros problemas.
Leccion aprendida
Muchos están convencidos de que un error tan importante es necesariamente el culpable del despido, pero esto no es así: en primer lugar, todos los programadores están equivocados y, en segundo lugar, rara vez cometen un error dos veces.
De hecho, tengo un programador familiar, un ingeniero brillante, que fue despedido por un solo error. Después de eso, fue contratado por Google (y pronto promovido): honestamente habló sobre el error cometido en la entrevista, y ella no fue considerada fatal.
Esto es lo que Thomas Watson, el legendario jefe de IBM, tiene que decir:
Se anunció una orden del gobierno por un millón de dólares. IBM Corporation, o mejor dicho, personalmente, Thomas Watson Sr., realmente quería conseguirlo. Desafortunadamente, el representante de ventas no pudo hacer esto, e IBM perdió la licitación. Al día siguiente, este oficial llegó a la oficina del Sr. Watson y puso un sobre en su escritorio. El Sr. Watson ni siquiera lo miró: estaba esperando a un empleado y sabía que era una carta de renuncia.
Watson preguntó qué salió mal.
El representante de ventas describió en detalle el progreso de la licitación. Llamó a los errores que podrían haberse evitado. Finalmente, dijo: “Sr. Watson, gracias por dejarme explicar. Sé cuánto necesitábamos este pedido. Sé lo importante que era ”, y estaba a punto de irse.
Watson se le acercó a la puerta, lo miró a los ojos y le devolvió el sobre con las palabras: “¿Cómo puedo dejarte ir? Acabo de invertir un millón de dólares en tu educación.
Tengo una camiseta que dice: "Si realmente aprendes de los errores, entonces ya soy un maestro". De hecho, en lo que respecta a los errores, soy Doctor en Ciencias.
Primer lugar: API de App Inventor
Los errores verdaderamente aterradores afectan a una gran cantidad de usuarios, se hacen públicos, se arreglan por mucho tiempo y son cometidos por aquellos que no pueden permitirlos. Mi mayor error satisface todos estos criterios.
Cuanto peor, mejor
Leí el
ensayo de Richard Gabriel sobre este enfoque en los años noventa como estudiante de posgrado, y me gusta tanto que se lo pido a mis alumnos. Si no lo recuerda bien, actualice su memoria, es pequeño. En este ensayo, el deseo de "hacerlo bien" y el enfoque "cuanto peor, mejor" se contrastan de muchas maneras, incluida la simplicidad.
Como debería: el diseño debe ser fácil de implementar e interactuar. La simplicidad de la interfaz es más importante que la simplicidad de implementación.
Lo peor, lo mejor: el diseño debe ser simple en implementación e interfaz. La simplicidad de implementación es más importante que la simplicidad de la interfaz.
Olvídalo por un momento. Desafortunadamente, lo olvidé por muchos años.
Inventor de aplicaciones
Mientras estaba en Google, formé parte del equipo de
App Inventor , un entorno de desarrollo en línea con soporte de arrastrar y soltar para desarrolladores principiantes de Android. Era 2009, y teníamos prisa por lanzar la versión alfa a tiempo, para que en el verano pudiéramos impartir clases magistrales para maestros que pudieran usar el ambiente de aprendizaje en el otoño. Me ofrecí para implementar sprites, nostálgico de cómo solía escribir juegos en TI-99/4. Para aquellos que no están al tanto: un sprite es un objeto gráfico bidimensional que puede moverse e interactuar con otros elementos del programa. Ejemplos de sprites son naves espaciales, asteroides, pelotas y raquetas.
Implementamos el Inventor de aplicaciones orientado a objetos en Java, por lo que solo hay un montón de objetos. Como las bolas y los sprites se comportan de manera muy similar, creé una clase de sprites abstracta con propiedades (campos) X, Y, Velocidad (velocidad) y Encabezado (dirección). Tenían los mismos métodos para detectar colisiones, rebotar en el borde de la pantalla, etc.
La principal diferencia entre la pelota y el sprite es exactamente lo que se dibuja: un círculo o trama lleno. Desde que implementé los sprites por primera vez, era lógico especificar las coordenadas x e y de la esquina superior izquierda del lugar donde se encontraba la imagen.
Cuando los sprites comenzaron a funcionar, decidí que podías implementar objetos de bola con muy poco código. El único problema fue que tomé el camino más simple (desde el punto de vista del implementador), indicando las coordenadas x e y de la esquina superior izquierda del contorno que rodea la bola.
De hecho, era necesario indicar las coordenadas x e y del centro del círculo, como lo enseña cualquier libro de texto de matemáticas y cualquier otra fuente que mencione círculos.
A diferencia de mis errores pasados, no solo mis colegas, sino también millones de usuarios de App Inventor sufrieron esto. Muchos de ellos eran niños o completamente nuevos en la programación. Tuvieron que realizar muchas acciones innecesarias cuando trabajaban en cada aplicación en la que la pelota estaba presente. Si recuerdo el resto de mis errores con una sonrisa, entonces esto me pone a sudar hoy.
Finalmente parcheé este error solo recientemente, diez años después. "Parcheado", pero no "arreglado", porque como dice Joshua Bloch, las API son eternas. Al no poder realizar cambios que afectarían a los programas existentes, agregamos la propiedad OriginAtCenter con falso en los programas antiguos y verdadero en todos los futuros. Los usuarios pueden hacer una pregunta legítima a quién se le ocurrió a cualquiera localizar un punto de referencia en otro lugar que no sea el centro. A quien? Un programador que era demasiado vago para crear una API normal hace diez años.
Lecciones aprendidas
Cuando trabaje en una API (que casi todos los programadores a veces tienen que hacer), debe seguir los mejores consejos descritos en el video de Joshua Bloch "
Cómo crear una buena API y por qué es tan importante " o
en esta breve lista :
- La API puede ser de gran beneficio para usted, así como un gran daño . Una buena API crea clientes leales. Lo malo se convierte en tu eterna pesadilla.
- Las API públicas, como los diamantes, son eternas . Haz tu mejor esfuerzo: no hay otra oportunidad de hacer todo como debería.
- Los horarios para la API deben ser cortos : una página con firmas de clase y método y descripciones que no requieren más de una línea. Esto le permitirá reestructurar fácilmente la API, si la primera vez que sale no es perfecta.
- Describa los escenarios de uso antes de implementar la API e incluso trabajar en su especificación. De esta forma, evita la implementación y la especificación de una API completamente no funcional.
Si escribiera al menos una pequeña sinopsis con un guión artificial, muy probablemente habría identificado un error y lo habría corregido. Si no, uno de mis colegas definitivamente lo haría. Cualquier decisión que tenga consecuencias de largo alcance debe considerarse al menos un día (esto se aplica no solo a la programación).
El título del ensayo de Richard Gabriel, "Lo peor, lo mejor", indica la ventaja que llega primero al mercado, incluso con un producto imperfecto, mientras que otra persona ha estado buscando el ideal durante años. Pensando en el código de sprites, entiendo que ni siquiera tuve que escribir más código para hacer todo como debería. Nos guste o no, estaba muy equivocado.
Conclusión
Los programadores cometen errores todos los días, ya sea escribir código con errores o no querer probar algo que aumente su habilidad y productividad. Por supuesto, puedes ser un programador y no permitir errores tan graves como lo hice yo. Pero convertirse en un buen programador sin darse cuenta de sus errores y no aprender de ellos es imposible.
Constantemente me encuentro con estudiantes que piensan que cometen demasiados errores y, por lo tanto, no están diseñados para la programación. Sé cuán común es el síndrome del impostor en TI. Espero que aprendas las lecciones que he enumerado, pero recuerda la principal: cada uno de nosotros comete errores: vergonzoso, divertido, aterrador. Estaré sorprendido y molesto si en el futuro no tengo suficiente material para continuar el artículo.