Si los ingenieros de software son tan brillantes, ¿por qué el software es tan ‘defectuoso’, como el problema de mi signo @ y ‘ser cambiado?

Primero, no todos los ingenieros de software son brillantes: muchos simplemente luchan por mantenerse al día con las demandas de su profesión, o hacen la mayoría de las cosas de forma rutinaria, o hacen líos constantemente, posiblemente sin tener idea de que lo están haciendo. En segundo lugar, la brillantez en sí misma es una noción inexacta, y tener más o menos de ella no necesariamente se correlaciona de ninguna manera con la habilidad para inventar un gran software, y probablemente menos con un software libre de errores, así que tenga en cuenta que las premisas de su La pregunta ya puede ser defectuosa. He conocido a muchas personas “brillantes”, pero completamente dispersas, algunos ingenieros, que no pudieron decirte dónde están las llaves de su auto, o qué día es, y mucho menos escribir un proyecto de software grande y coherente (aunque pueden ser brillante en varios lugares dentro de un proyecto de software). Puede haber clases enteras de errores que las mentes más brillantes tienden a crear. No lo sé. De hecho, hay numerosos estudios que relacionan mentes brillantes con enfermedades mentales. No afirmaré que los llamados grandes ingenieros están locos. Más bien, estoy indicando por contraejemplo una falla potencial en su lógica, pero estoy divagando.

Hablando de defectos en la lógica, estos están en todas partes en el desarrollo de software, y en matemáticas, y en la vida cotidiana de probablemente todos nosotros. Hace poco me quedé boquiabierto al darme cuenta de que los australianos celebran la Navidad en la época más calurosa del año. He sabido durante décadas que las estaciones se voltean al sur del ecuador, pero nunca seguí la lógica, nunca hice la conexión de que diciembre es la mitad del verano para ellos, y que Bondi Beach está llena de personas en trajes de baño y sombreros de Santa . De manera similar, me impresionó hace años descubrir que Sydney está en la costa este de Australia. Toda mi vida he sabido que fue en la costa oeste. Discutí con un australiano (¡de Sydney!) Al respecto, y finalmente lo busqué y sentí que todo mi mundo era una mentira. Finalmente determiné que casi siempre había visto fotos de la Ópera de Sydney con el agua a la izquierda, así que pensé que estaba en el océano en la costa oeste, y luego mi cerebro llenó el resto y cimenté ese conocimiento en por más de 20 años Ni siquiera está en el océano. Está en un puerto. Esto les sucede a los desarrolladores sobre todo tipo de lógica y conexiones. He tenido cosas al revés muchas veces. He tenido 14 años de conversaciones de la industria con desarrolladores, donde todos nos corregimos todo el tiempo en reuniones y chats cuando alguien tiene su lógica en algo invertido. “No, eso es realmente O (n)”. “Creo que quisiste decir 43 negativo allí”. “¿Por qué tiene una función de 6 líneas aquí? En su lugar, puede componer esas dos funciones”. Sin embargo, no todos nos estamos mirando en todo momento, siempre corregiéndonos por consenso. A veces tenemos que sentarnos y escribir código por nuestra cuenta, y nos equivocamos.

Algunas compañías hacen “programación extrema”, donde toda la escritura de códigos se realiza en pares, por lo que siempre hay alguien vigilando por encima de su hombro, lo que puede ayudar, pero también es completamente posible que una persona explique su lógica incorrecta a la otra en un de manera convincente, y lo he hecho, y me lo han hecho muchas veces. Muchas tiendas usan revisiones de código, donde todo el código que se registra en una sucursal principal es revisado por al menos otra persona primero, como una especie de verificación de cordura. Aquí se detectan muchos errores, y algunos, posiblemente muchos, no. La primera vez que solicité una revisión de código, lo primero que hice fue abrir mis pruebas (estaba haciendo TDD completo en ese momento), y cuando expliqué la prueba en esa confirmación, descubrí que lo había escrito mal , y no estaba probando lo que pensé que estaba probando. ¿Cómo es eso de ROI? Si los programadores fueran tan brillantes, nunca encontraríamos ningún problema durante el emparejamiento o la revisión de código, y no los haríamos, pero lo hacemos, porque los programadores cometen errores TODO EL TIEMPO, brillantes o no. He dado y visto demostraciones de códigos en vivo donde la audiencia corrige el código que la persona está escribiendo, porque lo están arruinando, en vivo.

De hecho, acabo de dar una demostración en vivo recientemente, y después de 14 años de conocer la función lerp (interpolación lineal), haberla usado desde motores de juegos y haber escrito la mía en algunos idiomas diferentes, terminé demostrando una función completamente extraña. función que llamé lerp, que en realidad no era lerp. Luego, más tarde en la charla, expresé mi frustración al escribir una función diferente, diciendo que había escrito esto muchas veces a lo largo de los años, pero que nunca se me ocurrió un buen nombre, y un amigo de la audiencia dijo: “Bueno, eso es lerp “. Después de la charla, revisando el video, finalmente lo puse todo junto. He tenido dos ideas conflictivas en mi cabeza durante la mayor parte de 2 décadas: una en la que me doy cuenta de que estoy haciendo lerp, y escribo una lerp adecuada, y otra en la que no me doy cuenta de que necesito lerp, y escribo algo así, pero invente nombres raros para ello cada vez. Esta charla me vio inventar una tercera cosa que nunca había hecho antes, porque no hice la conexión de que lo que necesitaba era lerp, y sin embargo, lo llamé lerp, porque los cerebros son raros. Escribí una gran y desagradable función “toRange”, porque mod es integral, y no sabía sobre mod ‘de Data.Fixed, que funciona para reales, y que me permite reemplazar ~ 10 líneas de casos con un pequeño, todo -matemáticas. La gente me dijo más tarde que la charla fue brillante y, sin embargo, estuvo llena de vergonzosa falta de brillantez como esta.

Philip Wadler, uno de los creadores de Haskell, y coautor de los genéricos de Java, ha dicho en algunas de sus charlas: “La mayoría de los idiomas que usa son inventados, y se nota “. Su punto es que la mayoría de los idiomas que usamos están inventados. Son solo ideas aleatorias de los escritores de idiomas que son inteligentes y parecen funcionar bastante bien, pero no se basan en nada, como las matemáticas o la lógica formal. No se demuestra fácilmente que sean correctos, y pueden tener agujeros. Haskell (como muchos, muchos otros idiomas) tiene un problema en su Preludio (una biblioteca central cargada por defecto) con funciones no totales. Estas son funciones que no tienen un resultado para todas las entradas dadas. Por ejemplo, la función `head` no es total. Le da el primer elemento de una lista, pero si le da una lista vacía, algo que puede suceder en cualquier momento mientras se ejecuta un programa, arroja una excepción y bloquea el programa. Se supone que Haskell tiene un súper principio, pero viene con un montón de funciones inseguras que bloquean el programa y se cargan de manera predeterminada. Los principiantes tengan cuidado.

Este problema de no totalidad es grande, y está en todas partes en nuestra profesión, y puede ser difícil de eliminar. Escribes una buena función de división, y solo después te das cuenta / recuerda que dividir por 0 no tiene sentido. Mientras tanto, las personas usan esa función y ocasionalmente (o constantemente) hacen que sus programas se bloqueen por errores de división por 0. Hay un número infinito de funciones posibles, no totales, y otras nuevas que se escriben todo el día todos los días. También hay una serie de intentos para resolver el problema, incluidos los verificadores de totalidad, los intentos de describir las funciones totales a través de sistemas de tipo fuerte, utilizando lenguajes restringidos, sobre los cuales se pueden hacer garantías más fuertes, y aún más. Sin embargo, apostaría a que la mayoría de los programadores ni siquiera saben sobre estas cosas, y que aún se está explorando el espacio. Lamentablemente, la forma estándar en que se maneja la no totalidad en la industria es detectar los errores manualmente, algo que debe recordar hacer absolutamente en todas partes donde pueda ocurrir un error, y saber dónde ocurrirán los errores, y recordar tratarlos en todas partes manualmente es preguntar mucho, incluso de mentes brillantes. Nadie pega cada tiro libre. Esto también significa que el código a menudo se parece más a una mezcla de cosas que a las matemáticas, por lo que los poderes que obtienes al razonar sobre el código de varias maneras matemáticas se ven socavados. Ni siquiera sabía que se podía razonar sobre el código de manera matemática hasta hace aproximadamente un año. Ha sido una gran revelación.

Hablando de idiomas restringidos, y su potencial bondad, después de 25 años de codificación, solo el año pasado aprendí que lograr la integridad no es necesariamente algo bueno. Siempre he “sabido” que era lo mínimo que tenía que tener un sistema antes de poder escribir un programa, pero (como probablemente con la mayoría de los desarrolladores) nunca investigó más, y nunca aprendí que la gran mayoría de los programas probablemente no lo necesita, y estaría mucho mejor sin él. Solo estoy ahora, 2.5 décadas aprendiendo cómo la restricción a menudo otorga poder. En un sistema donde puede hacer menos, puede [al menos potencialmente] saber más. Si no ha oído hablar del problema P vs. NP, lo que significa para el mundo de la programación es que, en un sistema completo, no tenemos idea de si un programa terminará, lo que es similar a decir que no sepamos si alguna vez obtendremos una respuesta, o si el programa lo hará en lugar de entrar en un bucle infinito o fallar. ¡Esto es bastante malo!

Estamos escribiendo todo en un mundo donde literalmente no tenemos idea de si podemos saber si siempre funcionará. Todos estamos adivinando y esperando todo el tiempo, en todo lo que hacemos. De hecho, estoy un poco sorprendido de que funcione tan bien como la mayoría de las veces. No lo está haciendo porque es todo un sistema grande y brillante; lo está haciendo porque con el tiempo hemos aprendido lo que es menos probable que explote en nuestras caras, y porque, cuando las cosas explotan, como a menudo todavía lo hacen, las arreglamos, especialmente si realmente nos importa que no lo hagan. Has visto muchos menos errores de los que hay / fueron, porque afectaron a otras personas antes de que llegaras allí, y te arreglaron antes de que tuvieras la oportunidad de ser afectado por ellos. El software es muy orgánico de esta manera. Las personas molestas que gritan a los desarrolladores sobre cosas rotas son como glóbulos blancos, detectan problemas, y los desarrolladores que solucionan los peores son como anticuerpos que destruyen a los invasores.

Cuanto más he examinado la lógica formal, las pruebas, etc., y me doy cuenta de que soy un n00b completo aquí, más me he encontrado con la extrañeza de construir lógicas a partir de la nada, y lo extraño, a menudo ignorado, aún rincones aparentemente ineludibles donde las cosas no funcionan realmente bien, ejemplificadas en los teoremas de incompletitud de Gödel. Casi cada vez que encuentro algo que parece verdadero y profundo, y como respuesta a todos mis problemas, alguien más brillante ha venido a hacer agujeros para mí.

Pensé que la evaluación perezosa que aprendí a través de Haskell fue maravillosa, hasta que me enteré de lo difícil de razonar sobre las fugas espaciales y las “bombas de impacto” que puede (y a menudo lo hace). Pensé en los tipos dependientes, como se me reveló a través del trabajo de Ranjit Jhala en Haskell, y el lenguaje Idris de Edwin Brady resolvería la mayoría de los problemas de expresividad persistentes con el sistema de tipos Hindley-Milner utilizado por Haskell, pero luego aprendí que los tipos dependientes promueven lo horrible problema de detención al nivel de tipo. Pensé que los GADT resolvían el problema de que los ADT no permitían que los tipos de suma generen salidas con tipos diferentes, pero desde entonces escuché que los GADT aparentemente arruinan la tipificación de principios, de la que todavía no sé nada. Los diversos esquemas de recursión (Fix, Free, etc.) suenan geniales, pero cada uno es capaz de algunas cosas y no de otras, y nada de lo que he visto aún otorga los poderes de todos combinados. Esto sucede absolutamente en todas partes. Hay dos declaraciones que he escuchado durante gran parte de mi carrera, que no he querido creer, pero que finalmente he admitido que probablemente sean ciertas: 1) “No hay bala de plata” y 2) “Ingeniería es el arte de equilibrar las compensaciones competitivas “. Todo lo que elijas te pierde otras cosas que podrías haber deseado. Es una búsqueda constante para tratar de encontrar ese punto dulce donde el código no es una tarea masiva para escribir, puede ser entendido rápidamente por los nuevos desarrolladores, y no explota casi nunca, incluso si se cambia constantemente para cumplir constantemente Nuevas necesidades.

Tenga en cuenta que las compensaciones no son solo en la ingeniería en sí, donde los algoritmos más rápidos a menudo usan más espacio y viceversa, por ejemplo, sino en las herramientas que usamos para escribir el código y las herramientas que usamos para compartir nuestros conocimientos entre nosotros y en las decisiones comerciales que nos afectan a todos cuando intentamos hacer nuestro trabajo. Los desarrolladores más brillantes no lo saben todo, e incluso los pocos que parecen saberlo aún pueden encontrarse con dominios que no conocen. Es posible que las necesidades de los negocios simplemente no les brinden el tiempo y los recursos para aprender lo que necesitan saber para cada cosa nueva, por lo que tengo que abordarlo y espero haber hecho un buen trabajo. Acabo de escuchar una charla sobre Idris de Edwin Brady donde lamenta que su trabajo (escribir / publicar artículos, enseñar a los estudiantes) le impide introducir ciertas cosas en el idioma que le gustaría, porque simplemente no tiene el tiempo para hacerlo. Casi todos los desarrolladores tienen problemas como este. Podría ser un asistente en C ++ (no lo soy), pero no sé nada sobre los fondos de cobertura (no lo sé), por lo que hoy no puedo usar mis habilidades para escribir nada en ese dominio que sea bueno. Necesito tiempo para aprender todo sobre ese espacio, y mis primeros trabajos probablemente no serán tan perspicaces. Podría escribir un gran código que se cae debido a cosas obvias para un comerciante que simplemente no podía saber, porque no hago lo que hacen. Ser un gran codificador no significa que seas una gran cosa más. Solo podrá utilizar sus excelentes habilidades de codificación en problemas que entienda lo suficiente como para interpretarlos como problemas de codificación.

Puede que sepa todo sobre física y matemática de gráficos en 3D, pero nada sobre bibliotecas de gráficos y escritura para GPU. Cualquier desarrollador dado puede saber casi nada acerca de las complejidades de Unicode, o de las complejidades de los errores de caché. Se necesitan años para aprender las innumerables cosas que hay que aprender en el espectro de la programación de computadoras, y nadie lo sabe todo. Nadie puede ni siquiera. No hay tiempo suficiente en la vida de nadie para exponerse a todo eso, si todo lo que hicieron fue leer todo el día todos los días. Incluso leer no es bueno, porque leer sobre codificación es muy diferente a escribir código y hacer que todo funcione. He leído libros completos sobre idiomas, sistemas y software, y aún me siento como un principiante completo hasta después de haber pasado mucho tiempo con un sistema. No puedo decirte cuánto he leído y cuántas charlas tecnológicas he visto en mónadas; más de un año de eso, y todavía no tenía idea de qué eran las mónadas. Tuve que usarlos. Tuve que chocar contra las paredes y trabajar alrededor de ellas. Ahora tengo un buen sentido de ellos, pero todavía no entiendo completamente todo lo que permiten las mónadas, y a menudo encuentro usos incluso simples de ellos que confunden mi comprensión durante largos períodos de tiempo. He escrito código durante 25 años, pero solo aprendí sobre programación funcional hace 2 años, y ahora que estoy explorando ese espacio, siento que nunca supe realmente lo que estoy haciendo, y que la mayoría de lo que Lo que he hecho durante todos estos años fue un completo desastre inventado.

También hay un montón de legado, cosas que ya nadie debería saber, pero que aparecen para mordernos de vez en cuando. Hay personas que trabajan todo el tiempo en software heredado, y a menudo no hay información sobre cómo se hicieron las cosas, o por qué, por lo que tienen que redescubrirlo todo. Incluso los codificadores brillantes pueden requerir mucho tiempo para comprender el código de los demás, y las motivaciones detrás de él, y las razones por las que existen varias cosas. Inventamos nuestros propios modismos con frecuencia, y luego nos confunden los de los demás. Es como si todos tuviéramos nuestros propios dialectos de estos idiomas en nuestras cabezas, por lo que mi brillo podría parecer un galimatías para la mayoría de las personas. Por el contrario, podría escribir un código incorrecto que haga el trabajo, y los nuevos programadores podrían pensar que es brillante y pasar años escribiendo código con ese estilo, pensando que están haciendo las cosas bien. Muchos desarrolladores tienen que leer el código de muchos otros programadores todo el tiempo, y luchar por qué fue escrito de varias maneras. A menudo arreglamos algo que obviamente está mal, pero no sabíamos que estaba escrito intencionalmente mal, porque algo en algún otro lugar estaba mal, y esto tenía que estar mal para funcionar correctamente, por lo que nuestra brillantez nos engañó. Lo arreglamos, y así lo rompimos. Es una buena idea dejar un comentario en líos como ese, al menos para tratar de advertir a los futuros desarrolladores que las cosas están mal a propósito.

Luego, hay cosas fuera del software que arruinan nuestros esfuerzos. Lea el caso del correo electrónico de 500 millas para ver cuán locos pueden ser los errores “sin culpa de nadie”, y cuán verdaderamente brillante debe ser para resolverlos (nunca lo habría descubierto). Lea sobre el espectacular fallo del Mars Climate Orbiter, donde dos bits de software eran correctos, pero juntos estaban equivocados (fue culpa de alguien en este caso, aunque el software funcionó bien, solo con las unidades incorrectas). Esa es otra gran clase de errores para los que todavía estamos tratando de encontrar buenas respuestas. En este momento tenemos soluciones alternativas, como pruebas y contratos / políticas (aunque el contrato no ayudó en el caso del orbitador). Hay muchos casos en los que nadie está realmente equivocado, pero la combinación de cosas que no están mal conduce a problemas. Ver: la mutación no es necesaria para demostrar el problema. Considere tres bibliotecas: f …

En estos días tenemos el (los) problema (s) adicional (es) de múltiples núcleos en nuestras máquinas y toneladas de comunicación con los servicios web y entre nosotros a través de nuestras computadoras y dispositivos, donde tenemos que escribir código que fragmente sobre los lugares y tome decisiones basadas en el información desordenada que recibe (o no recibe) de fuentes externas. Hay problemas muy grandes que nadie ha resuelto por completo en este espacio, por lo que todos siguen las “mejores prácticas hasta ahora” y esperan lo mejor, y generan tanta redundancia y tantas comprobaciones y fallas como pueden, porque no podemos dejar de hacer cosas mientras lo resolvemos. Tenemos que seguir enviando cosas todos los días que no comprendemos.

Entonces, para terminar, no importa cuán brillante seas. No puede ser lo suficientemente brillante por la abrumadora complejidad que existe en casi todas partes en la ingeniería de software. Estoy tratando de eliminarlo en estos días aprendiendo principios de programación funcional, y se siente genial, porque enormes extensiones de errores que he conocido se vuelven imposibles, o mucho más fáciles de razonar sobre el uso de un buen lenguaje FP (Haskell) y los principios de FP, pero FP también me está enseñando sobre complejidades más grandes que nunca he sabido que existen. A veces siento que todo lo que realmente he hecho es pasar de una tonelada de errores de principiante a los errores más serios e intermedios que los matemáticos, los lógicos y los “informáticos” (cualesquiera que sean), y los ingenieros de software brillantes no tienen respuestas completas para todavía. Tenemos un largo camino por recorrer.

Los programas de computadora son los artefactos más complejos creados por la humanidad. Son aproximadamente cinco órdenes de magnitud más complejos que los sistemas puramente mecánicos como los rascacielos o los transbordadores espaciales, en términos de la cantidad de componentes y la cantidad de posibles interacciones. Los sistemas mecánicos dependen de las propiedades generales de la materia para extenderse y disipar el efecto de los defectos de construcción, como la falta de remaches y las tensiones que se encuentran en uso, mientras que incluso un pequeño error en un programa puede detener todo. Entonces, los programas son mucho más frágiles que los sistemas mecánicos.

Debido a que los componentes de un sistema de software no están hechos de nada físico, no hay que esperar a que lleguen las piezas o que el concreto se seque. Se pueden conectar rápidamente, comprimiendo el cronograma de desarrollo hasta que lo único que lo frene sea el tiempo de diseño. Esto ejerce presión sobre el cronograma de diseño que no está presente en la misma medida cuando se construyen ‘cosas’.

Que podamos construir software bajo estas restricciones locas es un milagro y un testimonio de las herramientas, las metodologías y la mente del hombre.

Eso sucede debido a la falta de coincidencia de diseño del teclado, nit debido a errores de software. Cuando se crearon los teclados, funcionaban de una manera muy simple: un script, un conjunto limitado de teclados. Sin embargo, como la gente ha declarado que usa múltiples diseños incluso para un solo idioma / script, los teclados a menudo tienen problemas de desajuste en el diseño del teclado (AZERTY / QWERTY / Dvorak).

Los teclados generalmente, en sí mismos, no tienen mucha información sobre el diseño en sí para presentar al dispositivo. ¡Intente cambiar el diseño entre QWERTY (Internacional), QWERTY (Reino Unido), QWERTY (EE. UU.) Y seleccione lo que se ajuste!

Administración: “Tenemos que enviar ahora. Puede regresar y arreglar eso cuando tengamos más tiempo”.

La respuesta es “deuda técnica”, y nunca, nunca “tienes más tiempo”, porque después de que envían una cosa, necesitan enviar la siguiente.

No tengo idea de tu problema ‘@’ y ‘”‘, pero como realmente no me dijiste qué tipo de hardware, sistema operativo, software, etc., estabas usando, incluidos los números de versión exactos, no hay forma razonablemente puede esperar una respuesta a esa pregunta.