L'ingénieur logiciel
- Page 5
- 18 min
- Partie 3 : Cinq candidatures, un seul poste
Page 5 sur 9 · Entrevues : Ingénieur de donnéesL'ingénieur logiciel
1. Lire l'offre d'emploi
2. Le déroulement des entrevues
3. Cinq candidatures, un seul poste
4. Préparer votre propre entrevue
Imaginez un très bon plombier qui se joint à l’équipe de conception d’un bâtiment. Il sait exactement comment l’eau circule, où les tuyaux fuient et ce qui arrive quand deux robinets s’ouvrent en même temps. Mais les architectes posent d’autres questions : qui habite cette pièce, et comment l’utilise-t-on? Le plombier n’a pas tort. Il regarde une autre partie du bâtiment.
Les ingénieurs backend (côté serveur) qui passent à l’ingénierie de données sont souvent comme ce plombier. Ils exploitent des services en production depuis des années. Ils connaissent les nouvelles tentatives, les défaillances et les doublons mieux que la plupart des spécialistes des données. La nouveauté, c’est la personne au bout du pipeline : un analyste ou un scientifique des données qui pose des questions avec SQL. Cette personne a besoin de tables faciles à comprendre et à interroger, pas seulement correctes.
Lukas est ce candidat. Observez à quelle vitesse il repère les problèmes de fiabilité dans le pipeline de Tidewell. Puis observez ce qui arrive quand Esther l’interroge sur les personnes qui utiliseront les données.
La personne candidate
Lukas Becker
Ingénieur backend, 6 ans dans les paiements, en transition vers l'ingénierie de données
- 6 ans en backend Java
- Paiements
- Au Canada depuis 3 ans
- Vancouver
- Ingénieur logiciel principal, Larchmont Payments (Vancouver, de 2023 à aujourd’hui). Java 21, Spring Boot, PostgreSQL, Kafka. Paiements par carte pour environ 2 000 commerçants.
- Création du traitement quotidien de rapprochement des règlements : compare les fichiers de règlement bancaires à notre grand livre, environ 600 000 transactions par jour. Idempotent dès sa conception.
- Direction de la correction des versements en double aux commerçants après des délais d’attente dépassés de l’API bancaire : clés d’idempotence et modèle outbox (boîte d’envoi). Aucun versement en double depuis.
- Ingénieur logiciel, Spreewerk Zahlungen (Berlin, de 2020 à 2023). API de paiement, consommateurs Kafka, PostgreSQL.
- Création de pipelines de données avec Kafka et Spring Batch.
- Compétences : Java, Kotlin, Spring, PostgreSQL, Kafka, Docker, Kubernetes, SQL, Python (notions de base).
Ce qu’Esther voit avant l’appel
Section intitulée « Ce qu’Esther voit avant l’appel »Esther lit le CV deux fois. Elle aime voir l’expression « idempotent dès sa conception ». L’histoire des versements évoque un vrai problème vécu en production. Elle s’attend à ce que Lukas maîtrise les réexécutions et les doublons.
Mais la phrase « création de pipelines de données avec Kafka et Spring Batch » peut vouloir dire beaucoup ou très peu. Déplacer des données entre services n’est pas la même chose que construire des tables pour les analystes. Ses questions :
- L’affirmation « idempotent dès sa conception » résiste-t-elle aux questions concrètes : corrections, réexécutions, fichiers qui changent?
- Pense-t-il aux personnes qui interrogent les données, ou seulement à leur déplacement?
- Peut-il modéliser l’historique, par exemple quel compte avait quel compteur à quelle date?
Termes utilisés sur cette page
Section intitulée « Termes utilisés sur cette page »- Idempotent : vous pouvez exécuter le traitement deux fois, ou dix fois, et obtenir le même résultat qu’après une seule exécution.
- Clé d’idempotence : identifiant unique envoyé avec une requête. Il permet au serveur de reconnaître une requête répétée sans refaire le travail.
- Clé naturelle : les colonnes qui identifient une chose réelle, par exemple l’identifiant du compteur et l’heure du relevé.
- Livraison au moins une fois : chaque message arrive, mais certains peuvent arriver plusieurs fois. Le système qui les lit doit gérer les doublons.
- Granularité : ce que représente une ligne dans une table. Par exemple, « un relevé d’un compteur à un instant donné, par intervalles de 15 minutes ».
- Table de faits et table de dimensions : une table de faits contient des événements ou des mesures (relevés). Une table de dimensions décrit des choses (comptes, compteurs). Les analystes les joignent.
- SCD de type 2 (dimension à évolution lente, type 2) : table qui conserve chaque version d’un enregistrement, avec un début et une fin.
- Fonction de fenêtrage : fonction SQL qui examine d’autres lignes proches de la ligne courante, par exemple le relevé précédent du même compteur (
LAG). - dbt : outil qui transforme des instructions SQL SELECT en tables dans l’entrepôt de données, avec des tests et de la documentation.
L’entrevue
Section intitulée « L’entrevue »Minutes 0 à 5 : l'ouverture
Esther(intervieweur) :
Bonjour Lukas. Je suis Esther, ingénieure de données principale dans l’équipe plateforme. Il est 16 h, c’est mon troisième appel aujourd’hui. Alors si je suis lente, c’est moi, pas vous. Bon, le plan. Vous me parlez d’un pipeline que vous avez construit, et je pose beaucoup de questions. Ensuite, notre vrai problème. Puis vos questions. Pas d’outils d’IA pour cette étape. Le papier, ça va, et je vais dessiner au tableau.
Lukas(personne candidate) :
Rit. D’accord, pas de problème. J’ai du papier ici.
Minutes 5 à 25 : le pipeline, puis l'approfondissement
Esther(intervieweur) :
Alors, un pipeline que vous avez construit ou dont vous êtes responsable.
Lukas(personne candidate) :
Oui. Le rapprochement des règlements chez Larchmont. Donc, chaque nuit, les banques nous envoient un fichier, un fichier de règlement. Il indique quels paiements par carte elles ont vraiment versés, et les frais. On doit vérifier que ça correspond à notre grand livre. Chaque paiement dans notre grand livre doit être dans le fichier, avec le même montant.
Le traitement commence vers 3 h. Il télécharge le fichier, l’analyse, l’écrit dans une table de préparation dans Postgres. Ensuite, il fait le rapprochement avec la référence bancaire. Ce qui ne correspond pas va dans une table, et l’équipe des opérations regarde ça le matin. Combien de lignes… environ 600 000 par jour, je pense. Au Vendredi fou, plus, peut-être un million.
Esther(intervieweur) :
D’accord. Et qu’est-ce qui arrive s’il s’exécute deux fois?
Lukas(personne candidate) :
Rien. C’est la première chose que j’ai conçue. Chaque ligne a la référence bancaire, et il y a une contrainte d’unicité dessus. On insère avec « on conflict do nothing ». Donc une deuxième exécution insère zéro ligne. Le rapprochement est sûr aussi, il met seulement le statut à jour.
Esther(intervieweur) :
Et si la banque envoie un fichier corrigé? Même jour, mêmes références, montants différents.
Lukas(personne candidate) :
Pause. Alors « do nothing » garde les anciens montants. Hmm. C’est pas bon. Les banques envoient les corrections dans un autre type de fichier, les ajustements. Donc en pratique, on ne voit pas ça. Mais si une banque renvoie le même fichier avec de nouveaux montants, on garde les mauvais. Honnêtement, je n’y avais pas pensé.
Esther(intervieweur) :
Ça va. Quel a été le pire incident avec ce traitement?
Lukas(personne candidate) :
Le changement de format. Une banque a ajouté une colonne dans le fichier, au milieu. Sans nous le dire. Notre analyseur lisait par position. Donc après la nouvelle colonne, chaque valeur était décalée d’une colonne vers la droite. Les frais allaient dans le montant. Et on l’a trouvé… pas vite. Le traitement était au vert. Deux jours plus tard, l’équipe des opérations a dit : « On a 40 000 écarts, quelque chose ne va pas. » Après ça, j’ai ajouté deux vérifications. L’analyseur vérifie les noms des en-têtes, pas la position. Et le fichier a une dernière ligne avec le nombre total et le montant total. On compare ça. Si c’est différent, le traitement échoue, avec une alerte bien visible.
Esther(intervieweur) :
Qui utilise les résultats du rapprochement? À part les opérations.
Lukas(personne candidate) :
Les finances, parfois. Ils demandent : « Combien d’écarts par banque au dernier trimestre? » Alors j’écris une requête et je leur envoie un CSV. Peut-être une fois par mois, c’est pas beaucoup de travail.
Minutes 25 à 50 : le problème de Tidewell
Esther(intervieweur) :
D’accord, maintenant notre vrai problème. Nos compteurs envoient un relevé toutes les 15 minutes. Parfois, un compteur perd sa connexion réseau et les relevés arrivent en retard, jusqu’à trois jours plus tard. Notre traitement nocturne lit les données selon leur date d’arrivée. Le mois dernier, après un échec, on a relancé le traitement et un client a été facturé deux fois. Et l’équipe de prévision dit qu’il manque des données dans son historique. Comment concevriez-vous le pipeline des relevés pour que ça ne se reproduise pas?
Lukas(personne candidate) :
D’accord. Ma première question, c’est : qu’est-ce qui arrive s’il s’exécute deux fois?
Esther(intervieweur) :
Rit. C’est ma question. Vous me l’avez prise.
Lukas(personne candidate) :
Désolé! Donc, la nouvelle exécution a ajouté les mêmes relevés encore une fois. On doit pouvoir relancer chaque étape sans risque. Un relevé a une clé naturelle : l’identifiant du compteur et l’heure du relevé. Pas l’heure d’arrivée. Si chaque écriture utilise cette clé, une deuxième exécution ne peut pas créer un deuxième relevé.
Esther(intervieweur) :
D’accord. Écrire comment? On a des tables Delta. Delta a MERGE : trouver par clé, mettre à jour si elle existe, insérer sinon.
Lukas(personne candidate) :
Comme « on conflict » dans Postgres, d’accord. Alors MERGE sur l’identifiant du compteur plus l’heure du relevé. Et avant le MERGE, enlever les doublons dans les nouvelles données. Parce que Kafka garantit une livraison au moins une fois. Donc le même relevé peut arriver deux fois dans un lot.
Esther(intervieweur) :
Et les relevés en retard? Trois jours de retard.
Lukas(personne candidate) :
Le traitement ne doit pas seulement demander « qu’est-ce qui est arrivé hier ». Il demande : quelles dates de relevé sont dans les nouvelles données? Ensuite, il met ces jours à jour. Donc un relevé du lundi qui arrive jeudi va dans le lundi.
Esther(intervieweur) :
Bien. Maintenant, je veux savoir comment vous construiriez ça. Dessinez-moi les blocs.
Lukas(personne candidate) :
J’écrirais un service. Java, un consommateur Kafka. Il lit les relevés, les vérifie, enlève les doublons et écrit dans la base de données avec l’upsert. Ensuite, la facturation appelle une API sur ce service : donnez-moi la consommation pour ce compte, de cette date à cette date. La base de données, c’est Postgres, avec des partitions par… La vidéo fige pendant quelques secondes.
Esther(intervieweur) :
Désolée, Lukas, votre image a figé. La dernière chose que j’ai entendue, c’est « Postgres, avec des partitions ».
Lukas(personne candidate) :
Ah, désolé. C’est mieux maintenant? Postgres avec des partitions par mois. Mais attendez, je vais compter. 115 millions par jour, fois 365… ça fait environ 42 milliards de lignes par année. Hmm. C’est trop pour notre Postgres. Peut-être quelque chose de plus gros.
Esther(intervieweur) :
On a déjà Spark, des tables Delta et dbt. Pourquoi ne pas les utiliser?
Lukas(personne candidate) :
Je peux utiliser Spark. Mais dbt, c’est du SQL avec des gabarits, non? Je préfère du vrai code. Je peux écrire des tests unitaires, le réviser, le déboguer.
Esther(intervieweur) :
dbt a des tests aussi. Des tests de données, et des tests unitaires depuis la version 1.8. Et l’équipe de prévision et les analystes peuvent lire du SQL. Peuvent-ils lire votre Java?
Lukas(personne candidate) :
Pause. Non. D’accord, c’est un bon point. Je n’ai pas pensé à qui le lit.
Esther(intervieweur) :
D’accord. Alors les relevés nettoyés sont dans une table. Comment les analystes vont-ils consommer ces données?
Lukas(personne candidate) :
Chaque équipe a son propre groupe de consommateurs. Alors chaque équipe lit le sujet à sa vitesse, et…
Esther(intervieweur) :
Désolée, j’ai mal choisi mon mot. « Consommer » est aussi un mot de Kafka. Je parle des personnes. Un analyste qui écrit du SQL dans l’entrepôt de données. Qu’est-ce qu’il voit?
Lukas(personne candidate) :
Ah, d’accord. Il voit la table des relevés. L’identifiant du compteur, l’heure du relevé, la valeur en kWh. Une ligne, c’est un relevé. Un compteur, un moment à intervalle de 15 minutes.
Esther(intervieweur) :
Bien, c’est la granularité. Maintenant, l’analyste demande : consommation totale par compte par mois, sur deux ans. Où est le compte?
Lukas(personne candidate) :
J’ajouterais l’identifiant du compte au relevé quand il arrive. Je le cherche dans le CRM, et je l’écris dans la ligne. Ensuite, la requête est simple, on regroupe par compte et par mois.
Esther(intervieweur) :
Deux problèmes. Quand on remplace un compteur, le CRM change, et il garde seulement l’état actuel. Et parfois, le CRM est erroné, et on le corrige une semaine plus tard.
Lukas(personne candidate) :
Hmm. Alors les anciennes lignes ont le mauvais compte. Je dois les mettre à jour… Des millions de lignes, chaque fois que quelqu’un corrige le CRM. C’est pas idéal. Laissez-moi réfléchir. Pause. Dans les paiements, les commerçants changent de forfait de frais. On garde chaque forfait avec « valide du » et « valide au ». Donc ici aussi : une table avec compteur, compte, début de validité, fin de validité. Alors le relevé ne contient pas le compte. On fait la jointure au moment de la requête, selon l’heure.
Esther(intervieweur) :
Oui. Ça s’appelle une dimension à évolution lente, de type 2. Pouvez-vous décrire la jointure?
Lukas(personne candidate) :
D’accord, je connaissais l’idée, pas le nom. Donc, jointure entre les relevés et les liens sur l’identifiant du compteur. Et l’heure du relevé entre le début et la fin de validité.
Esther(intervieweur) :
Le remplacement a lieu à exactement 10 h, et l’ancien lien se termine à 10 h. Le nouveau commence à 10 h. Où va le relevé de 10 h?
Lukas(personne candidate) :
BETWEEN inclut les deux limites… donc il va dans les deux comptes. Double comptage. Alors supérieur ou égal au « début », et inférieur à la « fin ». La fin n’est pas incluse.
Esther(intervieweur) :
Une dernière sur SQL. L’équipe de prévision veut trouver les lacunes : les périodes sans relevé pendant plus d’une heure pour un compteur. Comment?
Lukas(personne candidate) :
Je lirais les relevés par compteur, dans l’ordre, avec du code, et je comparerais chacun au précédent.
Esther(intervieweur) :
Pour 1,2 million de compteurs?
Lukas(personne candidate) :
D’accord, en SQL. Regrouper par compteur et par jour, compter, et garder ceux où le nombre est inférieur à 96. Ah, mais ça dit seulement combien il en manque, pas où. Alors… une autojointure? Chaque relevé avec celui de 15 minutes avant. Et là où il n’y en a pas, c’est le début d’une lacune.
Esther(intervieweur) :
Ça fonctionne. Il y a plus simple. Connaissez-vous les fonctions de fenêtre?
Lukas(personne candidate) :
LAG, je pense? Je l’ai vu. Je ne l’ai jamais utilisé, honnêtement. Dans mon travail, la base de données servait à l’application, pas à des questions comme ça.
Esther a ensuite posé deux courtes questions. La facturation a-t-elle besoin de traitement en continu? Lukas a dit non : elle s’exécute une fois par jour, et l’exactitude compte plus que la vitesse. Dans les paiements, a-t-il dit, le règlement se fait aussi une fois par jour. Pour l’assistant d’IA du service à la clientèle, le filtre de compte doit être dans la couche d’accès aux données. Pas dans la requête (prompt) de l’assistant. « Le modèle ne doit pas pouvoir demander un autre compte. Pas “ne devrait pas”. Ne doit pas. » Esther a noté cette phrase.
Puis elle a demandé combien de temps attendre les relevés en retard. Lukas a dit que c’est une décision d’affaires, comme l’heure limite bancaire dans les paiements : « La facturation doit dire combien de temps elle attend. Après ça, il faut une estimation, et une correction sur la prochaine facture. » Esther était d’accord.
Minutes 50 à 57 : les questions de Lukas
Lukas(personne candidate) :
J’ai deux questions. D’abord, le fournisseur de compteurs. Comment les relevés passent-ils de son système à Kafka? Qui est responsable de cette partie?
Esther(intervieweur) :
Bonne question. Le système central de collecte est vieux, et le fournisseur change le format d’exportation sans nous prévenir, comme votre banque. L’intégration, c’est moitié nous, moitié l’équipe d’infrastructure de la plateforme. Honnêtement, c’est pas clair, et ça tombe en panne.
Lukas(personne candidate) :
D’accord. Ça ressemble à mon fichier bancaire. Deuxième question : quelle part du travail est en SQL et dbt, et quelle part est du code, comme les traitements Spark?
Esther(intervieweur) :
La majorité, c’est SQL et dbt. Je dirais 70 %, peut-être plus. Spark pour la couche brute et les gros chargements de données historiques. Un peu de Python pour Airflow.
Minutes 57 à 60 : la conclusion
Esther(intervieweur) :
Merci, Lukas. Vous avez facilité ma question « s’exécute deux fois » aujourd’hui. Aisha vous écrira pour les prochaines étapes.
Lukas(personne candidate) :
Merci. Et je vais regarder LAG ce soir.
Après l’appel : les notes d’Esther
Section intitulée « Après l’appel : les notes d’Esther »Lukas Becker, approfondissement de la conception de pipelines
- Pipelines idempotents, nouvelles exécutions, doublons : preuves solides. A soulevé « s’exécute deux fois » avant moi. Clé naturelle, MERGE, déduplication du lot, livraison au moins une fois par Kafka. A trouvé lui-même la lacune de son « do nothing on conflict » face aux corrections.
- Données en retard : preuves solides. Reconstruire selon la date du relevé, pas la date d’arrivée. Le délai d’attente est une décision d’affaires.
- Production et incidents : preuves solides. Changement de format bancaire : vérification des en-têtes et totaux de contrôle. Très proche de notre problème de système central de collecte.
- Modélisation des données pour l’analyse : quelques preuves. A trouvé la granularité avec de l’aide. A trouvé le principe des périodes de validité grâce aux forfaits de frais; ne connaissait pas le nom SCD de type 2; a repéré l’erreur de limite quand je l’ai questionné.
- SQL analytique : préoccupation. Première réponse en code, pas en SQL. Connaît LAG seulement de nom.
- Choix des outils : préoccupation. Première conception avec un nouveau service Java et Postgres, à côté d’une plateforme Spark et dbt existante. Il a écouté quand j’ai demandé qui lit le code.
Recommandation : non pour ce rôle. Environ 70 % du travail est en SQL et dbt pour les analystes, et c’est son point faible aujourd’hui. Mais c’est un ingénieur solide, et l’intégration du système central de collecte demande exactement ses compétences : changements de format, validation, nouvelles tentatives, relances sûres. J’aimerais que Graham parle à l’équipe d’infrastructure de la plateforme.
Ce qui s’est passé ensuite
Section intitulée « Ce qui s’est passé ensuite »L’étape de modélisation avec Pierre a confirmé l’avis d’Esther : de bons instincts, mais les schémas en étoile et la granularité étaient nouveaux pour Lukas. Au bilan, Graham a décidé de ne pas poursuivre pour le poste d’ingénieur de données.
Mais Graham n’a pas envoyé seulement un « non ». Il a appelé Lukas lui-même. Il a expliqué la décision en deux phrases : le rôle consiste surtout en modélisation analytique avec SQL et dbt. Ce n’est pas encore son point fort. Ensuite, il a demandé si Lukas accepterait de parler à l’équipe d’infrastructure de la plateforme. Elle est responsable du backend (partie serveur) pour l’intégration du système central de collecte des compteurs. Elle avait un poste ouvert d’ingénieur backend principal. Les notes d’Esther accompagnaient la recommandation.
Lukas a dit oui. Une semaine plus tard, il passait une première entrevue avec cette équipe. Son récit du fichier bancaire a été leur première question.
Ce n’est pas un échec. L’entrevue a montré ce que Lukas fait bien et a trouvé une équipe où ces compétences comptent le plus. Un « non » honnête avec une raison claire l’a aidé davantage qu’un refus vague.
Ce qu’il faut retenir
Section intitulée « Ce qu’il faut retenir »- Vos anciennes habitudes peuvent être vos meilleures réponses. « Que se passe-t-il si le traitement s’exécute deux fois? » Cette question venait naturellement à Lukas grâce à son expérience des paiements. Utilisez les questions de fiabilité de votre ancien domaine.
- Partez de ce que l’entreprise possède. Avant de concevoir un nouveau service, demandez ce que l’équipe utilise déjà. Ensuite, expliquez pourquoi vous ajouteriez quelque chose de nouveau, si c’est votre choix.
- Les données ont des lecteurs. En ingénierie de données, les analystes et les scientifiques des données utilisent directement vos tables. Pensez à la granularité, aux noms et aux jointures qu’ils écriront.
- Raisonnez à partir des modèles que vous connaissez. Lukas ne connaissait pas les « dimensions à évolution lente de type 2 ». Mais il connaissait les plans tarifaires avec des dates de validité. Décrivez le modèle dans vos propres mots. La personne qui mène l’entrevue peut vous donner son nom.
- Un « non » peut mener à un autre poste. Dites clairement quels sont vos points forts. Une bonne entreprise pourra alors voir où vous avez votre place, même si ce n’est pas le poste visé.
Si votre profil ressemble à celui de Lukas
Section intitulée « Si votre profil ressemble à celui de Lukas »- Apprenez la modélisation dimensionnelle. Renseignez-vous sur la granularité, les tables de faits et les tables de dimensions. Ensuite, prenez votre propre système, par exemple les paiements, et dessinez un schéma en étoile pour une question d’affaires. Décrivez à voix haute la granularité de chaque table.
- Exercez-vous aux fonctions de fenêtrage jusqu’à ce qu’elles deviennent naturelles.
ROW_NUMBERpour la déduplication,LAGpour les écarts, les totaux cumulés avecSUM() OVER. Commencez par Le temps et le classement, puis résolvez chaque problème d’abord en SQL, pas en code. - Créez un petit projet dbt. Prenez un jeu de données public. Écrivez des modèles de préparation et de magasin de données, un modèle incrémental avec une clé unique, et des tests. Exécutez le projet deux fois et vérifiez que rien ne change. Vous aurez ainsi une réponse à la question « pourquoi pas dbt? ».
- Exercez-vous à conserver l’historique dans les tables. Créez une table de dimensions à évolution lente de type 2 pour un sujet connu, comme les plans tarifaires ou les prix. Testez la jointure au moment exact du changement.
- Gardez vos exemples de fiabilité prêts. Votre incident de changement de format et votre correction d’idempotence sont des exemples solides. Racontez-les avec des chiffres et dites ce que la correction ne couvre toujours pas. Consultez Expliquer vos décisions.
- Avant de postuler, demandez quelle part du travail se fait en SQL. Si le poste porte surtout sur la modélisation pour l’analyse, préparez-vous d’abord à cela. S’il porte sur l’intégration et les services, un poste en plateforme de données ou en backend vous conviendrait peut-être mieux aujourd’hui.