Questions d'entretien pour programmeur / développeur logiciel et comment y répondre
Un entretien de développeur est rarement un examen de définitions. Celui qui vous reçoit veut voir comment vous réfléchissez quand quelque chose casse, comment vous tranchez entre deux conceptions imparfaites et comment vous travaillez avec du code que vous n'avez pas écrit. Il y a souvent une partie technique ou de coding (en direct ou un test en amont), mais l'essentiel du temps passe à expliquer vos décisions : pourquoi vous avez choisi cette structure de données, pourquoi vous avez ajouté une file d'attente au lieu d'appeler directement, pourquoi ce bug a pris trois jours.
Ce qui sépare ceux qui réussissent de ceux qui échouent n'est pas le savoir, mais la capacité à raisonner à voix haute sans se bloquer. Beaucoup savent résoudre le problème mais se taisent pendant qu'ils réfléchissent, ou lâchent la solution sans expliquer le cheminement. Voici des questions propres au poste, avec un guide pour cadrer chacune. Lisez-les, mais ne vous arrêtez pas là : une réponse ne compte que si vous savez la formuler sous pression.
Ce qu'on évalue dans cet entretien
- Résolution de problèmes et raisonnement technique à voix haute
- Débogage systématique dans l'incertitude
- Conception et architecture : gérer des compromis sans réponse unique
- Qualité du code et collaboration en code review
- Communication : expliquer clairement des décisions techniques
- Gestion du code hérité et de la dette technique
Questions fréquentes pour programmeur / développeur logiciel
- 01
Racontez-moi le bug le plus difficile que vous ayez débogué. Comment l'avez-vous trouvé et pourquoi vous a-t-il donné tant de fil à retordre ?
Ne décrivez pas le bug, décrivez votre méthode : comment vous l'avez reproduit, quelles hypothèses vous avez écartées et comment vous avez isolé la cause. Ce qu'on évalue, c'est votre processus de débogage, pas l'anecdote.
Exemple de réponse « Nous avions une erreur de paiement qui n'apparaissait qu'en production, une transaction sur mille. J'ai d'abord réussi à la reproduire : j'ai capturé les payloads réels des cas en échec et monté un test qui les rejouait en local. J'ai écarté la passerelle en comparant ses logs aux nôtres, et écarté des données corrompues en validant le schéma. Au final, c'était une situation de compétition (race condition) : deux webhooks du même paiement arrivaient à quelques millisecondes d'écart et le second écrasait le premier. J'ai mis une semaine parce que le log agrégé masquait l'ordre réel d'arrivée. Je l'ai résolu avec un verrou par identifiant de paiement et j'ai ajouté un test de concurrence pour que ça ne revienne pas. »
- 02
Vous êtes en code review et un collègue vous signale que votre solution ne passe pas à l'échelle. Que faites-vous ?
Montrez que vous dissociez votre ego du code. Racontez comment vous demandez le cas concret qui met en défaut votre approche, quelles questions vous posez pour cerner la vraie limite, et quand vous cédez face à quand vous défendez votre choix avec des données.
Exemple de réponse « La première chose, c'est de lui demander le cas concret : à partir de quel volume mon approche cesse-t-elle de tenir ? S'il me dit qu'avec 10 000 éléments par requête ma boucle explose, je le vérifie avec des données réelles de production. Ça nous est arrivé sur une liste que j'avais traitée en mémoire : il avait raison pour les 5 % de gros comptes, donc j'ai paginé la requête. Mais si le cas qu'il m'oppose n'existe ni dans nos données ni dans la roadmap, je le dis avec des chiffres : on préfère le simple aujourd'hui et on note la limite quelque part. J'accepte quand il y a des preuves, je défends quand les preuves sont de mon côté, et je n'en fais jamais quelque chose de personnel. »
- 03
Esquissez-moi dans les grandes lignes un système de raccourcissement d'URL (ou un fil d'actualité, un panier...). Par où commencez-vous ?
Commencez par les questions, pas par la solution : volume, lectures contre écritures, latence acceptable. Raisonnez les compromis à voix haute (cohérence contre disponibilité, où mettre du cache) plutôt que de réciter une architecture figée apprise par cœur.
Exemple de réponse « Avant de dessiner quoi que ce soit, je poserais trois questions : combien d'URL nouvelles par jour et combien de redirections ? peuvent-elles expirer ? l'analyse des clics compte-t-elle ? Supposons mille écritures et un million de lectures par jour : c'est un système de lectures, donc j'optimise de ce côté. Je générerais des codes de 7 caractères en base 62 à partir d'un compteur, avec des blocs pré-réservés par instance, pour éviter les collisions sans avoir à coordonner chaque requête. Je stockerais la correspondance dans une base clé-valeur et je placerais un cache devant, pour les 20 % d'URL qui concentrent 80 % du trafic. La redirection peut être cohérente à terme : si un lien met une seconde à se propager, ce n'est pas grave ; ça me permet de répliquer sans bloquer les écritures. »
- 04
Pourquoi avez-vous choisi [votre langage/framework principal] sur votre dernier projet, et quand aurait-ce été une mauvaise idée ?
Parlez de critères réels : écosystème, performance, l'équipe qui le maintiendra. Reconnaître quand ce n'était PAS le bon choix vaut mieux que de le défendre comme s'il était parfait pour tout.
Exemple de réponse « Sur mon dernier projet, j'ai choisi TypeScript avec Node parce que l'équipe maîtrisait déjà JavaScript, que le produit était une API avec beaucoup d'intégrations tierces et que le typage nous évitait les erreurs bêtes de contrats entre services. Ce n'était pas un choix de mode : j'ai tenu compte du fait qu'il serait facile de recruter et que l'écosystème offrait des bibliothèques mûres pour ce dont nous avions besoin. Quand aurait-ce été une mauvaise idée ? Si le cœur avait été du calcul intensif CPU, du traitement d'image ou quelque chose avec de fortes contraintes de mémoire : là, Node s'étouffe et je serais parti sur Go ou sur Python avec des extensions natives. D'ailleurs, un job de génération de PDF, on a fini par le sortir dans un worker séparé parce qu'il bloquait l'event loop. »
- 05
Vous devez ajouter une fonctionnalité à une partie du code que vous ne comprenez pas et que personne n'a documentée. Comment procédez-vous ?
Montrez une stratégie face au code hérité : lire les tests, tracer les entrées et les sorties, faire des changements petits et vérifiables. Mentionnez ce que vous refuseriez de toucher sans filet de sécurité.
Exemple de réponse « D'abord, je lis les tests, s'il y en a : c'est la seule documentation qui ne ment pas. S'il n'y en a pas, je trace le flux avec un cas réel : je pose des logs ou un débogueur à l'entrée et je suis les données jusqu'à la sortie, et je me dessine ainsi une carte de ce qui touche à quoi. Avant d'ajouter ma fonctionnalité, j'écris deux ou trois tests de caractérisation qui figent le comportement actuel, même s'il me paraît étrange : ce comportement peut être un contrat que quelqu'un attend. Ensuite, je fais le changement le plus petit possible et je vérifie que les tests restent au vert. Ce que je ne ferais pas, c'est refactorer en même temps que j'ajoute la fonctionnalité, ni toucher sans filet quelque chose qui manipule de l'argent ou des données d'utilisateurs : là, d'abord les tests, ensuite les changements. »
- 06
Parlez-moi d'une fois où vous avez pris un raccourci technique (une dette technique) volontairement. Comment l'avez-vous justifié ?
Faites bien comprendre que c'était une décision consciente, avec un coût connu, pas de la négligence. Expliquez ce que vous y avez gagné (un délai, valider une hypothèse), comment vous l'avez documenté et quel plan existait pour la rembourser.
Exemple de réponse « Pour valider une intégration avec un gros client, j'ai codé en dur sa configuration au lieu de construire le système de configuration par client qui s'imposait. Je l'ai décidé devant mon responsable : monter la version générique, c'était trois semaines, et le client décidait dans une. J'ai balisé le raccourci : un commentaire expliquant le pourquoi, un ticket dans le backlog avec la vraie solution estimée, et une alerte au cas où un autre client atteindrait ce code. Le client a signé, et au trimestre suivant nous avons remboursé la dette avec le système générique. Pour moi, la différence entre bonne et mauvaise dette, c'est ça : la bonne a une échéance, un responsable et un coût que quelqu'un a accepté à voix haute ; la mauvaise est celle qu'on découvre six mois plus tard par surprise. »
- 07
Différence entre deux choses qui se ressemblent dans votre stack (par ex. liste et dictionnaire, SQL et NoSQL, synchrone et asynchrone) : quand utilisez-vous chacune ?
Répondez par le quand, pas par la définition du manuel. Ancrez chaque option dans un cas d'usage et dans le coût que vous assumez (mémoire, latence, complexité). Si possible, citez une fois où vous avez mal choisi et où vous avez changé.
Exemple de réponse « SQL contre NoSQL, par exemple : ce n'est pas une guerre de religion, c'est une question sur vos données. Si elles ont des relations qui comptent (commandes, clients, factures) et que vous avez besoin de transactions, alors SQL, parce que les garanties vous sont fournies par la base et que vous n'avez pas à les réinventer dans le code. NoSQL, je l'utilise quand le schéma est mouvant ou que le volume de lectures simples est énorme : sessions, catalogues dénormalisés, événements. Le coût que vous assumez avec NoSQL, c'est que les questions que vous n'aviez pas prévues deviennent chères. Ça m'est arrivé : on a monté de l'analytique sur une base de documents et, six mois plus tard, chaque nouveau rapport était un calvaire ; on a migré cette partie vers Postgres et les requêtes sont passées d'heures de travail à un JOIN. »
- 08
Votre code passe en local mais échoue en production. Que vérifiez-vous en premier ?
Énumérez les suspects par ordre de probabilité : variables d'environnement, versions des dépendances, données réelles contre données de test, concurrence, fuseau horaire. L'important, c'est l'ordre de votre raisonnement, pas de deviner la cause exacte.
Exemple de réponse « Je procède par ordre de probabilité. D'abord, la configuration : des variables d'environnement manquantes ou qui pointent ailleurs, c'est la cause la plus fréquente et la moins coûteuse à vérifier. Ensuite, les données : en local, je teste avec des données propres, alors que la production a les cas tordus (valeurs nulles, accents, enregistrements de 2015). Troisièmement, les versions : le lockfile a-t-il été respecté au déploiement ? la version de Node ou de la base est-elle la même ? Quatrièmement, tout ce qui n'existe pas en local : concurrence réelle, latence réseau, permissions, fuseau horaire du serveur. Et pendant que je vérifie, je regarde les logs de l'erreur réelle en production au lieu de supposer : la moitié du temps, la stack trace vous dit déjà dans laquelle de ces quatre familles vous êtes. »
Beaucoup de ces questions sont du type « racontez-moi une fois où… ». Pour structurer ces réponses avec une histoire claire, utilisez la méthode STAR.
Conseils pour vous démarquer
- Pensez à voix haute pendant le coding. Le silence vous pénalise plus qu'une erreur : l'examinateur a besoin de voir votre raisonnement, pas seulement le résultat.
- Avant de coder, reformulez le problème et posez des questions sur les cas limites. Vous jeter sur le clavier sans clarifier les besoins est le signal d'alarme numéro un.
- Quand vous défendez une décision technique, nommez le compromis que vous avez accepté. « J'ai choisi X tout en sachant que Y » fait senior ; « X est mieux » fait junior.
- Préparez deux ou trois projets à raconter en détail : quel problème ils résolvaient, votre décision la plus difficile et ce que vous feriez autrement. C'est là que naît la moitié des questions de relance.
Entraînez-vous à un entretien pour programmeur / développeur logiciel
Collez votre CV et l'offre, puis parlez avec un recruteur IA qui adapte les questions à votre poste. Feedback honnête par compétences, sans carte bancaire.