Comment relever un challenge de programmation lors d'un entretien technique?

Comment relever un challenge de programmation lors d'un entretien technique?

Comme beaucoup de choses dans la vie, la maîtrise nécessite de la pratique et l'entretien technique ne fait pas exception. Souvent, cependant, l'accent est mis sur la recherche de la meilleure solution dès le départ plutôt que sur la démarche de résolution du problème posé.

La partie la plus importante, à mon humble avis, est de bien faire les choses en premier. Dans votre vie de tous les jours en tant que programmeur, vous ne seriez rarement, voire jamais, capable de produire un code «parfait» sans d'abord passer par un ensemble d'itérations.

L'approche lors de l'entretien de codage ne devrait pas différer et si elle est bien jouée, elle devrait vous aider à marquer des points inestimables pour démontrer vos compétences en résolution de problèmes.

Nous allons simuler une conversation entre vous et un recruteur si on vous demandait de résoudre le célèbre challenge FizzBuzz.

Le challenge

Écrire un programme qui imprime les nombres de 1 à 100. Mais pour les multiples de trois, imprimez Fizz au lieu du nombre et pour les multiples de cinq, imprimez Buzz. Pour les nombres qui sont des multiples de trois et cinq, imprimez FizzBuzz.

Le contexte

Le défi FizzBuzz n'est pas spécifique à JavaScript et fait partie du processus d'entretien technique dans presque tous les langages de programmation.

Il s'agit généralement d'une vérification rapide pour évaluer les instincts de programmation de base du candidat, mais peut également être transformé en une évaluation de connaissances approfondies si le recruteur décide de le faire.

Cela fait généralement partie d'un premier entretien technique léger réalisé lors du partage d'écran. C'est également un favori d'un programmeur non-JavaScript pour demander et évaluer rapidement vos connaissances techniques et votre approche.

Dans un contexte Javascript, il s'agit d'évaluer l'aisance du candidat avec les concepts suivants :

  • Opérateurs logiques

  • Boucles

  • Valeurs fausses
  • Opérateur conditionnel
  • Coercition de type

L'approche

Comme pour tous les problèmes que vous pourriez rencontrer, même ceux qui vous semblent familiers, une bonne lecture et une décomposition en petits morceaux sont indispensables. Dites clairement au recruteur que vous avez besoin de 3 à 5 minutes pour le lire calmement et proposez une réécriture de votre compréhension.

Si cela vous convient, lisez à voix haute, c'est encore mieux. Par exemple, voici comment je pourrais procéder pour la réécriture :

Alors il s'agit d'un registre de nombres de 1 à 100 - je vais avoir besoin d'une boucle Pour un multiple de 3 au lieu du nombre, mettre la chaîne « Fizz » Faire de même pour des multiples de 5 avec cette fois « Buzz » Dans le cas où le nombre est un multiple de 3 et 5, afficher « FizzBuzz » - comment vérifier si a est un multiple de b ? Si tous les cas ci-dessus échouent, afficher simplement le nombre tel quel Je demanderais probablement au recruteur si je devrais m'inquiéter des cas d'extrémité ou de mauvaises données d'entrée. Il est généralement implicite que l'entrée sera correcte et que les cas limites pourraient ne pas être nécessaires. Le fait que vous demandiez cependant ajoute une touche d'éloquence à votre approche de résolution de problèmes.

Les solutions possibles

L'une des choses les plus importantes est d'expliquer chaque étape de votre travail pendant que vous construisez la solution. Commencez par ce qui est évident. Vous aurez probablement besoin d'une fonction ou d'une classe comme structure principale. Commencez par là et pensez toujours au principe K.I.A.S.S.A.P :) — Keep It As Stupid Simple As Possible.

Première étape

// Les commentaires sont mes explications à haute voix
// Construisons une fonction principale
function fizzBuzz( start = 1, end = 100) { // Paramètres par défaut pour définir la plage par défaut
//J'ai besoin d'une boucle. Allons y
for( let i = start; i <= end; i++) {
// probablement une variable pour ce qui sera affiché
let output = i;
// Résultat logique
// Afficher le résultat
console.log(output);
}
}
// Nommer la fonction
fizzBuzz(); // cela imprime de 1 à 100 — jeu d'enfant ;)

Ce qui précède satisfait mon premier objectif sur ma compréhension du challenge réécrit.

Deuxième étape

Maintenant, si je suis la cadence du challenge, je vais résoudre deux choses :

  1. Choisir le bon opérateur pour trouver si un nombre est un multiple d'un autre

  2. L'appliquer pour la condition multiple de 3 et afficher « Fizz » L'opérateur de reste — %, est l'outil parfait ici. Si le nombre a est un multiple du nombre b alors

( b % a) === 0; // will be true;
// 4 is a multiple of 2
( 4 % 2 ) === 0; // is true

Appliquons cela à présent dans le corps de notre fonction

// rest of the logic here
if( (i % 3) === 0 ) {
output = ‘Fizz’;
}
// Knowing that 3,6 and 9 are multiple of 3 let’s
// quickly test a small sequence by calling
fizzBuzz(1,10);
// this should output
// 1, 2, ‘Fizz’, 4, 5, ‘Fizz’, 7, 8, ‘Fizz’, 10

Dernière étape

Puisque la condition Fizz s'est parfaitement déroulée, appliquons la même logique au reste.

// multiple of 5
if( (i % 5) === 0 ) {
output = ‘Buzz’;
}
// multiple of 3 and 5
if( (i % 3) === 0 && (i % 5 === 0)) {
output = ‘FizzBuzz’;
}

Waouh !! cela remplit toutes les conditions et nous donne ce chef-d'œuvre d'une solution une fois assemblée et débarrassée de tout commentaire.

function fizzBuzz( start = 1, end = 100) { 
    for( let i = start; i <= end; i++) {
        let output = i;
        if( (i % 3) === 0 ) {
            output = 'Fizz';
        }
        if( (i % 5) === 0 ) {
            output = 'Buzz';
        }
        if( (i % 3) === 0  && (i % 5) === 0) {
            output = 'FizzBuzz';
        }
        console.log(output);
    }
}
fizzBuzz();

Maintenant, à ce stade, j'ai une solution de travail qui résout le challenge. Ce qui suit est très délicat dans une situation d'entretien. Quelque chose me dérange dans mon code. Le dernier bloc if qui vérifie les multiples de 3 et 5 semble redondant. Dois-je maintenant exprimer cela à haute voix et proposer de le remanier ou dois-je attendre que le recruteur le remarque ? Les entretiens tiennent compte de la gestion du temps et la maximisation de vos avantages par rapport à vos inconvénients. Si vous vous sentez capables de proposer quelque chose de plus solide dans un temps raisonnable, alors allez-y. En cas de doute, attendez qu'on vous le demande. De cette façon, le recruteur peut décider que le reste de votre temps pourrait valoir la peine d'approfondir cette question. Si c'est le cas, il serait intéressant de se pencher sur un refactoring, cela pourrait être une façon d'aborder les étapes du refactoring.

Le refactoring

Nous pourrions, bien sûr, obtenir un one-liner sophistiqué ici pour ce challenge particulier, mais je ne suis pas particulièrement fan de faire des choses pour le plaisir ou la beauté.

Alors actionnons l'interrupteur, ce que je vais faire cette fois, c'est que je vais vous montrer ma solution finale et je vais vous expliquer comment j'y suis arrivé. Cela peut devenir une compétence pratique si vous devez lire et comprendre le code d'autres personnes ou si vous devez l'expliquer à quelqu'un d'autre. Au fil des années, j'ai proposé de nombreuses solutions à ce challenge, mais celle ci-dessous est de loin ma préférée.

function fizzBuzz( start = 1, end = 100) {
 for( let i = start; i <= end; i++) {
  let output = ( (i % 3) ? ‘’ : ‘Fizz’ ); // mult of 3 is falsy
  output += ( (i % 5) ? ‘’ : ‘Buzz’) ; // mult of 5 is falsy
  console.log(output || i); // output i if output is falsy
 }
}
fizzBuzz(1,15);

La solution utilise la syntaxe de l'opérateur ternaire pour définir les conditions et tire parti de quelque chose qui pourrait ne pas être très évident au premier abord pour un œil non averti : les valeurs fausses en JavaScript.

Commençons par les valeurs fausses en JavaScript, de quoi diable parlons-nous. Une excellente définition est fournie par le Mozilla Developer Network (MDN) : Une valeur fausse est une valeur considérée comme fausse lorsqu'elle est rencontrée dans un contexte booléen.

JavaScript utilise la conversion de type pour contraindre n'importe quelle valeur à un booléen dans les contextes qui l'exigent, tels que les conditions et les boucles.

Dans le contexte qui est le nôtre, les mots clés importants sont « contexte booléen » et « conditionnels » car ils sont pertinents pour notre solution. Avant de voir comment cela s'applique, voici la liste des valeurs fausses les plus courantes en Javascript :

  • Le booléen false n'est pas le même que la chaîne 'false'

  • Le nombre 0 - encore une fois, c'est différent de la chaîne '0'

  • L'objet nul

  • Le type primitif indéfini affecté à une variable non initialisée

  • Toute représentation d'une chaîne vide telle qu'un guillemet simple, des guillemets doubles ou des contre-ticks.

La réécriture

Concentrons-nous sur un segment de notre fonction fizzBuzz

if( (i % 3) === 0 ) {
 output = ‘Fizz’;
}
// this could be refactored as
if( !(i % 3) ) output = ‘Fizz’;

La décomposition de la ligne refactorisée nous donne cette image if (…) ==> construction conditionnelle à l'extérieur — contexte booléen à l'intérieur ! ==> est faux (i % 3) ==> type coercion — vérifiera si la valeur est fausse ou vraie Remplacez i par quelques chiffres pour mieux le comprendre.

if (!( 1 % 3))
/*becomes if (!( 3 )) /*3 is not false or falsy so check fails*/
if (!( 2 % 3))
/*becomes if (!( 6 )) /*6 is not false or falsy so check fails*/
if (!( 3 % 3))
/*becomes if (!( 0 )) /*0 is not false but is falsy so check passes*/

Je peux réécrire maintenant toute ma fonction en utilisant la logique ci-dessus

function fizzBuzz( start = 1, end = 100) {
 for( let i = start; i <= end; i++) {
  let output = i;
  if( !(i % 3) ) output = ‘Fizz’;
  if( !(i % 5) ) output = ‘Buzz’;
  if( !(i % 3) && !(i % 5) ) output = ‘FizzBuzz’;
  console.log(output);
 }
}

J'étais assez extatique quand je suis arrivé à cette solution, mais cela n'a malheureusement pas duré trop longtemps. La dernière ligne était toujours redondante pour moi et me dérangeait honnêtement. Comment combiner les chèques 3 et 5 en un seul passage ? Et puis ça m'a frappé, et si je pouvais commencer par une chaîne vide, y attacher le mot "Fizz" s'il passe la condition 3 et attacher le mot "Buzz" s'il passe aussi la condition 5. j'ai dessiné ça sur un bout de papier i = 1 ==> pas de Fizz '' ==> pas de Buzz '' ==> la sortie est 1 i = 3 ==> oui ‘Fizz’ ==> non Buzz ‘’ ==> la sortie est ‘Fizz’ i = 5 ==> non Fizz '' ==> oui 'Buzz' ==> la sortie est 'Buzz' i = 15 => oui ‘Fizz’ ==> oui ‘Buzz’ ==> la sortie est ‘FizzBuzz

L'opérateur ternaire permettra d'attribuer une valeur si la condition est vérifiée et une valeur alternative si elle échoue de manière très laconique.

Quelque chose d'autre est devenu évident, nous sortons soit une chaîne soit un nombre pendant que nous parcourons les valeurs de i et comme nous l'avons vu dans une section précédente, une chaîne vide est une valeur fausse. Alors, comment traduisons-nous toute cette intelligence en code fonctionnel ?

L'élément essentiel pour y parvenir était que la valeur de sortie allait soit être l'une des chaînes possibles « Fizz », « Buzz », « FizzBuzz » ou être fausse. Dans le cas faux, je serai simplement transmis tel quel.

Donc la réécriture finale avec plus de commentaires

function fizzBuzz( start = 1, end = 100) {
 for( let i = start; i <= end; i++) {
  // output is assigned a value or empty
  let output = ( (i % 3) ? ‘’ : ‘Fizz’ );
  // output concatenates the next value
  output += ( (i % 5) ? ‘’ : ‘Buzz’) ;
  // || or operator if output is falsy will show i value
  console.log(output || i);
 }
}
fizzBuzz(1,15);

J'espère que vous avez suivi tout cela :) C'était une solution très satisfaisante pour moi car je pense qu'elle était facile à lire, qu'elle a résolu le problème et qu'elle contenait une touche de JavaScript intéressante.

Pour finir

L'exercice de code ne couvre qu'un aspect des nombreuses choses qui se produisent pendant un entretien technique pour un développeur. Comme je l'ai mentionné, il faut une solide quantité de pratique pour produire un résultat quelle que soit la complexité du problème. N'hésitez pas à utiliser des simulations d'entretiens (nous vous proposerons bientôt d'autres modèles) pour davantage de pratique. Si cela vous a plu, partagez et laissez-un commentaire :)