Los 7 problemas más molestos de la programación

Se ha dicho que los territorios inexplorados de los mapas antiguos a menudo se marcaban con la ominosa advertencia: "Aquí hay dragones". Quizás apócrifa, la idea era que nadie que se adentrara en estos rincones desconocidos del mundo debería hacerlo sin estar preparado para luchar contra un enemigo aterrador. Cualquier cosa podía pasar en estas misteriosas regiones y, a menudo, algo no estaba bien.

Los programadores pueden ser un poco más civilizados que los caballeros medievales, pero eso no significa que el mundo técnico moderno no tenga su parte de dragones técnicos esperándonos en lugares imprevistos: problemas difíciles que esperan hasta que la fecha límite esté a pocos minutos; complicaciones que han leído el manual y saben lo que no está bien especificado; dragones malvados que saben cómo infiltrarse en errores incipientes y fallas intempestivas, a menudo justo después de que se haya comprometido el código.

Habrá algunos que descansarán tranquilamente por la noche, animados por su ingenua seguridad en sí mismos de que las computadoras son completamente predecibles, produciendo con seriedad las respuestas correctas. Oh, qué poco saben. A pesar de todo el arduo trabajo de los diseñadores de chips, desarrolladores de lenguajes y millones de programadores en todas partes, todavía existen espinosos matorrales de problemas de programación que pueden poner de rodillas incluso a los programadores más poderosos.

Aquí hay siete de los rincones más retorcidos del mundo de la programación donde colocamos grandes marcadores que dicen: "Aquí hay dragones".

Multihilo

Parecía una buena idea: divida su programa en secciones independientes y deje que el sistema operativo las ejecute como pequeños programas separados. Si los procesadores tienen cuatro, seis, ocho o incluso más núcleos, ¿por qué no escribir su código de modo que pueda tener cuatro, seis, ocho o más subprocesos utilizando todos los núcleos de forma independiente?

La idea funciona cuando, de hecho, las partes están completamente separadas y no tienen nada que ver entre sí. Pero una vez que necesitan acceder a las mismas variables o escribir bits en los mismos archivos, todas las apuestas se cancelan. Uno de los subprocesos llegará primero a los datos y no puede predecir qué subproceso será.

Por lo tanto, creamos monitores, semáforos y otras herramientas para organizar el desorden multiproceso. Cuando funcionan, funcionan. Simplemente agregan otra capa de complejidad y convierten el acto de almacenar datos en una variable en un elemento que requiere un poco más de reflexión.

Cuando no funcionan, es un caos puro. Los datos no tienen sentido. Las columnas no cuadran. El dinero desaparece de las cuentas con un puf. Son todos los bits en la memoria. Y buena suerte tratando de precisar algo. La mayoría de las veces, los desarrolladores terminan bloqueando grandes partes de la estructura de datos para que solo un hilo pueda tocarla. Eso puede detener el caos, pero solo eliminando la mayor parte de las ventajas de tener varios hilos trabajando en los mismos datos. También podría reescribirlo como un programa de "un solo subproceso".

Cierres

En algún momento, alguien decidió que sería útil pasar las funciones como si fueran datos. Esto funcionó bien en instancias simples, pero los programadores comenzaron a darse cuenta de que los problemas surgían cuando las funciones llegaban fuera de sí mismas y accedían a otros datos, a menudo llamados "variables libres". ¿Qué versión fue la correcta? ¿Fueron los datos cuando se inició la llamada a la función? ¿O fue cuando la función realmente se ejecuta? Esto es especialmente importante para JavaScript, donde puede haber grandes espacios intermedios.

La solución, el "cierre", es una de las mayores fuentes de dolores de cabeza para los programadores de JavaScript (y ahora Java y Swift). Los novatos e incluso muchos veteranos no pueden averiguar qué se está cerrando y dónde podrían estar los límites del llamado cierre.

El nombre no ayuda, no es como si el acceso estuviera cerrado permanentemente como un bar que anuncia la última llamada. En todo caso, el acceso está abierto, pero solo a través de un agujero de gusano en el continuo de datos y tiempo, un extraño mecanismo de cambio de tiempo que está destinado a generar un programa de televisión de ciencia ficción. Pero llamarlo "Mecanismo de acceso de pila complejo" o "Sistema de malabarismo de control de datos" parece demasiado largo, por lo que estamos atascados con "cierres". No me hable de si alguien debe pagar por las variables que no son libres.

Demasiado big data

Cuando la RAM comienza a llenarse, todo comienza a ir mal. No importa si está realizando un análisis estadístico novedoso de los datos del consumidor o trabajando en una hoja de cálculo vieja y aburrida. Cuando la máquina se queda sin RAM, se convierte en la llamada memoria virtual que se derrama en el disco duro superlento. Es mejor que colapsar por completo o terminar el trabajo, pero lo hace todo más lento.

El problema es que los discos duros son al menos 20 o 30 veces más lentos que la RAM y las unidades de disco del mercado masivo suelen ser más lentas. Si algún otro proceso también está intentando escribir o leer desde el disco, todo empeora dramáticamente porque las unidades solo pueden hacer una cosa a la vez.

La activación de la memoria virtual exacerba otros problemas ocultos con su software. Si hay fallas de subprocesos, comienzan a romperse mucho más rápido porque los subprocesos que están atascados en la memoria virtual del disco duro se ejecutan mucho más lento que los otros subprocesos. Sin embargo, eso solo dura un breve período, porque los hilos de una vez alhelí se intercambian en la memoria y los otros hilos se cuelgan. Si el código es perfecto, el resultado es simplemente mucho más lento. Si no es así, las fallas lo envían rápidamente al desastre. Ese es un pequeño ejemplo.

Gestionar esto es un verdadero desafío para los programadores que trabajan con grandes cantidades de datos. Cualquiera que se vuelva un poco descuidado con la construcción de estructuras de datos derrochadoras termina con un código que ralentiza la producción. Puede funcionar bien con algunos casos de prueba, pero las cargas reales lo envían en espiral al fracaso.

NP-completo

Cualquiera con una educación universitaria en ciencias de la computación conoce los misteriosos problemas envueltos en un acrónimo que rara vez se explica: polinomio no determinista completo, también conocido como NP-completo. Los detalles a menudo toman un semestre entero para aprender, e incluso entonces, muchos estudiantes de informática salen con la idea confusa de que nadie puede resolver estos problemas porque son demasiado difíciles.

Los problemas NP-completos a menudo son bastante difíciles, si los ataca simplemente con la fuerza bruta. El "problema del vendedor ambulante", por ejemplo, puede llevar un tiempo exponencialmente largo ya que la ruta de ventas incluye cada vez más ciudades. Resolver un “problema de mochila” al encontrar un subconjunto de números que se acerquen más a algún valor N se resuelve probando todos los subconjuntos posibles, que es un número muy grande. Todos corren con miedo de estos problemas porque son el ejemplo perfecto de uno de los mayores fantasmas de Silicon Valley: algoritmos que no escalan.

La parte complicada es que algunos problemas NP-completos son fáciles de resolver con una aproximación. Los algoritmos no prometen la solución exacta, pero se acercan bastante. Puede que no encuentren la ruta perfecta para el vendedor ambulante, pero pueden llegar a unos pocos puntos porcentuales de la respuesta correcta.

La existencia de estas soluciones bastante buenas solo hace que los dragones sean más misteriosos. Nadie puede estar seguro de si los problemas son realmente difíciles o lo suficientemente fáciles si está dispuesto a estar satisfecho con una respuesta que sea lo suficientemente buena.

Seguridad

“Hay conocidos conocidos; hay cosas que sabemos que sabemos ”, dijo una vez Donald Rumsfeld, secretario de Defensa durante la segunda administración Bush, en una conferencia de prensa. “También sabemos que existen incógnitas conocidas; es decir, sabemos que hay algunas cosas que no sabemos. Pero también hay incógnitas desconocidas, las que no conocemos, no las conocemos ".

Rumsfeld estaba hablando de la guerra en Irak, pero lo mismo se aplica a la seguridad informática. Los mayores problemas son agujeros que ni siquiera sabemos que son posibles. Todo el mundo entiende que debe hacer que su contraseña sea difícil de adivinar; eso es conocido. Pero, ¿a quién se le ha dicho que su hardware de red tiene su propia capa de software enterrada en su interior? La posibilidad de que alguien pueda omitir la piratería de su sistema operativo y, en su lugar, apunte a esta capa secreta es una incógnita desconocida.

La posibilidad de ese tipo de hackeo puede que no le sea desconocida ahora, pero ¿y si hay otros? No tenemos ni idea de si podemos endurecer los agujeros que ni siquiera sabemos que existen. Puede ajustar las contraseñas, pero hay grietas que ni siquiera puede imaginar. Esa es la diversión de trabajar con seguridad informática. Y cuando se trata de programación, el pensamiento centrado en la seguridad es cada vez más importante. No puede dejar que los profesionales de seguridad limpien su desorden.

Cifrado

El cifrado suena poderoso e impenetrable cuando los funcionarios encargados de hacer cumplir la ley se ponen frente al Congreso y piden lagunas oficiales para detenerlo. El problema es que la mayor parte del cifrado se basa en una nebulosa nube de incertidumbre. Las pruebas matemáticas que tenemos se basan en suposiciones inciertas, como si fuera difícil factorizar números realmente grandes o calcular un registro discreto.

¿Son esos problemas realmente difíciles? Nadie ha descrito públicamente ningún algoritmo para romperlos, pero eso no significa que las soluciones no existan. Si encontraras una manera de escuchar a escondidas todas las conversaciones e irrumpir en cualquier banco, ¿se lo dirías rápidamente al mundo y les ayudarías a tapar los agujeros? ¿O te quedarías en silencio?

El verdadero desafío es utilizar el cifrado en nuestro propio código. Incluso si confiamos en que los algoritmos básicos son seguros, hay mucho trabajo por hacer para hacer malabarismos con contraseñas, claves y conexiones. Si comete un error y deja una contraseña desprotegida, todo se abre.

Gestión de identidad

A todo el mundo le encanta esa caricatura de New Yorker con el remate: "En Internet, nadie sabe que eres un perro". Incluso tiene su propia página de Wikipedia con cuatro secciones elaboradas. (En Internet, nadie conoce el viejo dicho sobre el análisis del humor y la disección de ranas).

La buena noticia es que el anonimato puede ser liberador y útil. La mala noticia es que no tenemos ni idea de cómo hacer nada más que comunicaciones anónimas. Algunos programadores hablan de "autenticación de dos factores", pero los inteligentes pasan a la "autenticación de factor N".

Después de la contraseña y tal vez un mensaje de texto a un teléfono celular, no tenemos mucho que sea muy estable. Los lectores de huellas dactilares se ven impresionantes, pero muchas personas parecen estar dispuestas a divulgar cómo pueden ser pirateados (consulte aquí, aquí y aquí para empezar).

No mucho de esto le importa al mundo de la charla inactiva en Snapchat o Reddit, pero el flujo de páginas de Facebook pirateadas es un poco desconcertante. No existe una manera fácil de manejar asuntos serios como la propiedad, el dinero, la atención médica o casi todo lo demás en la vida, excepto una pequeña charla sin sentido. A los fanáticos de bitcoin les encanta parlotear sobre cuán sólida puede ser la cadena de bloques, pero de alguna manera las monedas siguen siendo estafadas (ver aquí y aquí). No tenemos un método real para manejar la identidad.

Medir la dureza

Por supuesto, cuando se trata de programación, ¿existe alguna forma de medir la dificultad de un problema? Nadie lo sabe realmente. Sabemos que algunos problemas son fáciles de resolver, pero es completamente diferente certificar uno como difícil. NP-completo es sólo una parte de un elaborado intento de codificar la complejidad de los algoritmos y el análisis de datos. La teoría es útil, pero no puede ofrecer ninguna garantía. Es tentador decir que es difícil saber siquiera si un problema es difícil, pero bueno, entiendes el chiste.

Artículos relacionados

  • Descargar: Guía de desarrollo profesional para desarrolladores
  • El poder de la programación perezosa
  • 7 malas ideas de programación que funcionan
  • 9 malos hábitos de programación que amamos en secreto
  • 21 tendencias de programación candentes y 21 enfriar
  • Descargar: la guía de supervivencia empresarial del programador profesional
  • Descargar: 29 consejos para triunfar como desarrollador independiente
  • 7 lenguajes de programación que amamos odiar
  • 5 lecciones más atemporales de programación 'barbas grises'
  • 22 insultos que ningún desarrollador quiere escuchar
  • 9 predicciones para el futuro de la programación
  • Las 13 habilidades de desarrollador que necesitas dominar ahora
  • Programa el mundo: 12 tecnologías que debes conocer ahora
  • Ataque de los lenguajes de programación de una letra