Entretien technique saboté (2022)
(xeiaso.net)- Palima Aethera semble être la candidate idéale pour sauver l’infrastructure chaotique de Techaro, mais retourne volontairement l’ambiance de l’entretien avec une étrange solution de live coding sur le tri
- L’intervieweur Jeff, après avoir vérifié la prononciation de son nom et si son visage est bien réel, se montre très intéressé par l’expérience de Palima sur l’infrastructure de MovieFlix et par son choix de FreeBSD
- Pour l’exercice de tri d’un tableau de nombres, Palima implémente en Haskell un sleepsort qui crée un thread par valeur, attend un temps proportionnel à cette valeur, puis l’affiche
- Palima insiste pour appeler cela un « tri en temps constant » et explique avoir fait une optimisation x10 en réduisant le délai de
100000à un multiple de10000microsecondes, ce qui fait rire Jeff - Après l’entretien, Palima s’attend à être recalée, mais Techaro lui envoie une proposition d’embauche pour un montant conséquent, et Palima décide de dormir en se disant que tout finira par se trier tout seul
Le jour de l’entretien, commencé dans un rêve
- Dans son rêve, Palima remarque que son talisman d’éveil a disparu de son poignet et comprend qu’elle est en train de rêver
- Réveillée le matin par la vibration de sa montre, elle se souvient qu’elle a un rendez-vous important ce jour-là
- Le trajet jusqu’au travail se boucle en 30 secondes, et Palima s’assoit sur une chaise modifiée pour accueillir sa queue et sa nageoire dorsale
- Sa station de travail lui signale que Firefox est obsolète, puis un script compile et lance une nouvelle version
Début de l’entretien chez Techaro
- La visioconférence se déroule sur un service de la gamme E100, et Palima allume l’éclairage de sa caméra
- Le premier intervieweur, Jeff, prononce d’abord mal le nom de Palima avant de se corriger aussitôt
- Palima précise que
Pa-lee-mahse prononce ainsi, etAetheracommeAy-theer-ah - Jeff dit qu’il le notera pour que les autres puissent aussi l’appeler correctement
- Palima précise que
- Quand Jeff demande si elle utilise un avatar virtuel, Palima répond : « C’est mon vrai visage »
- Rien qu’en lisant la description du poste, Palima a compris que l’infrastructure de Techaro était en plein chaos et avait besoin d’une héroïne
Présentation du parcours et expérience infra
- Palima se présente comme quelqu’un qui a beaucoup travaillé à fabriquer des dispositifs automatiques numériques et à les envoyer dans le monde pour accomplir leurs objectifs
- Chez MovieFlix, elle a contribué à bâtir l’infrastructure de streaming simultané pour les films populaires et les séries TV
- Elle ajoute avoir aussi travaillé sur de nombreux projets qu’elle ne peut pas divulguer, dont Jeff bénéficie probablement déjà d’au moins trois à l’heure actuelle
- Si elle veut rejoindre une petite entreprise, c’est pour mieux connaître les gens personnellement ; travailler comme une pièce anonyme dans une machine n’a selon elle qu’un attrait limité dans le temps
- Parmi ses projets d’infrastructure préférés, elle cite le benchmark de noyaux d’OS pour le backend de MovieFlix
- Palima espérait que Linux l’emporterait, mais après
epoll(7), FreeBSD s’est révélé plus rapide, ce qui l’a amenée à choisir FreeBSD - Elle ajoute qu’elle doit probablement encore avoir les droits de commit sur FreeBSD
- Palima espérait que Linux l’emporterait, mais après
Live coding : sleepsort
- Jeff explique que le profil de Palima semble correspondre à ce que recherche Techaro, mais qu’il faut tout de même passer par un coding challenge pour évaluer tout le monde selon les mêmes critères
- L’exercice consiste à trier un tableau de nombres sur un site web, puis à expliquer la méthode de tri utilisée
- Le langage était libre, et Palima choisit d’écrire du code Haskell
- L’implémentation crée un green thread distinct pour chaque nombre, attend
threadDelay (100000 * time), puis écrit la valeur dans un canal avant de l’afficher - Palima explique que ce tri n’utilise aucune comparaison et qu’« il suffit parfois d’un peu de repos »
- Quand Jeff demande si le temps ne varie pas selon les valeurs d’entrée, Palima répond que la complexité temporelle ne se soucie pas d’effets de bord comme le temps
Optimisation et résultat inattendu
- Quand Jeff demande comment optimiser, Palima se contente de changer le multiplicateur du délai
100000 * timedevient10000 * time- Palima explique que c’est désormais 10 fois plus rapide
- Jeff finit par éclater de rire, et quand Palima se fait demander pourquoi elle a utilisé un algorithme de tri aussi étrange, elle rétorque : « Pourquoi poser une question aussi étrange ? »
- Palima juge que Techaro n’est pas assez complexe pour la contenir et qu’un unique serveur dédié de Typhoon Digital aurait suffi à la place de Kubernetes
- Une fois l’entretien terminé, elle s’attend à recevoir rapidement un e-mail de refus
- Mais Techaro lui envoie finalement un e-mail disant vouloir l’embaucher pour une somme conséquente, et Palima se demande s’ils savent vraiment ce qu’ils s’apprêtent à assumer
- Palima décide de se rendormir en se disant que d’ici le soir, les choses finiront bien par se trier d’elles-mêmes
1 commentaires
Commentaires sur Hacker News
Ce n’est ni en temps constant, ni en temps polynomial, mais en temps pseudo-polynomial. Ça semble échouer avec des nombres négatifs, et pour être linéaire par rapport au nombre de bits servant à représenter l’entrée, il faudrait quelque chose comme
10000 * log(time + min(time) + 1)En théorie de la complexité calculatoire, dire qu’un algorithme numérique s’exécute en temps pseudo-polynomial signifie que son temps d’exécution est polynomial en fonction des valeurs numériques de l’entrée, c’est-à-dire du plus grand entier présent dans l’entrée, et non polynomial en fonction de la taille de l’entrée (le nombre de bits nécessaires pour représenter ce nombre)
https://en.m.wikipedia.org/wiki/Pseudo-polynomial_time
La complexité calculatoire traite du nombre d’étapes dans un modèle de calcul, pas du temps qui s’écoule sur une horloge. sleep sort exploite les propriétés de l’ordonnanceur du système d’exploitation, et dans un environnement à temps virtuel, le temps avance directement jusqu’au prochain événement planifié. En partant de ce type de modèle de calcul, ça tourne en pratique avec une complexité polynomiale
Et si tu veux faire la leçon aux autres, le minimum serait d’écrire correctement pseudo-polynomial
1de la longueur de chaque valeur, séparée par des0Reconvertir ça en entiers est linéaire, puis il suffit d’appeler la boîte d’origine et de renvoyer le résultat ; à partir de là, ça devient polynomial par rapport à la longueur de mon entrée. J’ai parlé d’entiers, mais le fond du sujet, c’est l’encodage, donc on pourrait aussi utiliser un seul
0pour les décimales et00pour séparer les entréesDe toute façon, le cœur de la blague, c’est bien que le temps passé à dormir ne compte pas, non ? L’ordinateur peut faire autre chose pendant ce temps. Il y a quelque chose d’assez convaincant dans le côté « c’est idiot, mais j’aime bien »
sleep sort vient de /prog/ [0]. Il y a probablement pas mal de lecteurs silencieux de HN qui avaient participé au thread sleep sort à l’époque ; peut-être même xena :)
[0] https://www.cs.princeton.edu/courses/archive/fall13/cos226/l...
<=>à utiliser quand on veut tester « plus petit, égal ou plus grand ». GénialComme l’a dit l’auteur original, ce texte ressemble énormément au style narratif de la série Interview d’aphyr, par exemple « Rewriting the Technical Interview ». Tout cela se lit avec plaisir
[0] - https://aphyr.com/posts/353-rewriting-the-technical-intervie...
https://joelgrus.com/2016/05/23/fizz-buzz-in-tensorflow/
Extrait :
Un tri informatique doit lire l’entrée, donc il lui faut au minimum un temps linéaire. C’est d’autant plus vrai si l’on ne connaît pas d’autres informations sur l’entrée, comme une distribution uniforme
Il existe plusieurs tris en temps linéaire, comme sleep sort, postman sort ou counting sort. Mais cela vaut pour des ensembles de nombres ou des clés de tri limités
En revanche, si l’on utilise un boulier au lieu d’un ordinateur, on obtient un tri en temps constant presque crédible : https://en.wikipedia.org/wiki/Bead_sort
C’est une histoire mignonne, mais en aucun cas du temps constant
Créer
Nthreads et les ajouter à une liste de réveil triée prend entre O(N log N) et O(N^2) selon le système d’exploitation ou le runtime du langageQuelque part en coulisses, il y a une liste triée, un tas, ou un algorithme en N^2. De même, sleep sort lui-même est au minimum en temps linéaire, puisqu’il faut réveiller
Nthreads pour produireNéléments triésPire encore, le temps réel augmente aussi avec la taille des valeurs. On peut d’abord trouver le minimum et le maximum pour compresser la plage, mais cela reste linéaire
Ici, c’est une blague à double sens fondée sur deux conceptions contradictoires du mot « temps ». Il est exact que, du point de vue de l’analyse de complexité, rendre un algorithme de tri en temps constant est impossible
L’intention réelle de la blague, c’est le temps d’horloge. En entretien, c’est ce temps-là qui est le plus pertinent, et en pratique, quand quelqu’un vous lance un truc du genre « écrivez une fonction de tri d’entiers », il est rare qu’il n’utilise que des nombres inférieurs à 100, donc ce programme s’exécute en apparence presque instantanément
C’est une plaisanterie métalinguistique subtile qui se moque en renversant la compréhension de la façon dont fonctionne l’informatique. Dommage que la blague n’ait pas pris
https://en.wikipedia.org/wiki/Ultimate_fate_of_the_universe#...
sleepdoit bien finir par se ramener à un entier, donc on pourrait aussi traiter ça en temps linéaire avec quelque chose comme un tri radixIl existe des espaces de problèmes où cela reste avantageux, même avec une dépendance à la taille de la plus grande valeur
Bien sûr, aucun système réel ne fonctionne ainsi. Les timeouts des appels système ne sont généralement pas un cas où cette approche est favorable. Et bien entendu, il vaudrait mieux appliquer directement un tri radix qui ne dépend que de
log(max_value)plutôt qu’une méthode proportionnelle linéairement au maximumNthreads et les ajouter à une liste de réveil triée coûte O(N log N) à O(N^2) n’est pas une limite fondamentale des systèmes d’ordonnancementC’est d’autant plus vrai si l’on tient compte de matériel spécialisé permettant un ordonnancement en temps constant par rapport au nombre de threads. Par exemple, même si ce serait totalement absurde économiquement, on pourrait construire un ordonnanceur qui envoie des paquets d’information via laser sur un vaste ensemble de miroirs placés à différentes distances, puis les fait revenir vers un détecteur connecté à l’ordinateur
On utiliserait ainsi la vitesse de la lumière pour introduire le délai voulu. Par conséquent, sleep sort ne dépend pas intrinsèquement d’une complexité algorithmique cachée d’un mode particulier d’ordonnancement des threads, et, même si ce n’est pas pratique, on pourrait en théorie l’optimiser en O(1)
Si ça vous plaît, il existe aussi une sorte de suite appelée Protos : https://xeiaso.net/blog/protos
J’écris encore des histoires dans cet « univers », mais il faut un peu de temps pour recharger l’énergie satirique. Le prochain épisode sera peut-être sur l’informatique spatiale
Cela dit, cet univers semble meilleur pour trouver des noms
Le passage où
threadDelay (100000 * time)devientthreadDelay (10000 * time)et où l’on dit « maintenant c’est dix fois plus rapide » est en lien avec cet article : https://thedailywtf.com/articles/The-Speedup-LoopJe n’ai pas lu l’article, mais je déteste ce genre de choses. J’ai passé un entretien à distance chez Meta il y a quelque temps, et l’interlocuteur a mangé en parlant dans son micro pendant tout l’échange
C’était tellement déconcentrant que j’en ai oublié comment écrire une boucle for
Si on était déjà en poste, il fallait poser un congé, avec le stress du genre « est-ce que je gaspille mes congés limités pour ça ? », « est-ce qu’il y aura du parking ? », « est-ce que j’arriverai à l’heure ? ». Puis on passait un « entretien initial » de 30 minutes, on attendait des semaines, puis soit on était invité au vrai entretien, soit on n’avait plus aucune nouvelle
Tout le processus pouvait prendre un mois, avec au moins deux jours de congé et des déplacements importants
Aujourd’hui, un recruteur ou les RH vous appellent, demandent si vous êtes disponible pour un appel vidéo, font un échange de 15 à 20 minutes le jour même, puis transmettent votre CV au décideur et planifient un ou plusieurs entretiens vidéo ou une session technique. Certaines entreprises vous demandent de faire tranquillement chez vous des tests comportementaux ou techniques
Si vous travaillez à distance, vous pouvez tout régler sur la pause déjeuner. La bande passante de la communication en présentiel est certes bien plus grande, mais seul le distanciel permet de passer un entretien le matin avec une entreprise de Tel Aviv, à midi avec une société de Varsovie, puis le soir avec une entreprise californienne
Créer 1000 threads, ce n’est pas au moins du temps linéaire ? On pourrait peut-être réduire jusqu’au logarithmique, mais je doute que ce code le fasse automatiquement
Pour que sleep sort soit en temps constant, il faut une borne sur l’entrée, c’est-à-dire une limite sur le plus grand nombre, et il faut aussi ne pas compter des opérations arbitraires comme la lecture et le traitement de l’entrée ou la création des threads
Mais si l’on autorise cela, alors tous les autres tris deviennent aussi en temps constant. Une seule de ces deux conditions semble déjà suffire
Si le runtime des threads maintient sa propre notion du temps, l’algorithme n’a même pas besoin de dormir en temps réel
Une fois tous les threads créés, le runtime peut constater qu’ils sont tous inactifs et que le prochain thread à planifier est celui de l’instant N ; il suffit donc de mettre à jour le temps courant à N et d’exécuter ce thread. En répétant cela, on obtient un tableau trié sans aucun
sleepEn fin de compte, le tri est déjà terminé au moment où les threads commencent à s’endormir ; ils se sont simplement enregistrés auprès d’un coordinateur chargé de les réveiller plus tard, par exemple une roue de temporisation. Il n’est pas nécessaire d’effectuer un vrai sommeil
Je ne connais pas Haskell, mais le runtime tokio de Rust permet cela avec
start_paused: https://docs.rs/tokio/latest/tokio/runtime/struct.Builder.ht...En laissant de côté les multiples couches d’abstraction et les détails d’implémentation omis, trier des valeurs avec un tel ordonnanceur, c’est simplement un tri par tas :)