MFormations
Modern Frontend Engineering

Chapitre 23

Chapitre 23 — Préparation aux Entretiens Techniques

Chapitre 23 — Préparation aux Entretiens Techniques

Chapitre 23 — Interviews : Cours Complet

1. Questions Comportementales (30 Questions — Méthode STAR)

1.1 La Méthode STAR

S — Situation : Contexte (projet, équipe, délais)
T — Task : Objectif ou défi spécifique
A — Action : Ce que VOUS avez fait (pas l'équipe)
R — Result : Résultat mesurable (chiffres, feedback, livrables)

Règle d'or : 70% sur l'Action, 15% Situation, 15% Result. Une réponse STAR dure 2-3 minutes.

1.2 Questions de Leadership et Initiative (6)

Q1 : Parle-moi d'un moment où tu as pris l'initiative sur un projet.

  • STAR attendu : "Notre design system n'avait pas de composant DatePicker. J'ai proposé d'en créer un en m'inspirant de Radix UI. J'ai implémenté le composant avec tests et documentation. Adopté par 3 équipes en 2 mois, réduisant le temps de développement formulaire de 40%."

Q2 : Décris une situation où tu as introduit un nouveau processus ou outil.

  • STAR attendu : "L'équipe n'avait pas de code review. J'ai proposé d'instaurer des PRs avec checklist. J'ai configuré GitHub branch protection et écrit un template de PR. En 3 mois, les bugs en production ont diminué de 60%."

Q3 : Comment as-tu géré un désaccord technique avec un collègue ?

  • STAR attendu : "Un collègue voulait Redux, je préférais Zustand. On a fait un proof-of-concept de 2 jours chacun. Résultat : Zustand était 3x plus simple pour notre cas. On a présenté les deux approches à l'équipe et voté."

Q4 : Raconte un projet que tu as mené de A à Z.

  • STAR attendu : "J'ai développé un dashboard analytics de zéro. J'ai choisi Next.js + D3.js. Implémenté le responsive, les exports PDF, et les filtres temps réel. Livré en 3 semaines, utilisé par 200 utilisateurs internes."

Q5 : As-tu déjà dû convaincre ta hiérarchie d'adopter une technologie ?

  • STAR attendu : "J'ai proposé de migrer de Webpack à Vite. J'ai fait une présentation avec benchmarks : build 10x plus rapide, HMR instantané. La migration a pris 1 semaine pour 15 modules. L'équipe a gagné 30min/jour."

Q6 : Décris une contribution open-source ou un side project.

  • STAR attendu : "J'ai contribué à React Testing Library en ajoutant un nouveau query selector. J'ai suivi le processus de contribution (issue, PR, review). La feature a été mergée et utilisée par des milliers de développeurs."

1.3 Questions de Travail d'Équipe (6)

Q7 : Parle d'un conflit dans ton équipe et comment il a été résolu. Q8 : Décris la meilleure équipe dans laquelle tu as travaillé. Q9 : Comment fais-tu pour onboarder un nouveau développeur ? Q10 : Que fais-tu si un membre de l'équipe ne livre pas à temps ? Q11 : Comment gères-tu les code reviews ? Donne un exemple concret. Q12 : As-tu déjà dû travailler avec des non-techniques ? Comment ?

1.4 Questions d'Échec et Apprentissage (6)

Q13 : Décris un échec technique et ce que tu en as appris.

  • STAR attendu : "J'ai déployé une migration de base de données sans rollback plan. Les données ont été corrompues. J'ai passé la nuit à les restaurer. J'ai mis en place : backups automatiques, migration scripts testés en staging, feature flags."

Q14 : Parle d'un bug critique que tu as causé en production. Q15 : Quelle est la décision technique que tu regrettes le plus ? Q16 : As-tu déjà sous-estimé la complexité d'une tâche ? Q17 : Qu'as-tu appris d'un projet qui a échoué ? Q18 : Comment gères-tu le feedback négatif sur ton code ?

1.5 Questions de Priorisation et Gestion du Temps (6)

Q19 : Comment gères-tu plusieurs priorités concurrentes ? Q20 : Décris un projet avec des délais irréalistes. Q21 : Comment décides-tu ce qui est prioritaire dans une tâche ? Q22 : Parle d'un moment où tu as dit "non" à une fonctionnalité. Q23 : Comment gères-tu la dette technique et les features ? Q24 : Que fais-tu quand tu es bloqué sur un problème ?

1.6 Questions de Vision et Carrière (6)

Q25 : Où te vois-tu dans 5 ans ? Q26 : Pourquoi veux-tu travailler ici plutôt qu'ailleurs ? Q27 : Quelle est ta plus grande force en tant que développeur ? Q28 : Quelle est ta plus grande faiblesse (et comment l'adresses-tu) ? Q29 : Qu'est-ce qui te motive dans le développement front-end ? Q30 : As-tu des questions pour nous ? (toujours en préparer 3-5)

1.7 Grille d'Évaluation — Comportemental

Critère1 (Faible)2 (Moyen)3 (Bon)4 (Excellent)
Structure STARPas de structureSTAR partielSTAR clairSTAR + métriques
ConcrétudeGénéralitésUn exemple vagueExemple détailléChiffres + impact
Rôle personnel"On a fait"Partiellement actifRôle clairLeader reconnu
RéflexionPas d'apprentissageApprentissage superficielLeçon appriseChangement systémique
HonnêtetéÉvite les échecsMinimiseAssumeVulnérabilité constructive

2. Questions Techniques (20 Questions)

2.1 JavaScript (8 questions)

Q31 : Explique les closures. Donne 3 cas d'usage concrets en front-end.

Réponse attendue :

// Closure = fonction + son scope lexical
function createLogger(prefix) {
  return (msg) => console.log(`[${prefix}] ${msg}`);
}

// Cas d'usage :
// 1. Event handlers avec contexte
function attachHandler(id) {
  document.getElementById(id).addEventListener('click', () => {
    console.log(`Clicked ${id}`); // closure sur id
  });
}

// 2. Custom React hooks
function useCounter(initial = 0) {
  const [count, setCount] = useState(initial);
  const increment = useCallback(() => setCount(c => c + 1), []);
  return { count, increment };
}

// 3. Debounce/throttle
function debounce(fn, delay) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
}

Q32 : Quelle est la différence entre == et === ? Donne des exemples de coercion.

Réponse attendue :

// === : pas de coercion (recommended)
1 === '1'   // false
0 === false // false
null === undefined // false

// == : coercion de type
1 == '1'   // true (string → number)
0 == false // true (boolean → number)
null == undefined // true (règle spéciale)
[] == false // true ([] → '' → 0, false → 0)

// Pièges à connaître :
'' == 0     // true
'\n' == 0   // true
[] == ![]   // true (!!)

Q33 : Explique l'Event Loop. Que va afficher ce code ?

console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
queueMicrotask(() => console.log('4'));
requestAnimationFrame(() => console.log('5'));
console.log('6');
// Réponse : 1, 6, 3, 4, 2, 5

Réponse attendue : Call Stack → Microtasks (Promise, queueMicrotask) → Tasks (setTimeout) → rAF avant paint.

Q34 : Explique this en JavaScript. Quels sont les 5 cas ?

Réponse attendue :

  1. Default : this = window (non-strict) / undefined (strict)
  2. Implicit : obj.fn() → this = obj
  3. Explicit : fn.call(obj), fn.apply(obj), fn.bind(obj)
  4. New : new Fn() → this = nouvelle instance
  5. Arrow : lexical this (pas de binding propre)

Q35 : Quelle est la différence entre var, let et const ?

Aspectvarletconst
ScopeFunctionBlockBlock
HoistingOui (undefined)Oui (TDZ)Oui (TDZ)
ReassignableOuiOuiNon
RedéclarableOuiNonNon
Window propertyOui (non-module)NonNon

Q36 : Implémente Array.prototype.map à la main.

function myMap(arr, callback, thisArg) {
  const result = [];
  for (let i = 0; i < arr.length; i++) {
    if (i in arr) { // skip holes
      result.push(callback.call(thisArg, arr[i], i, arr));
    }
  }
  return result;
}

// Edge cases à mentionner :
// - Holes (sparse arrays)
// - thisArg optionnel
// - Ne modifie pas l'original
// - Gère les objets array-like

Q37 : Quelle est la différence entre deep copy et shallow copy ? Comment faire une deep copy ?

// Shallow copy
const copy1 = { ...original };
const copy2 = Object.assign({}, original);

// Deep copy
const deep = structuredClone(original); // ✅ Moderne (2022+)
const deep2 = JSON.parse(JSON.stringify(original)); // ⚠️ perd fonctions, dates, undefined, circular

// Alternatives : Lodash cloneDeep, Immer

Q38 : Explique les Promises. Quelle est la différence entre Promise.all, Promise.allSettled, Promise.race et Promise.any ?

MethodRésout si…Rejette si…
Promise.allToutes réussissentUne rejette (fail-fast)
Promise.allSettledToutes terminentJamais
Promise.raceLa première se settleLa première rejette
Promise.anyLa première réussitToutes rejettent (AggregateError)

2.2 React (6 questions)

Q39 : Explique le Virtual DOM et comment React optimise les rendus.

Réponse attendue :

  1. React crée un VDOM (arbre JS d'objets représentant le DOM réel)
  2. State/Props change → nouveau VDOM
  3. Diffing algorithm compare VDOM old et new (O(n) grâce aux keys et assumptions)
  4. Reconciliation : applique les changements minimaux au DOM réel
  5. Optimisations : keys stables, memo, useMemo, useCallback, shouldComponentUpdate

Q40 : Quelle est la différence entre useEffect, useLayoutEffect et useInsertionEffect ?

HookTimingUsage
useEffectAprès paint (async)Data fetching, subscriptions, side-effects
useLayoutEffectAvant paint (sync)DOM measurements, animations
useInsertionEffectAvant layout (CSS-in-JS)Injection de styles

Q41 : Explique le cycle de vie d'un composant React avec hooks.

Mount:
  1. Constructor (état initial)
  2. Render (JSX → VDOM)
  3. DOM actualisé
  4. useLayoutEffect (sync)
  5. Paint (navigateur)
  6. useEffect (async)

Update (state/props change):
  1. Render
  2. Cleanup des effets précédents
  3. DOM actualisé
  4. useLayoutEffect cleanup + run
  5. Paint
  6. useEffect cleanup + run

Unmount:
  1. Cleanup de tous les effets
  2. DOM retiré

Q42 : Qu'est-ce que le "lifting state up" ? Donne un exemple.

// ❌ État dupliqué
function Parent() {
  return (
    <>
      <Input1 />  {/* a son propre state */}
      <Input2 />  {/* a son propre state — peut-on sync ? */}
    </>
  );
}

// ✅ State lifté
function Parent() {
  const [value, setValue] = useState('');
  return (
    <>
      <Input value={value} onChange={setValue} />
      <Display value={value} />
    </>
  );
}

Q43 : Explique les portails React (createPortal).

// Le composant Modal est dans l'arbre React mais rendu ailleurs dans le DOM
function Modal({ children, isOpen }) {
  if (!isOpen) return null;
  return createPortal(
    <div className="modal-overlay">
      <div className="modal-content">{children}</div>
    </div>,
    document.getElementById('modal-root') // en dehors de #root
  );
}
// Utile pour : modals, tooltips, dropdowns, toasts
// Évite les problèmes de z-index et overflow: hidden

Q44 : Comment gères-tu les états globaux dans React ? Compare les solutions.

SolutionTailleBoilerplateAsyncDevTools
Context0 kBFaibleNonNon
Redux12 kBÉlevéOui (thunk/saga)Excellent
Zustand1 kBTrès faibleNon intégréOui
Jotai3 kBTrès faibleNonOui
React Query10 kBFaibleOui (API)Excellent

2.3 CSS (4 questions)

Q45 : Explique le Box Model et la différence entre box-sizing: content-box et border-box.

/* content-box (défaut) : width = contenu seulement */
/* border-box : width = contenu + padding + border */
* {
  box-sizing: border-box; /* presque toujours préféré */
}
/* 
  content-box : width: 100px + padding: 20px + border: 2px = 142px total
  border-box  : width: 100px inclut tout = 100px total
*/

Q46 : Compare Flexbox et CSS Grid. Quand utiliser l'un ou l'autre ?

FlexboxCSS Grid
1 dimension (row OU column)2 dimensions (row ET column)
Distribution de contenuPlacement explicite
Meilleur pour : navbar, centrage, rangéesMeilleur pour : layout page, galeries, Dashboard
justify-content, align-itemsgrid-template, grid-area

Q47 : Explique la spécificité CSS. Que vaut la spécificité de chaque sélecteur ?

/* Spécificité : (inline, id, class, element) */
*                 /* (0,0,0,0) */
h1                /* (0,0,0,1) */
.class            /* (0,0,1,0) */
#id               /* (0,1,0,0) */
style="..."       /* (1,0,0,0) */
!important        /* 🚨 override tout (sauf autre !important inline) */

/* Calcul : */
div.class          /* (0,0,1,1) = 11 */
ul#nav li.active   /* (0,1,1,2) = 112 */

Q48 : Qu'est-ce que le CSS Stacking Context ? Donne des exemples qui en créent un.

/* Un stacking context isole un sous-arbre du z-index global */
/* Créé par : */
position: relative/absolute + z-index: auto/z-index: valeur
opacity < 1
transform, filter, perspective, clip-path
mix-blend-mode
isolation: isolate  /* ✅ Crée un contexte volontairement */

/* Piège célèbre : */
.el { z-index: 999999; }
.parent { opacity: 0.99; }
/* .el ne passera PAS devant .other si .parent et .other sont frères */

2.4 Outils et Écosystème (2 questions)

Q49 : Quelle est la différence entre un bundler (Webpack/Vite) et un transpiler (Babel/SWC) ?

OutilRôle
BundlerRésout les imports/exports → fichier bundle unique
TranspilerTransforme JS moderne → JS compatible navigateur
Vite utilise esbuild (bundler + transpiler) en dev, Rollup en prod
SWC est un transpiler Rust (100x plus rapide que Babel)

Q50 : Explique le Tree Shaking. Comment s'assurer qu'il fonctionne ?

Tree shaking = élimination du code mort via static analysis (ES modules)

Conditions :
✅ ES Modules (import/export statiques)
✅ Side-effect-free dans package.json
✅ Mode production (minification + dead code elimination)

❌ CommonJS (require() est dynamique)
❌ Modules avec effets de bord (import 'styles.css')
❌ Accès aux propriétés d'objets (import * as utils → pas de tree shake)

Vérification : bundle analyzer, webpack-stats

2.5 Grille d'Évaluation — Technique

Critère1 (Faible)2 (Moyen)3 (Bon)4 (Excellent)
ExactitudeFauxPartiellement correctCorrectPrécis + nuances
ProfondeurSurfaceConcept comprisMécanisme interneSpec + edge cases
VocabulaireApproximatifTermes correctsTermes précisJargon technique
CodePas de codeCode non fonctionnelCode fonctionnelFonctionnel + optimal
CommunicationConfusStructure basiqueClair + structuréPédagogique

3. Whiteboard Sessions (5 Sessions)

3.1 Session 1 : Debounce avec Options (Lead, Trailing, Max Wait)

Énoncé : Implémente une fonction debounce avec support des options
- leading : appel immédiat au premier déclenchement
- trailing : appel après le délai (défaut)
- maxWait : temps maximum avant exécution forcée
function debounce(fn, delay, options = {}) {
  const { leading = false, trailing = true, maxWait } = options;
  let timer = null;
  let lastArgs = null;
  let lastCallTime = null;
  let leadingInvoked = false;

  function invoke() {
    if (lastArgs) {
      fn(...lastArgs);
      lastArgs = null;
      leadingInvoked = false;
    }
  }

  function shouldInvokeLeading() {
    return leading && !leadingInvoked;
  }

  return function (...args) {
    const now = Date.now();
    lastArgs = args;

    if (shouldInvokeLeading()) {
      fn(...args);
      leadingInvoked = true;
      lastCallTime = now;
      return;
    }

    if (maxWait && lastCallTime && (now - lastCallTime >= maxWait)) {
      clearTimeout(timer);
      timer = null;
      invoke();
      lastCallTime = now;
      return;
    }

    clearTimeout(timer);
    timer = setTimeout(() => {
      if (trailing) invoke();
      timer = null;
      lastCallTime = null;
    }, delay);
  };
}

3.2 Session 2 : Composant Autocomplete avec Accessibilité

Énoncé : Conçois un composant Autocomplete React avec :
- Recherche asynchrone (debounce 300ms)
- Navigation clavier (flèches, Enter, Escape)
- Support ARIA (combobox, listbox, option)
- Highlight du texte recherché
- Gestion des états : loading, empty, error, results
function Autocomplete({ fetchSuggestions }) {
  const [inputValue, setInputValue] = useState('');
  const [results, setResults] = useState([]);
  const [isOpen, setIsOpen] = useState(false);
  const [activeIndex, setActiveIndex] = useState(-1);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);
  const inputRef = useRef(null);
  const listRef = useRef(null);

  // Debounce search
  useEffect(() => {
    if (!inputValue) { setResults([]); return; }

    const timer = setTimeout(async () => {
      setIsLoading(true);
      setError(null);
      try {
        const data = await fetchSuggestions(inputValue);
        setResults(data);
        setIsOpen(true);
      } catch (e) {
        setError(e.message);
      } finally {
        setIsLoading(false);
      }
    }, 300);

    return () => clearTimeout(timer);
  }, [inputValue, fetchSuggestions]);

  const handleKeyDown = (e) => {
    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault();
        setActiveIndex(i => Math.min(i + 1, results.length - 1));
        break;
      case 'ArrowUp':
        e.preventDefault();
        setActiveIndex(i => Math.max(i - 1, -1));
        break;
      case 'Enter':
        if (activeIndex >= 0) selectItem(results[activeIndex]);
        break;
      case 'Escape':
        setIsOpen(false);
        setActiveIndex(-1);
        break;
    }
  };

  return (
    <div role="combobox" aria-expanded={isOpen} aria-haspopup="listbox">
      <input
        ref={inputRef}
        value={inputValue}
        onChange={e => { setInputValue(e.target.value); setActiveIndex(-1); }}
        onKeyDown={handleKeyDown}
        onFocus={() => results.length > 0 && setIsOpen(true)}
        aria-autocomplete="list"
        aria-controls="suggestion-list"
        aria-activedescendant={activeIndex >= 0 ? `option-${activeIndex}` : undefined}
      />
      {isLoading && <Spinner />}
      {error && <Alert type="error">{error}</Alert>}
      {isOpen && results.length > 0 && (
        <ul ref={listRef} id="suggestion-list" role="listbox">
          {results.map((item, i) => (
            <li
              key={item.id}
              id={`option-${i}`}
              role="option"
              aria-selected={i === activeIndex}
              className={i === activeIndex ? 'active' : ''}
              onMouseDown={() => selectItem(item)}
            >
              <Highlight text={item.label} query={inputValue} />
            </li>
          ))}
        </ul>
      )}
      {isOpen && !isLoading && !error && results.length === 0 && (
        <div role="status">Aucun résultat</div>
      )}
    </div>
  );
}

3.3 Session 3 : Algorithme de Pagination

Énoncé : Implémente un composant de pagination qui montre :
- Les 3 premières pages, ..., page courante - 1, page courante, page courante + 1, ..., les 3 dernières
- Exemple (page 10 sur 20) : 1 2 3 ... 9 10 11 ... 18 19 20
function getPaginationRange(current, total, siblings = 1) {
  const totalVisible = siblings * 2 + 5; // first + last + current + 2*siblings

  if (total <= totalVisible) {
    return Array.from({ length: total }, (_, i) => i + 1);
  }

  const pages = [];

  pages.push(1, 2, 3);

  if (current > 5) pages.push('...');

  const start = Math.max(4, current - siblings);
  const end = Math.min(total - 3, current + siblings);

  for (let i = start; i <= end; i++) {
    pages.push(i);
  }

  if (current < total - 4) pages.push('...');

  pages.push(total - 2, total - 1, total);

  return pages;
}

function Pagination({ current, total, onChange }) {
  const pages = getPaginationRange(current, total);

  return (
    <nav aria-label="Pagination">
      <button disabled={current === 1} onClick={() => onChange(current - 1)}>
        Précédent
      </button>
      {pages.map((page, i) =>
        page === '...' ? (
          <span key={`ellipsis-${i}`} aria-hidden="true">…</span>
        ) : (
          <button
            key={page}
            aria-current={page === current ? 'page' : undefined}
            className={page === current ? 'active' : ''}
            onClick={() => onChange(page)}
          >
            {page}
          </button>
        )
      )}
      <button disabled={current === total} onClick={() => onChange(current + 1)}>
        Suivant
      </button>
    </nav>
  );
}

3.4 Session 4 : Machine à États (State Machine)

Énoncé : Implémente un hook useMachine qui gère une machine à états.
Utilisation : const [state, send] = useMachine(config, initial)
function useMachine(config, initialState) {
  const [state, setState] = useState(initialState);

  const send = useCallback((event) => {
    setState(currentState => {
      const transitions = config[currentState]?.on;
      if (!transitions) {
        console.warn(`No transitions defined for state "${currentState}"`);
        return currentState;
      }

      const transition = transitions[event.type];
      if (!transition) {
        console.warn(`No transition for event "${event.type}" in state "${currentState}"`);
        return currentState;
      }

      const nextState = typeof transition === 'function'
        ? transition(event)
        : transition;

      // Effets de bord (entry/exit)
      config[currentState]?.exit?.(event);
      config[nextState]?.entry?.(event);

      return nextState;
    });
  }, [config]);

  return [state, send];
}

// Usage
const machineConfig = {
  idle: {
    on: {
      FETCH: 'loading',
    },
  },
  loading: {
    entry: () => fetchData(),
    on: {
      SUCCESS: 'success',
      ERROR: 'error',
    },
  },
  success: {
    on: {
      REFETCH: 'loading',
    },
  },
  error: {
    on: {
      RETRY: 'loading',
    },
  },
};

function useFetch(url) {
  const [state, send] = useMachine(machineConfig, 'idle');
  // ...
}

3.5 Session 5 : Virtual List (Windowed List)

Énoncé : Implémente une liste virtuelle qui ne rend que les éléments visibles
(10 000 éléments, hauteur fixe 50px, viewport 500px → seulement 10 éléments rendus)
function VirtualList({ items, itemHeight, containerHeight, renderItem }) {
  const [scrollTop, setScrollTop] = useState(0);

  const totalHeight = items.length * itemHeight;
  const startIndex = Math.floor(scrollTop / itemHeight);
  const endIndex = Math.min(
    items.length - 1,
    Math.ceil((scrollTop + containerHeight) / itemHeight)
  );

  const visibleItems = items.slice(startIndex, endIndex + 1);
  const bufferTop = startIndex * itemHeight;

  return (
    <div
      style={{ height: containerHeight, overflow: 'auto' }}
      onScroll={e => setScrollTop(e.target.scrollTop)}
    >
      <div style={{ height: totalHeight, position: 'relative' }}>
        <div style={{ position: 'absolute', top: bufferTop, width: '100%' }}>
          {visibleItems.map((item, i) => (
            <div key={item.id} style={{ height: itemHeight }}>
              {renderItem(item, startIndex + i)}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// Optimisations : memo sur renderItem, ResizeObserver, dynamic height

3.6 Grille d'Évaluation — Whiteboard

Critère1 (Faible)2 (Moyen)3 (Bon)4 (Excellent)
ApprochePas de planPlan vagueStructure claireArchitecture + edge cases
SyntaxeErreurs nombreusesErreurs mineuresSyntaxe correcteSans erreur
LogiqueNon fonctionnelPartiellementFonctionnelOptimal + performant
CommunicationSilenceParle en écrivantExplique les choixDialogue + alternative
TestsPas de test mentalTest 1 casTest cas nominauxTest edge + perf

4. System Design Front-End (5 Questions)

4.1 Design 1 : Netflix Front-End

Problème : Conçois l'architecture front-end de Netflix.

Contraintes :

  • 200M+ utilisateurs
  • Multi-appareils (TV, mobile, desktop)
  • Streaming vidéo adaptatif
  • Personnalisation par utilisateur
  • 5 profils par compte

Architecture attendue :

Architecture Micro-frontends (Module Federation)

Shell (App Shell)
├── Navigation (header, footer, auth)
├── Browse (rows, categories)
│   ├── Hero Row (featured content)
│   ├── Continue Watching
│   ├── Trending Now
│   └── Genre Rows (×20)
├── Search (typeahead, suggestions)
├── Player (video player + controls)
└── My List (gestion, sync)

Performance :
- SSR (Next.js) pour le shell et le SEO
- Streaming SSR pour le Hero
- ISR pour les catalogues (revalidate toutes les heures)
- Code splitting par route et par composant
- Image lazy loading + responsive (AVIF, WebP)
- Service Worker pour offline fallback
- Prefetch des rows suivantes (Intersection Observer)

State Management :
- React Query pour les données serveur (cache, stale-while-revalidate)
- Zustand pour l'UI locale (modals, sidebar)
- Zustand persisté pour les préférences (profil, langue)

Rendu vidéo :
- MSE (Media Source Extensions) pour l'adaptatif
- EME (Encrypted Media Extensions) pour le DRM
- Web Workers pour le téléchargement en arrière-plan

Questions posées sur le design :

  • Comment gères-tu les 20+ catégories sans bloquer le rendu ?
  • Comment implémentes-tu le carrousel horizontal infini ?
  • Comment gères-tu la personnalisation en temps réel ?
  • Comment testes-tu sur 2000+ types d'appareils ?

4.2 Design 2 : Gmail Front-End

Problème : Conçois l'architecture front-end de Gmail.

Contraintes :

  • 1.5B+ utilisateurs
  • Boîte de réception temps réel
  • Recherche instantanée
  • Offline support
  • Labels, filtres, automation

Architecture attendue :

Architecture : Single-Page Application (Angular → Lit/Web Components)

Key Components :
- App Shell : skeleton + auth
- Inbox : virtual list (react-window)
- Thread View : lazy loaded
- Search : index local (IndexedDB) + debounce serveur
- Compose : floating editor (draft auto-save)
- Settings : lazy loaded

Data Layer :
- IndexedDB pour le cache hors-ligne (Dexie.js)
- WebSocket pour les nouveaux emails temps réel
- Request deduplication (même email pas fetché 2x)
- Optimistic updates (send → UI instantané → confirmation)

Architecture Offline :
- Service Worker cache-first pour l'UI
- IndexedDB pour les emails (full-text search)
- Background sync pour les envois en attente
- Conflict resolution (version vector clocks)

Performance :
- Virtual scrolling (paquet de 50 emails par frame)
- Search : Web Worker + IndexedDB full-text
- Compose : lazy load editor (TinyMCE/ProseMirror)

4.3 Design 3 : Figma Front-End

Problème : Conçois l'architecture front-end de Figma.

Contraintes :

  • Canvas infini
  • Multiplayer temps réel
  • 100+ outils d'édition
  • WebGL rendering
  • Undo/redo infini

Architecture attendue :

Architecture : Canvas-based (WebGL + WebCodecs)

Key Architecture Decisions :
- Rendering : WebGL 2.0 via custom engine (pas de DOM)
- Scene graph : arbre immutable (Immer-like)
- CRDT pour le multiplayer (Y.js ou custom)
- SharedArrayBuffer pour le state partagé

Multiplayer :
- OT (Operational Transformation) pour le texte
- CRDT pour les objets du canvas
- WebRTC DataChannels pour faible latence
- WebSocket fallback pour la fiabilité

State Management :
- Scene Graph (immutable, Immer)
- Command pattern pour undo/redo
- History stack (500 étapes max)
- Serialization optimisée (MessagePack)

Performance Canvas :
- Virtual canvas (seulement les éléments visibles)
- Viewport culling (quadtree)
- Layer rasterization
- OffscreenCanvas pour le rendu différé
- Web Workers pour les calculs coûteux

4.4 Design 4 : Slack Front-End

Problème : Conçois l'architecture front-end de Slack.

Contraintes :

  • Messages temps réel (WebSocket)
  • Recherche full-text
  • Upload de fichiers
  • Threads, réactions, mentions
  • 10k+ membres par workspace

Architecture attendue : Focus sur le state management temps réel, la virtualisation des messages (infinite scroll up), le search avec debounce, les mentions autocomplete, et le rendering efficace des réactions en temps réel.

4.5 Design 5 : Google Maps Front-End

Problème : Conçois l'architecture front-end de Google Maps.

Contraintes :

  • Données géographiques massives
  • Zoom de rue à satellite
  • Directions en temps réel
  • Traffic data
  • Street View

Architecture attendue : Focus sur le WebGL rendering des tuiles, viewport-based data loading, tile caching stratégique, Web Workers pour les calculs d'itinéraire, et le découpage en couches (routes, traffic, satellite, POIs).

4.6 Grille d'Évaluation — System Design

Critère1 (Faible)2 (Moyen)3 (Bon)4 (Excellent)
PérimètreOublie des contraintesContraintes principalesToutes les contraintesContraintes + non-fonctionnelles
ArchitectureMonolithiqueCouches simplesMicro-frontends modulairesArchitecture évolutive
ComposantsPas de découpageDécoupage basiqueComposants clairsComposants + isolation
Data flowPas de stateState localState distribuéState synchro offline
PerformanceIgnoréeMentionnéeChiffréeOptimisée (metrics)
Trade-offsAucun1 trade-off2-3 trade-offsDiscussion balanced

5. Questions d'Architecture (5 Questions)

Q51 : Micro-frontends — Quand les utiliser ? Quels risques ?

Réponse attendue :

PourContre
Équipes indépendantesComplexité opérationnelle
Technos différentesBundle size (runtime duplication)
Déploiement indépendantTesting cross-microfrontend
Scaling d'équipeCommunication inter-microfrontend

Architectures :

  • Module Federation (Webpack 5) : partage de modules à l'exécution
  • iFrames : isolation forte, UX dégradée
  • Web Components : standard, indépendant du framework
  • Single SPA : orchestration centralisée

Anti-patterns :

  • Micro-frontends pour une équipe de 3 personnes
  • Partage excessif de composants (couplage)
  • Routing fragmenté (perte de UX unifiée)

Q52 : Monorepo vs Polyrepo — Que choisir pour un projet front-end ?

CritèreMonorepoPolyrepo
Partage de codeFacile (mêmes packages)Difficile (publish npm)
CI/CDComplexe (filtering)Simple (par repo)
Atomic commitsPossibleImpossible
OutilsTurborepo, Nx, LernaStandard
ScalingLimité (git scale)Illimité

Recommandation :

  • Monorepo pour 2-10 équipes avec partage de design system
  • Polyrepo pour équipes totalement indépendantes
  • Outils récents : Turborepo (Vercel), Nx (Nrwl)

Q53 : Comment scales-tu une application React pour 50 développeurs ?

Réponse attendue :

1. Architecture : Feature-based folders, pas de technical layers
2. Design System : Composants partagés (Radix UI + Tailwind)
3. Code splitting : Par feature, lazy loading automatique
4. Testing : Vitest + Playwright (E2E sur les features critiques)
5. TypeScript strict : Pas de any, génériques, branded types
6. Linting : ESLint + Prettier + commit hooks
7. Documentation : Storybook + JSDoc + ADRs
8. Performance : Bundle analyzer, size-limit, Lighthouse CI
9. Monorepo : Turborepo + pnpm workspaces
10. RFC Process : ADR obligatoire pour les décisions majeures

Q54 : Comment gères-tu la migration d'une application legacy (jQuery → React) ?

Réponse attendue :

Stratégie "Strangler Fig" (incremental replacement) :

1. Strangler Fig
   - Proxy côté serveur (Nginx) ou client (module federation)
   - Les nouvelles routes vont vers React
   - Les anciennes restent sur jQuery

2. Micro-frontend approach
   - React à l'intérieur d'un div, isolé par Shadow DOM
   - Communication via window events ou CustomEvent

3. Feature flag
   - Les deux versions cohabitent
   - Rollout progressif (10% → 50% → 100%)
   - Rollback immediate

4. Couche de traduction
   - API bridge entre l'ancien state (jQuery.data) et React
   - Migration par composant, pas par page

5. Testing
   - Screenshot testing avant/après (Percy, Chromatic)
   - Feature parity checklist

Q55 : Comment assurez-vous la performance d'une application front-end à grande échelle ?

Réponse attendue :

Stratégie en 3 axes :

1. BUILD TIME
   - Code splitting automatique (React.lazy, dynamic import)
   - Tree shaking + side-effects analysis
   - Image optimization (next/image, sharp)
   - Bundle analysis + size-limit

2. RUNTIME
   - Virtual scrolling (react-window)
   - Memoization (React.memo, useMemo, useCallback)
   - Web Workers pour les calculs lourds
   - Lazy loading (Intersection Observer)
   - Debounce/Throttle pour les events fréquents

3. NETWORK
   - CDN + Edge (Vercel, Cloudflare)
   - Caching headers (stale-while-revalidate)
   - Prefetch (rel=preload, link rel=prefetch)
   - Service Worker (offline, cache API)
   - HTTP/2 multiplexing

Metrics targets :
- LCP < 2.5s
- FID < 100ms
- CLS < 0.1
- TBT < 200ms
- Bundle size < 200KB (critical path)

5.1 Grille d'Évaluation — Architecture

Critère1 (Faible)2 (Moyen)3 (Bon)4 (Excellent)
Connaissance conceptAucuneNotionsMaîtriseExpertise (pros/cons)
Expérience pratiqueThéoriqueProjet personnelProductionScale production
Trade-offsUn seul côté2 côtés3+ trade-offsAnalyse nuancée
AlternativesAucune1 alternative2-3 alt.Comparaison détaillée
Mise en œuvreVagueÉtapes généralesPlan d'actionTimeline + risques

6. Checklist Pré-Entretien

6.1 Les Jours Précédents

  • Relire les fondamentaux JS (closures, event loop, this, promises)
  • Revoir les 10 questions React les plus fréquentes
  • Préparer 3-5 histoires STAR (échec, conflit, initiative, leadership, apprentissage)
  • S'entraîner au whiteboarding sur un tableau ou un éditeur vide
  • Rechercher l'entreprise (produit, stack technique, engineering blog)
  • Préparer 5 questions à poser à l'intervieweur

6.2 Pendant l'Entretien

  • Clarifier les exigences avant de coder
  • Verbaliser son raisonnement (penser à voix haute)
  • Commencer par un cas simple, puis ajouter de la complexité
  • Demander s'il faut optimiser pour la performance, la mémoire ou la lisibilité
  • Toujours tester mentalement son code (edge cases)
  • Si bloqué, demander un indice plutôt que de rester silencieux

6.3 Après l'Entretien

  • Envoyer un email de remerciement dans les 24h
  • Noter les questions posées pour les prochains entretiens
  • Demander du feedback si refusé
  • Continuer à coder et à apprendre

7. Conclusion

La préparation aux entretiens techniques est un investissement. Même si vous échouez au premier entretien, chaque tentative est une opportunité d'apprentissage. Les compétences les plus valorisées ne sont pas la connaissance d'un framework spécifique, mais :

  1. La maîtrise des fondamentaux (JS, CSS, réseau)
  2. La capacité à raisonner à voix haute
  3. L'humilité (reconnaître ce qu'on ne sait pas)
  4. L'architecture (penser au-delà d'un composant)
  5. La communication (pédagogie, écoute, collaboration)