Les 7 problèmes les plus épineux de la programmation

On a dit que les territoires inexplorés des anciennes cartes étaient souvent marqués de l'avertissement inquiétant: «Voici les dragons». Peut-être apocryphe, l'idée était que personne ne se promenant dans ces coins inconnus du monde ne devrait le faire sans être prêt à combattre un ennemi terrifiant. Tout pouvait arriver dans ces régions mystérieuses, et souvent rien n'était bon.

Les programmeurs sont peut-être un peu plus civilisés que les chevaliers médiévaux, mais cela ne veut pas dire que le monde technique moderne n'a pas sa part de dragons techniques qui nous attendent dans des endroits imprévus: des problèmes difficiles qui attendent que la date limite soit à quelques minutes; complications qui ont lu le manuel et savent ce qui n'est pas bien spécifié; des dragons maléfiques qui savent comment se faufiler dans les bogues insignifiants et les pépins intempestifs, souvent juste après la validation du code.

Il y en aura qui se reposent tranquillement la nuit, réchauffés par leur confiance naïve que les ordinateurs sont totalement prévisibles, produisant sérieusement les bonnes réponses. Oh, comme ils en savent peu. Malgré tout le travail acharné des concepteurs de puces, des développeurs de langage et des millions de programmeurs du monde entier, il existe encore des fourrés épineux de problèmes de programmation qui peuvent mettre à genoux même les programmeurs les plus puissants.

Voici sept des coins les plus sinistres du monde de la programmation où nous placerions de grands marqueurs indiquant: «Voici des dragons».

Multithreading

Cela semblait être une bonne idée: divisez votre programme en sections indépendantes et laissez le système d'exploitation les exécuter comme de petits programmes séparés. Si les processeurs ont quatre, six, huit ou même plus de cœurs, pourquoi ne pas écrire votre code de manière à ce qu'il puisse avoir quatre, six, huit ou plus de threads en utilisant tous les cœurs indépendamment?

L'idée fonctionne - lorsque les parties sont en fait complètement séparées et n'ont rien à voir les unes avec les autres. Mais une fois qu'ils ont besoin d'accéder aux mêmes variables ou d'écrire des bits dans les mêmes fichiers, tous les paris sont ouverts. L'un des threads va d'abord accéder aux données et vous ne pouvez pas prédire de quel thread il s'agira.

Ainsi, nous créons des moniteurs, des sémaphores et d'autres outils pour organiser le désordre multithread. Quand ils travaillent, ils travaillent. Ils ajoutent simplement une autre couche de complexité et transforment le fait de stocker des données dans une variable en un élément qui nécessite un peu plus de réflexion.

Quand ils ne fonctionnent pas, c'est le chaos pur. Les données n'ont pas de sens. Les colonnes ne s'additionnent pas. L'argent disparaît des comptes avec un pouf. Tout est en mémoire. Et bonne chance pour essayer de cerner tout cela. La plupart du temps, les développeurs finissent par verrouiller de gros morceaux de la structure de données afin qu'un seul thread puisse la toucher. Cela peut endiguer le chaos, mais seulement en éliminant la plupart des avantages d'avoir plusieurs threads travaillant sur les mêmes données. Vous pouvez aussi bien le réécrire comme un programme «à thread unique».

Fermetures

Quelque part le long de la ligne, quelqu'un a décidé qu'il serait utile de transmettre des fonctions comme s'il s'agissait de données. Cela fonctionnait bien dans des cas simples, mais les programmeurs ont commencé à se rendre compte que des problèmes se posaient lorsque des fonctions sortaient d'elles-mêmes et accédaient à d'autres données, souvent appelées «variables libres». Quelle version était la bonne? Était-ce les données lorsque l'appel de fonction a été lancé? Ou était-ce lorsque la fonction s'exécute réellement? Ceci est particulièrement important pour JavaScript où il peut y avoir de longs intervalles entre les deux.

La solution, la «fermeture», est l'une des plus grandes sources de maux de tête pour les programmeurs JavaScript (et maintenant Java et Swift). Les débutants et même de nombreux anciens combattants ne peuvent pas comprendre ce qui est fermé et où se situent les limites de la soi-disant fermeture.

Le nom n'aide pas - ce n'est pas comme si l'accès était fermé en permanence comme une barre annonçant le dernier appel. Si quoi que ce soit, l'accès est ouvert, mais uniquement par un trou de ver dans le continuum données-temps, un étrange mécanisme de décalage temporel qui est susceptible de générer une émission de télévision de science-fiction. Mais l'appeler «mécanisme d'accès à la pile complexe» ou «système de jonglage de contrôle des données» semble trop long, nous sommes donc coincés avec des «fermetures». Ne me demandez pas si quelqu'un doit payer pour les variables non libres.

Trop de données volumineuses

Lorsque la RAM commence à se remplir, tout commence à mal tourner. Peu importe que vous effectuiez une nouvelle analyse statistique des données des consommateurs ou que vous travailliez sur une vieille feuille de calcul ennuyeuse. Lorsque la machine est à court de RAM, elle se transforme en mémoire dite virtuelle qui se répand dans le disque dur ultra lent. C'est mieux que de s'écraser complètement ou de mettre fin au travail, mais le garçon fait tout ralentir.

Le problème est que les disques durs sont au moins 20 ou 30 fois plus lents que la RAM et que les disques durs grand public sont souvent plus lents. Si un autre processus essaie également d'écrire ou de lire à partir du disque, tout devient dramatiquement pire car les lecteurs ne peuvent faire qu'une seule chose à la fois.

L'activation de la mémoire virtuelle exacerbe d'autres problèmes cachés avec votre logiciel. S'il y a des problèmes de thread, ils commencent à se rompre beaucoup plus rapidement car les threads qui sont bloqués dans la mémoire virtuelle du disque dur s'exécutent beaucoup plus lentement que les autres threads. Cela ne dure qu'une brève période, cependant, car les threads autrefois wallflower sont échangés dans la mémoire et les autres threads se bloquent. Si le code est parfait, le résultat est simplement beaucoup plus lent. Si ce n'est pas le cas, les défauts l'envoient rapidement au désastre. Voilà un petit exemple.

Gérer cela est un véritable défi pour les programmeurs qui travaillent avec de grandes piles de données. Quiconque devient un peu négligent dans la construction de structures de données inutiles se retrouve avec un code qui ralentit jusqu'à une exploration en production. Cela peut fonctionner correctement avec quelques cas de test, mais de vraies charges l'envoient à l'échec.

NP-complet

Toute personne ayant une formation universitaire en informatique connaît les problèmes mystérieux enveloppés dans un acronyme rarement énoncé: polynôme non déterministe complet, alias NP-complet. Les détails prennent souvent un semestre entier à apprendre, et même dans ce cas, de nombreux étudiants en CS sortent avec une idée confuse que personne ne peut résoudre ces problèmes parce qu'ils sont trop difficiles.

Les problèmes NP-complets sont souvent assez difficiles - si vous les attaquez simplement avec la force brute. Le «problème du voyageur de commerce», par exemple, peut prendre un temps exponentiellement long car l'itinéraire de vente englobe de plus en plus de villes. Résoudre un «problème de sac à dos» en trouvant un sous-ensemble de nombres qui se rapproche le plus d'une certaine valeur N sont résolus en essayant tous les sous-ensembles possibles, ce qui est un très grand nombre. Tout le monde court avec peur de ces problèmes car ils sont l'exemple parfait de l'un des plus grands épouvantails de la Silicon Valley: des algorithmes qui ne peuvent pas évoluer.

La partie délicate est que certains problèmes NP-complets sont faciles à résoudre avec une approximation. Les algorithmes ne promettent pas la solution exacte, mais ils sont assez proches. Ils peuvent ne pas trouver l'itinéraire idéal pour le voyageur de commerce, mais ils peuvent se trouver à quelques points de pourcentage de la bonne réponse.

L'existence de ces très bonnes solutions ne fait que rendre les dragons plus mystérieux. Personne ne peut être sûr que les problèmes sont vraiment difficiles ou assez faciles si vous êtes prêt à être satisfait par une réponse juste assez bonne.

Sécurité

«Il y a des connus connus; il y a des choses que nous savons que nous savons », a déclaré un jour Donald Rumsfeld, le secrétaire à la Défense pendant la deuxième administration Bush, lors d'une conférence de presse. «Nous savons également qu'il existe des inconnues connues; c'est-à-dire que nous savons qu'il y a des choses que nous ne savons pas. Mais il y a aussi des inconnues inconnues - celles que nous ne savons pas, nous ne connaissons pas.

Rumsfeld parlait de la guerre en Irak, mais il en va de même pour la sécurité informatique. Les plus gros problèmes sont des trous dont nous ne savons même pas qu'ils sont possibles. Tout le monde comprend que vous devez rendre votre mot de passe difficile à deviner - c'est connu. Mais à qui a-t-on jamais dit que votre matériel réseau avait sa propre couche logicielle enfouie à l'intérieur? La possibilité que quelqu'un puisse sauter le piratage de votre système d'exploitation et cibler à la place cette couche secrète est une inconnue inconnue.

La possibilité de ce genre de piratage n'est peut-être pas inconnue de vous maintenant, mais que faire s'il y en a d'autres? Nous n'avons aucune idée si nous pouvons durcir les trous dont nous ignorons même l'existence. Vous pouvez réduire les mots de passe, mais il y a des fissures que vous ne pouvez même pas imaginer. C'est le plaisir de travailler avec la sécurité informatique. Et quand il s'agit de programmation, une réflexion axée sur la sécurité devient de plus en plus importante. Vous ne pouvez pas laisser aux professionnels de la sécurité le soin de nettoyer vos dégâts.

Chiffrement

Le cryptage semble puissant et impénétrable lorsque les responsables de l'application de la loi se présentent au Congrès et demandent des échappatoires officielles pour l'arrêter. Le problème est que la plupart des cryptages reposent sur un nuage d'incertitude brumeux. Les preuves mathématiques que nous avons reposent sur des hypothèses incertaines, comme il est difficile de factoriser de très grands nombres ou de calculer un log discret.

Ces problèmes sont-ils vraiment difficiles? Personne n'a décrit publiquement d'algorithmes pour les briser, mais cela ne signifie pas que les solutions n'existent pas. Si vous trouviez un moyen d'écouter chaque conversation et de pénétrer dans n'importe quelle banque, le diriez-vous rapidement au monde et l'aideriez-vous à combler les trous? Ou resteriez-vous silencieux?

Le vrai défi consiste à utiliser le cryptage dans notre propre code. Même si nous sommes convaincus que les algorithmes de base sont sécurisés, il reste encore beaucoup à faire pour jongler avec les mots de passe, les clés et les connexions. Si vous faites une erreur et laissez un mot de passe sans protection, tout tombe ouvert.

Gestion d'identité

Tout le monde aime ce dessin animé new-yorkais avec la punchline, "Sur Internet, personne ne sait que vous êtes un chien." Il a même sa propre page Wikipédia avec quatre sections élaborées. (Sur Internet, personne ne connaît la vieille scie sur l'analyse de l'humour et la dissection des grenouilles.)

La bonne nouvelle est que l'anonymat peut être libérateur et utile. La mauvaise nouvelle est que nous n'avons aucune idée de comment faire autre chose que des communications anonymes. Certains programmeurs parlent de «l'authentification à deux facteurs», mais les plus intelligents passent à «l'authentification à N facteurs».

Après le mot de passe et peut-être un message texte sur un téléphone portable, nous n'avons pas grand-chose de très stable. Les lecteurs d'empreintes digitales sont impressionnants, mais beaucoup de gens semblent prêts à divulguer comment ils peuvent être piratés (voir ici, ici et ici pour commencer).

Cela n'a pas beaucoup d'importance pour le monde du bavardage inactif sur Snapchat ou Reddit, mais le flux de pages Facebook piratées est un peu déconcertant. Il n'y a pas de moyen facile de gérer des questions sérieuses comme la propriété, l'argent, les soins de santé ou à peu près tout le reste de la vie, sauf des bavardages dénués de sens. Les fanbois de Bitcoin adorent bavarder sur la solidité de la blockchain, mais d'une manière ou d'une autre, les pièces continuent à se faire arnaquer (voir ici et ici). Nous n'avons pas de véritable méthode pour gérer l'identité.

Mesurer la dureté

Bien entendu, en matière de programmation, existe-t-il même un moyen de mesurer la difficulté d'un problème? Personne ne le sait vraiment. Nous savons que certains problèmes sont faciles à résoudre, mais il est tout à fait différent d'en certifier un comme étant difficile. L'exhaustivité NP n'est qu'une partie d'une tentative élaborée de codifier la complexité des algorithmes et de l'analyse des données. La théorie est utile, mais elle ne peut offrir aucune garantie. Il est tentant de dire qu'il est même difficile de savoir si un problème est difficile, mais bon, vous comprenez la blague.

Articles Liés

  • Télécharger: Guide de développement de carrière pour les développeurs
  • Le pouvoir de la programmation paresseuse
  • 7 mauvaises idées de programmation qui fonctionnent
  • 9 mauvaises habitudes de programmation que nous aimons secrètement
  • 21 tendances de programmation à chaud et 21 à froid
  • Télécharger: Le guide de survie en entreprise du programmeur professionnel
  • Téléchargement: 29 conseils pour réussir en tant que développeur indépendant
  • 7 langages de programmation que nous aimons détester
  • 5 autres leçons intemporelles de programmation 'Graybeards'
  • 22 insultes qu'aucun développeur ne veut entendre
  • 9 prédictions pour l'avenir de la programmation
  • Les 13 compétences de développeur que vous devez maîtriser maintenant
  • Programmer le monde: 12 technologies que vous devez savoir maintenant
  • Attaque des langages de programmation à une lettre