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ère | 1 (Faible) | 2 (Moyen) | 3 (Bon) | 4 (Excellent) |
|---|---|---|---|---|
| Structure STAR | Pas de structure | STAR partiel | STAR clair | STAR + métriques |
| Concrétude | Généralités | Un exemple vague | Exemple détaillé | Chiffres + impact |
| Rôle personnel | "On a fait" | Partiellement actif | Rôle clair | Leader reconnu |
| Réflexion | Pas d'apprentissage | Apprentissage superficiel | Leçon apprise | Changement systémique |
| Honnêteté | Évite les échecs | Minimise | Assume | Vulné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 :
- Default :
this = window(non-strict) /undefined(strict) - Implicit :
obj.fn()→ this = obj - Explicit :
fn.call(obj),fn.apply(obj),fn.bind(obj) - New :
new Fn()→ this = nouvelle instance - Arrow : lexical this (pas de binding propre)
Q35 : Quelle est la différence entre var, let et const ?
| Aspect | var | let | const |
|---|---|---|---|
| Scope | Function | Block | Block |
| Hoisting | Oui (undefined) | Oui (TDZ) | Oui (TDZ) |
| Reassignable | Oui | Oui | Non |
| Redéclarable | Oui | Non | Non |
| Window property | Oui (non-module) | Non | Non |
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 ?
| Method | Résout si… | Rejette si… |
|---|---|---|
Promise.all | Toutes réussissent | Une rejette (fail-fast) |
Promise.allSettled | Toutes terminent | Jamais |
Promise.race | La première se settle | La première rejette |
Promise.any | La première réussit | Toutes rejettent (AggregateError) |
2.2 React (6 questions)
Q39 : Explique le Virtual DOM et comment React optimise les rendus.
Réponse attendue :
- React crée un VDOM (arbre JS d'objets représentant le DOM réel)
- State/Props change → nouveau VDOM
- Diffing algorithm compare VDOM old et new (O(n) grâce aux keys et assumptions)
- Reconciliation : applique les changements minimaux au DOM réel
- Optimisations : keys stables, memo, useMemo, useCallback, shouldComponentUpdate
Q40 : Quelle est la différence entre useEffect, useLayoutEffect et useInsertionEffect ?
| Hook | Timing | Usage |
|---|---|---|
useEffect | Après paint (async) | Data fetching, subscriptions, side-effects |
useLayoutEffect | Avant paint (sync) | DOM measurements, animations |
useInsertionEffect | Avant 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.
| Solution | Taille | Boilerplate | Async | DevTools |
|---|---|---|---|---|
| Context | 0 kB | Faible | Non | Non |
| Redux | 12 kB | Élevé | Oui (thunk/saga) | Excellent |
| Zustand | 1 kB | Très faible | Non intégré | Oui |
| Jotai | 3 kB | Très faible | Non | Oui |
| React Query | 10 kB | Faible | Oui (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 ?
| Flexbox | CSS Grid |
|---|---|
| 1 dimension (row OU column) | 2 dimensions (row ET column) |
| Distribution de contenu | Placement explicite |
| Meilleur pour : navbar, centrage, rangées | Meilleur pour : layout page, galeries, Dashboard |
justify-content, align-items | grid-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) ?
| Outil | Rôle |
|---|---|
| Bundler | Résout les imports/exports → fichier bundle unique |
| Transpiler | Transforme 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ère | 1 (Faible) | 2 (Moyen) | 3 (Bon) | 4 (Excellent) |
|---|---|---|---|---|
| Exactitude | Faux | Partiellement correct | Correct | Précis + nuances |
| Profondeur | Surface | Concept compris | Mécanisme interne | Spec + edge cases |
| Vocabulaire | Approximatif | Termes corrects | Termes précis | Jargon technique |
| Code | Pas de code | Code non fonctionnel | Code fonctionnel | Fonctionnel + optimal |
| Communication | Confus | Structure basique | Clair + 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ère | 1 (Faible) | 2 (Moyen) | 3 (Bon) | 4 (Excellent) |
|---|---|---|---|---|
| Approche | Pas de plan | Plan vague | Structure claire | Architecture + edge cases |
| Syntaxe | Erreurs nombreuses | Erreurs mineures | Syntaxe correcte | Sans erreur |
| Logique | Non fonctionnel | Partiellement | Fonctionnel | Optimal + performant |
| Communication | Silence | Parle en écrivant | Explique les choix | Dialogue + alternative |
| Tests | Pas de test mental | Test 1 cas | Test cas nominaux | Test 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ère | 1 (Faible) | 2 (Moyen) | 3 (Bon) | 4 (Excellent) |
|---|---|---|---|---|
| Périmètre | Oublie des contraintes | Contraintes principales | Toutes les contraintes | Contraintes + non-fonctionnelles |
| Architecture | Monolithique | Couches simples | Micro-frontends modulaires | Architecture évolutive |
| Composants | Pas de découpage | Découpage basique | Composants clairs | Composants + isolation |
| Data flow | Pas de state | State local | State distribué | State synchro offline |
| Performance | Ignorée | Mentionnée | Chiffrée | Optimisée (metrics) |
| Trade-offs | Aucun | 1 trade-off | 2-3 trade-offs | Discussion balanced |
5. Questions d'Architecture (5 Questions)
Q51 : Micro-frontends — Quand les utiliser ? Quels risques ?
Réponse attendue :
| Pour | Contre |
|---|---|
| Équipes indépendantes | Complexité opérationnelle |
| Technos différentes | Bundle size (runtime duplication) |
| Déploiement indépendant | Testing cross-microfrontend |
| Scaling d'équipe | Communication 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ère | Monorepo | Polyrepo |
|---|---|---|
| Partage de code | Facile (mêmes packages) | Difficile (publish npm) |
| CI/CD | Complexe (filtering) | Simple (par repo) |
| Atomic commits | Possible | Impossible |
| Outils | Turborepo, Nx, Lerna | Standard |
| Scaling | Limité (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ère | 1 (Faible) | 2 (Moyen) | 3 (Bon) | 4 (Excellent) |
|---|---|---|---|---|
| Connaissance concept | Aucune | Notions | Maîtrise | Expertise (pros/cons) |
| Expérience pratique | Théorique | Projet personnel | Production | Scale production |
| Trade-offs | Un seul côté | 2 côtés | 3+ trade-offs | Analyse nuancée |
| Alternatives | Aucune | 1 alternative | 2-3 alt. | Comparaison détaillée |
| Mise en œuvre | Vague | Étapes générales | Plan d'action | Timeline + 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 :
- La maîtrise des fondamentaux (JS, CSS, réseau)
- La capacité à raisonner à voix haute
- L'humilité (reconnaître ce qu'on ne sait pas)
- L'architecture (penser au-delà d'un composant)
- La communication (pédagogie, écoute, collaboration)