Llegamos a ustedes gracias a:



Reportajes y análisis

Los 7 problemas más frustrantes en la programación

[22/12/2016] Se ha dicho que los territorios inexplorados de los viejos mapas eran frecuentemente señalados con la advertencia: "Aquí hay dragones. Quizás ficticia, la intención de esta marca era que nadie que se atreviese a introducirse en estos rincones del mundo, debía hacerlo sin estar preparado para batallar a un adversario terrorífico. Cualquier cosa puede suceder en estas regiones misteriosas, y con frecuencia esa cosa cualquiera no es nada buena.

Puede que los programadores sean un poco más civilizados que los caballeros medievales, pero eso no significa que el mundo tecnológico moderno no tenga su porción de dragones técnicos esperando por nosotros en lugares imprevistos: Problemas difíciles que esperan hasta que la fecha límite se encuentra a unos minutos; complicaciones que al leer el manual no se pueden especificar bien; dragones malévolos que saben cómo escabullirse en fallas prematuras y anomalías precoces, con frecuencia justo después de que el código es comprometido.

Habrá algunos que descansen silenciosamente por la noche, abrigados por su confianza ingenua en que las computadoras son completamente predecibles, capaces de producir las respuestas correctas con sinceridad. Oh, pero qué poco saben. Aún con todo el trabajo duro de los diseñadores de chips, los desarrolladores de lenguajes, y los millones de programadores en todo el mundo, siguen existiendo problemas espinosos de programación que pueden arrodillar hasta a los programadores más poderosos.

Aquí tenemos siete de los rincones más desafiantes del mundo de la programación donde pondríamos la señal que dice, "Aquí hay dragones.

Multithreading

Sonaba como una buena idea: Divida su programa en secciones independientes y permita que el sistema operativo los opere como programas pequeños individuales. Si los procesadores tienen cuatro, seis, ocho, o hasta más núcleos, por qué no escribir su código para que este pueda tener cuatro, seis, ocho, o más subprocesos usando todos los núcleos de manera independiente.

La idea funciona -cuando las partes en efecto se encuentran completamente separadas y no tienen nada qué ver una con la otra. Pero una vez que necesitan acceder a las mismas variables o escribir bits a los mismos archivos, todo puede pasar. Uno de los subprocesos va a llegar a los datos primero y no podrá predecir cuál de todos será.

En consecuencia, nosotros creamos monitores, semáforos y otras herramientas para organizar el desorden de los múltiples subprocesos. Cuando funcionan, funcionan. Ellos meramente añaden otra capa de complejidad y convierten el acto de almacenar los datos en una variable dentro de un ítem que requiere un poco más de pensamiento.

Cuando no funcionan, es un caos total. Los datos no tienen sentido. Las columnas no se suman correctamente. El dinero desaparece de las cuentas en un santiamén. Todo se trata de bits en la memoria. Y buena suerte al intentar descifrar qué pasa. La mayoría del tiempo, los desarrolladores terminan encerrando grandes trozos de la estructura de datos para que solo un subproceso pueda tocarlos. Puede que eso detenga el caos, pero eso solo es posible eliminando la mayoría de las ventajas de tener múltiples subprocesos trabajando en los mismos datos. Prácticamente sería lo mismo si volviera es escribir todo como un programa "de un solo subproceso.

Cierres

En algún punto, alguien decidió que sería útil propagar funciones como si fuesen datos. Esto funcionó bien en instancias simples, pero los programadores empezaron a darse cuenta de que surgían problemas cuando las funciones tenían un alcance mayor a ellas mismas y accedían a otros datos, con frecuencia llamados "variables libres. ¿Qué versión era la correcta? ¿Eran los datos cuando la llamada de función fue iniciada? ¿O fue cuando la función de hecho está operando? Esto es de especial importancia para JavaScript donde puede haber grandes brechas de por medio.

La solución, el "cierre, es una de las fuentes más grandes de dolores de cabeza para los programadores de JavaScript (y ahora Java y Swift). Los novatos, e inclusive muchos veteranos, no pueden descifrar lo que está siendo cerrado y dónde podrían encontrarse los límites del denominado cierre.

El nombre no ayuda -no es como si el acceso estuviese cerrado permanentemente. Más bien, el acceso está abierto, pero solo a través de un agujero de gusano en el continuo datos-tiempo, un mecanismo extraño de cambio de tiempo que eventualmente terminará por engendrar un show de televisión de ciencia ficción. Pero los nombres como "Complex Stack Access Mechanism o "Data Control Juggling System parecen ser demasiado largos, así que estamos atascados con "cierres. Que nadie me toque el tema de si es que alguien tiene que pagar por las variables no libres.

Datos demasiado grandes

Cuando la memoria RAM empieza a llenarse, todo empieza a salir mal. No importa si está desempeñando un análisis minuto a minuto de datos de consumidores, o trabajando en una vieja y aburrida hoja de cálculo. Cuando a la máquina se le agota la memoria RAM, ésta recurre a la memoria virtual que se saca del extremadamente lento disco duro. Es mejor que colapsar por completo o terminar el trabajo, pero todo se vuelve realmente lento.

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

Activar la memoria virtual exacerba otros problemas escondidos con su software. Si existen errores con los subprocesos, estos empiezan a romperse mucho más rápido porque los subprocesos que están atrapados en la memoria virtual del disco duro operan mucho más lentos que los demás subprocesos. Aunque eso solo dura un breve periodo porque una vez que los subprocesos que una vez fueron dejados de lado son intercambiados en la memoria y los otros subprocesos se cuelgan. Si el código es perfecto, el resultado es meramente más lento. Si no lo es, las fallas lo mandan rápidamente al colapso. Ese es un pequeño ejemplo.

Administrar esto es un verdadero reto para los programadores que están trabajando con grandes pilas de datos. Cualquiera que se vuelve un poco descuidado construyendo estructuras despilfarradas de datos termina con un código que se vuelve lento hasta el punto de terminar arrastrándose en la producción. Puede que funcione bien con unos cuantos casos de prueba, pero las cargas reales lo terminan llevando a un espiral de fracaso.

NP-complete

Cualquiera con una educación universitaria en ciencias de la computación conoce los misteriosos problemas envueltos en un acrónimo pocas veces develado: nondeterministic polynomial complete, más conocido como NP-complete. Los detalles con frecuencia toman un semestre completo en ser aprendidos, e incluso entonces, muchos estudiantes de ciencias de la computación terminan con la noción borrosa de que nadie puede resolver estos problemas porque son muy difíciles.

Los problemas NP-complete con frecuencia son bastante complicados -si los ataca simplemente con fuerza bruta. El "problema del vendedor viajero, por ejemplo, puede tomar un tiempo exponencialmente largo conforme la ruta de ventas va incluyendo más ciudades. Resolver el "problema de la mochila buscando un subconjunto de números, que se acercan lo más posible a un valor N, se resuelven probando todos los subconjuntos posibles, que es un número muy grande. Todos huyen aterrados de estos problemas porque son los ejemplos perfectos de uno de los mayores monstruos que se encuentran en Silicon Valley: algoritmos que no escalan.

La parte engañosa es que algunos problemas NP-complete 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 viajero, 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 realmente seguro de si es que los problemas son verdaderamente difíciles o sencillos si es que uno está dispuesto a conformarse con una respuesta que no es lo suficientemente buena.

Seguridad

"Existen conocidos conocidos, existen cosas que sabemos que sabemos, señaló Donald Rumsfeld, el secretario de Defensa durante la segunda administración de Bush, en una conferencia de prensa. "Nosotros también sabemos que existen desconocidos conocidos; es decir, sabemos que existen algunas cosas de las que desconocemos. Pero también existen desconocidos desconocidos -las cosas que desconocemos desconocer.

Rumsfeld estaba hablando sobre la guerra en Irak, pero lo mismo resulta válido para la seguridad en la computación. Los problemas más grandes son agujeros que ni siquiera sabemos si son posibles. Todos entienden que debería hacer que su contraseña sea difícil de adivinar -eso es un conocido conocido. Pero ¿a quién se le ha dicho que su hardware de networking tiene un software propio enterrado adentro? La posibilidad de que un hacker pueda saltarse su sistema operativo y acceder a esta capa secreta es un desconocido desconocido.

La posibilidad de ese tipo de ataque puede no serle desconocida ahora, pero ¿qué sucede si existen otras? No tenemos idea sobre si podemos reforzar los agujeros que ni siquiera sabemos que existen. Usted puede utilizar contraseñas. Pero existen grietas que no es capaz de imaginar. Eso es lo divertido de trabajar con la seguridad de la computación. Y cuando se trata de programación, la mentalidad orientada a la seguridad se está volviendo aún más relevante. Usted no puede delegar su desorden a los profesionales de la seguridad.

Cifrado

El cifrado suena poderoso e impenetrable cuando las autoridades policiales solicitan al congreso alguna manera oficial de detenerlo. El problema es que la mayoría del cifrado está construida sobre una nube borrosa de incertidumbres. Las pruebas matemáticas que tememos descansan en suposiciones inciertas, como que es difícil factorizar números realmente grandes o calcular un logaritmo discreto.

¿Esos problemas son realmente difíciles? Nadie ha descrito públicamente ningún algoritmo para resolverlos, pero eso no significa que las soluciones no existan. Si encontró una manera de escuchar todas las conversaciones sin ser notado y poder entrar a cualquier banco, ¿le diría inmediatamente al mundo y ayudaría a que todos taparan los agujeros?  ¿O permanecería en silencio?

El verdadero reto es utilizar el cifrado en nuestro propio código. Inclusive si confiamos en que los algoritmos básicos son seguros, existe mucho trabajo por hacer mientras realizamos malabares con las contraseñas, llaves y conexiones. Si comete un error y deja desprotegida una contraseña, todo termina por abrirse.

Administración de la identidad

A todos les encanta esa frase en la caricatura de la revista New Yorker que dice, "En Internet, nadie sabe que usted es un perro. Hasta cuenta con su propia página de Wikipedia con cuatro secciones elaboradas. (En internet, nadie conoce al viejo proverbio sobre analizar el humor y diseccionar ranas).

La buena noticia es que el anonimato puede ser liberador y útil. La mala noticia es que no tenemos idea de cómo hacer algo que no sea comunicación anónima. Algunos programadores hablan de una "autentificación de doble factor, pero los más inteligentes saltan hacia una "autentificación de N factores.

Después de una contraseña y quizás un mensaje de texto a un teléfono celular, no tenemos muchas cosas que sean muy estables. Las lectoras de huellas digitales se ven impresionantes, pero muchas personas parecen dispuestas a divulgar cómo pueden ser hackeadas (aquí, aquí y aquí, por ejemplo).

No mucho de esto le importa al mundo de las conversaciones en Snapchat o Reddit, pero el torrente de páginas de Facebook que han sido víctimas de hackers es un poco desconcertante. No existe una manera sencilla de manejar temas serios como propiedad, dinero, cuidado de la salud, o prácticamente nada más en la vida que no sean conversaciones triviales. A los fanáticos de bitcoin les encanta hablar sobre lo sólida que puede ser la cadena de bloqueo, pero de alguna forma las monedas siguen siendo el centro de estafas. No tenemos un método real para manejar la identidad.

Medir la dificultad

Por supuesto, cuando se trata de programación, ¿siquiera existe una manera mediante la cual podemos medir la dificultad del problema? Nadie lo sabe realmente. Si sabemos que algunos problemas son fáciles de resolver, pero es completamente distinto certificar uno como difícil. El factor NP-complete es solo una parte de un intento elaborado de cifrar la complejidad de los algoritmos y el análisis de datos. La teoría es útil, pero no puede ofrecer ninguna garantía. Resulta tentador decir que es difícil hasta saber si es que un problema es difícil, pero bueno, usted capta el chiste.

Peter Wayner, InfoWorld (EE.UU.)