Deux développeurs réalisent un tableau de bord. L'un, débutant, livre un fichier DashboardPage.tsx fonctionnel mais monolithique. L'autre, expérimenté, a divisé le code en une dizaine de fichiers distincts. Le chef de produit s'est exclamé : « C’est du surdimensionnement ! »
Mais six mois plus tard, la vérité émerge.
Le code du débutant est devenu une "montagne de boue" : chaque modification entraîne des effets en chaîne. Celui du senior, en revanche, est si bien structuré que même un nouvel arrivant peut intervenir en une semaine.
Cette différence fondamentale n'est pas liée à la maîtrise technique, mais à une fracture cognitive profonde entre deux niveaux de pensée.
La vérité cruelle : vous écrivez peut-être votre code de manière erronée
J’ai vu des développeurs front-end travaillant depuis 3 à 5 ans rester bloqués dans un cycle sans fin : « recevoir une demande → créer une page → valider le code ».
Leur quotidien ressemble à ceci :
- Le produit demande une page de liste d’utilisateurs → on crée
UserListPage.tsx - Un rapport est nécessaire → on crée
ReportPage.tsx - Les deux besoins incluent un tableau ? → copier-coller, ajuster quelques noms de champs
Ça semble efficace, non ?
Mais cette approche « page par page » ressemble à un travail de production en ligne : vous répétez constamment la même tâche sans construire de composants réutilisables.
Pire encore : quand le projet grandit, vous réalisez que vous avez creusé des trous que vous ne pouvez plus combler seul.
Débutant vs Senior : ce n’est pas la technique, c’est la vision
Beaucoup pensent qu’un développeur senior maîtrise parfaitement React/Vue, optimise les performances ou résout brillamment des problèmes algorithmiques.
Erreur.
La vraie barrière est celle-ci : êtes-vous en train de livrer une fonctionnalité, ou de construire un système ?
Voici un tableau comparatif pour situer votre niveau :
| Dimension | Débutant (pensée page) | Senior (pensée plateforme) |
|---|---|---|
| Focus | Comment implémenter cette requête ? | Comment résoudre systémiquement ce type de besoin ? |
| Organisation du code | Par page → composants | Par responsabilité → architecture en couches |
| Réutilisation | Extraire seulement quand nécessaire | Concevoir par défaut pour être réutilisable |
| Changement | Modifier une partie affecte plusieurs endroits | Les modifications sont contenues dans une couche précise |
| Collaboration | « Mon code fonctionne, c’est suffisant » | « Toute personne du groupe peut prendre en main rapidement » |
| Décision technique | Choisir la solution familière | Évaluer le coût de maintainance à long terme |
Vous voyez la différence ?
Le débutant optimise sa productivité individuelle. Le senior optimise la force collective.
L’un résout le présent. L’autre conçoit l’avenir.
La clé du raisonnement senior : l'architecture en couches n’est pas un excès
Beaucoup croient que l’architecture en couches est réservée aux grandes entreprises, et qu’elle constitue une surcharge inutile pour les petits projets.
C’est une erreur majeure.
L’objectif n’est pas de faire la preuve de son expertise, mais de rendre les changements prévisibles et contrôlables.
Voici comment un développeur expérimenté structure son code :
src/
├── components/ # Couche UI (seulement visuel)
│ ├── Button/
│ ├── Table/
│ └── Card/
├── features/ # Couche fonctionnalités (domaine métier)
│ ├── UserList/
│ ├── InvoiceForm/
│ └── Dashboard/
├── hooks/ # Couche gestion d’état
│ ├── useUserData.ts
│ ├── useAuth.ts
│ └── useTable.ts
├── services/ # Couche services (API, communication)
│ ├── api/
│ ├── analytics/
│ └── storage/
└── domain/ # Couche logique métier (règles métier)
├── user/
├── invoice/
└── validators/
Pourquoi cette division ?
Chaque couche correspond à un type de changement différent :
- Changer le style UI ? → modifier uniquement
components/ - Changer les champs API ? → toucher seulement
services/ - Modifier une règle métier ? → intervenir dans
domain/ - Produire une nouvelle fonctionnalité ? → assembler des modules existants dans
features/
C’est là que réside la puissance du raisonnement plateforme : les changements sont prévisibles, leurs impacts limités.
Exemple concret : deux façons d’écrire une page de paramètres
Version débutant
// SettingsPage.tsx (800 lignes)
function SettingsPage() {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
const [activeTab, setActiveTab] = useState('profile');
useEffect(() => {
fetch('/api/user/settings')
.then(res => res.json())
.then(data => setUser(data));
}, []);
const handleSave = async (formData) => {
setLoading(true);
await fetch('/api/user/settings', {
method: 'POST',
body: JSON.stringify(formData)
});
setLoading(false);
};
return (
<div>
<Tabs value={activeTab} onChange={setActiveTab}>
<Tab label="Profil" />
<Tab label="Notifications" />
</Tabs>
{activeTab === 'profile' && (
<form onSubmit={handleSave}>
{/* 300 lignes de formulaire */}
</form>
)}
{/* ... */}
</div>
);
}
Problèmes évidents :
- Logique, état et interface sont entrelacés
- La validation du formulaire est dispersée
- Nouveau besoin similaire ? Copier-coller, ajuster
- Un nouveau développeur doit lire 800 lignes pour changer un libellé
Version senior
// 1. Service - services/settings.ts
export const settingsService = {
getSettings: () => api.get('/user/settings'),
updateSettings: (data) => api.post('/user/settings', data)
};
// 2. Hook - hooks/useUserSettings.ts
export function useUserSettings() {
return useQuery({
queryKey: ['userSettings'],
queryFn: settingsService.getSettings
});
}
// 3. Form logic - hooks/useSettingsForm.ts
export function useSettingsForm() {
const { mutate, isLoading } = useMutation({
mutationFn: settingsService.updateSettings
});
return {
onSubmit: mutate,
isSubmitting: isLoading
};
}
// 4. Page - pages/SettingsPage.tsx (50 lignes)
export function SettingsPage() {
return (
<SettingsLayout>
<SettingsTabs>
<TabPanel value="profile">
<UserProfileForm />
</TabPanel>
<TabPanel value="notifications">
<NotificationPreferences />
</TabPanel>
</SettingsTabs>
</SettingsLayout>
);
}
// 5. Composant métier - features/UserProfileForm.tsx
function UserProfileForm() {
const { data: settings } = useUserSettings();
const { onSubmit, isSubmitting } = useSettingsForm();
return (
<Form onSubmit={onSubmit} loading={isSubmitting}>
{/* Seulement la logique d'affichage et d'interaction */}
</Form>
);
}
La différence est flagrante :
- Testabilité : chaque hook, chaque service peut être testé isolément
- Réutilisabilité :
useUserSettingspeut être utilisé partout - Maintenabilité : modifier une API → toucher juste
services/, changer l’UI → juste les composants - Extensibilité : ajouter un onglet ? Ajouter un
<TabPanel>suffit
C’est cela, une architecture de plateforme.
Les 5 habitudes automatiques des seniors
Après plusieurs années d’observation, j’ai identifié ces comportements instinctifs chez les développeurs expérimentés :
1. Concevoir les composants avec des points d’extension
// ❌ Logique figée
function DataTable({ data }) {
return <table>{/* rendu fixe */}</table>;
}
// ✅ Points d’extension intégrés
function DataTable({
data,
renderRow, // rendu personnalisé de ligne
renderEmpty, // état vide personnalisé
actions // boutons action dynamiques
}) {
return (
<table>
{data.length === 0 ? renderEmpty?.() : (
data.map(row => renderRow?.(row) ?? <DefaultRow />)
)}
</table>
);
}
2. Gestion d’état avec une conscience claire des limites
// ❌ État global trop large
const globalStore = {
user: {},
dashboardData: {},
reportData: {},
// ... 100 champs
};
// ✅ Division par domaine
const userStore = createSlice({ /* uniquement lié à l'utilisateur */ });
const dashboardStore = createSlice({ /* uniquement lié au tableau de bord */ });
// Chaque store a une seule responsabilité
3. Appels API toujours avec mécanismes de sécurité
// ❌ Appel brut
const data = await fetch('/api/data').then(r => r.json());
// ✅ Gestion centralisée des erreurs et redémarrages
const { data, error, retry } = useQuery({
queryFn: () => api.getData(),
retry: 3,
onError: (err) => toast.error(err.message)
});
4. Nommage orienté consensus, pas exactitude
// ❌ Noms incompréhensibles
function getData() { /* ... */ }
const tmp = useMemo(...);
// ✅ Noms clairs pour toute l’équipe
function fetchUserDashboardMetrics() { /* ... */ }
const memoizedFilteredUsers = useMemo(...);
5. Avant chaque validation, se demander : « Mon moi du futur va-t-il comprendre ? »
// ❌ Code illisible
const x = data.filter(d => d.status === 1 && d.type === 'A');
// ✅ Code auto-documenté
const STATUS_ACTIVE = 1;
const TYPE_ADMIN = 'A';
const activeAdminUsers = data.filter(
user => user.status === STATUS_ACTIVE && user.type === TYPE_ADMIN
);
Pourquoi tant de développeurs stagnent-ils au stade débutant ?
La cause principale : absence de boucle de retour.
Beaucoup livrent leur code et ne regardent jamais les conséquences :
- Est-ce facile à maintenir pour autrui ?
- Quand la même fonctionnalité revient, dois-je tout recoder ?
- Dans six mois, regardez votre propre code : êtes-vous tenté de le supprimer ?
Le chemin d’un développeur senior passe par :
- Écrire du code → se heurter à ses propres défauts → réfléchir
- Refactoriser → instaurer un modèle de conception → tester son efficacité
- L’appliquer dans de nouveaux projets → itérer et améliorer
Plus vite vous faites ce cycle, plus vite vous progressez.
À partir de demain : exercices pour adopter la pensée plateforme
Exercice 1 : Refactoriser une ancienne page
Prenez une page écrite il y a 6 mois. Recodez-la selon la pensée plateforme :
- Identifiez les parties réutilisables (tableau, formulaire, liste)
- Extraire la logique de récupération de données dans un hook indépendant
- Encapsuler les appels API dans une couche service
- Faire en sorte que le composant ne gère que l’affichage
Comparez le nombre de lignes et de fichiers avant/après. Vous serez surpris : ce qui paraît plus complexe est en réalité bien moins coûteux à maintenir.
Exercice 2 : Créer un composant configurable
Ne codez rien de figé. Tout doit être injectable via props ou contexte :
<DataGrid
columns={columnConfig}
dataSource={useUserData}
rowActions={[editAction, deleteAction]}
emptyState={<customempty></customempty>}
/>
Objectif : adapter ce composant à 80 % des besoins en tableaux, sans en recoder un autre.
Exercice 3 : Réaliser une revue de code avec une perspective plateforme
Examinez une PR de collègue avec ces critères :
- Ce morceau de code est-il réutilisible ?
- La gestion d’état respecte-t-elle des limites claires ?
- Un nouveau venu pourrait-il comprendre en 5 minutes ?
- Si le produit change, quelles parties seraient impactées ?
Non pas pour critiquer, mais pour bâtir une culture de qualité commune.
En conclusion : la pensée plateforme, ce n’est pas un luxe, c’est une nécessité de survie
Beaucoup pensent que la pensée plateforme est réservée aux grandes entreprises, inapplicable aux petits projets.
Exactement l’inverse.
Les petites équipes ont des ressources limitées, une rotation élevée, un héritage technique lourd — elles ont plus besoin que jamais d’une architecture solide pour éviter la chaos.
J’ai vu des startups s’effondrer parce qu’elles avaient négligé la dette technique au profit d’une « rapidité initiale ». Elles ont dû tout refaire.
Alors que les équipes ayant adopté la pensée plateforme dès le début, même avec trois développeurs, peuvent gérer des produits complexes.
Donc, la prochaine fois que vous écrivez du code, posez-vous la question :
« Je suis en train de livrer cette fonctionnalité, ou de construire un système ? »
Cette simple question détermine si vous êtes un opérateur de ligne de montage ou un architecte.
Passer de la pensée page à la pensée plateforme n’est pas une montée technique — c’est une transformation cognitive.
PS Si vous constatez que :
- Chaque changement touche plusieurs fichiers
- Le copier-coller est devenu une habitude
- Les nouveaux arrivants sont perdus dans votre code
Alors, c’est le moment de revoir votre modèle mental.
Partagez cet article avec vos collègues front-end. Où en sont-ils ? Comment ont-ils surmonté leurs obstacles ?