En développement, notamment dans les environnements asynchrones ou concurrents, la manière dont on gère les conflits ou les accès concurrents à des ressources partagées peut radicalement changer l’architecture d’un système.
Deux grandes philosophies s’affrontent : l’approche pessimiste et l’approche optimiste.
👉 Réfléchir à ces deux modèles en amont du lancement d’un projet est essentiel pour avoir un code cohérent et robuste. Ça change souvent la qualité du produit final.
🔍 Définition rapide
- Approche pessimiste : on verrouille la ressource dès qu’un processus veut y accéder, pour éviter tout conflit potentiel.
- Approche optimiste : on part du principe qu’il n’y aura pas de conflit, et on vérifie seulement à la fin si tout s’est bien passé.
Ces deux stratégies sont classiques en base de données, mais elles se retrouvent partout : dans les accès réseau, les traitements asynchrones, les mises à jour d’interface, etc.
🛡️ L’approche pessimiste
Principe
On anticipe les conflits. Dès qu’un utilisateur ou un processus accède à une ressource, on la bloque pour les autres. C’est le fameux lock
.
Avantages
- Sécurise les écritures : peu ou pas de conflits.
- Prévisible : les règles sont strictes.
Inconvénients
- Risque de blocage (deadlock).
- Moins scalable dans des systèmes fortement concurrents.
- Peut ralentir les performances à cause des verrous.
🎯 L’approche optimiste
Principe
On autorise tout le monde à accéder ou modifier la ressource, en supposant que les conflits seront rares. C’est à la validation que le système vérifie l’absence de problème (souvent via un hash ou une version).
Avantages
- Très performant dans un environnement où les conflits sont rares.
- Parfait pour les applications distribuées ou offline-first.
- Plus fluide côté utilisateur (moins de blocages visibles).
Inconvénients
- Demande de gérer les conflits à la main.
- Moins intuitif si les utilisateurs modifient simultanément.
- Peut être complexe à tester et à implémenter proprement.
🧠 Quand utiliser quoi ?
Situation | Approche recommandée |
---|---|
Conflits fréquents | Pessimiste |
Conflits rares, besoin de fluidité | Optimiste |
Système critique (financier, médical) | Pessimiste |
App distribuée ou mobile | Optimiste |
⚛️ Exemples en React avec Redux Toolkit
Prenons le cas d’une action asynchrone : supprimer un élément d’une liste côté serveur.
🔒 Approche pessimiste (confirmation après serveur)
// slice.js
const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
setTodos: (state, action) => action.payload,
},
extraReducers: (builder) => {
builder.addCase(deleteTodo.fulfilled, (state, action) => {
return state.filter(todo => todo.id !== action.payload.id);
});
},
});
export const deleteTodo = createAsyncThunk(
'todos/deleteTodo',
async (id, thunkAPI) => {
const response = await fetch(`/api/todos/${id}`, { method: 'DELETE' });
if (!response.ok) throw new Error('Erreur lors de la suppression');
return { id };
}
);
Ici, on attend la réponse du serveur avant de mettre à jour le store. C’est plus lent mais plus sûr.
⚡ Approche optimiste (on met à jour le state tout de suite)
const todosSlice = createSlice({
name: 'todos',
initialState: [],
reducers: {
removeTodo: (state, action) => {
return state.filter(todo => todo.id !== action.payload);
},
restoreTodo: (state, action) => {
state.push(action.payload);
},
},
extraReducers: (builder) => {
builder.addCase(deleteTodoOptimistic.rejected, (state, action) => {
// On pourrait re-fetch les données ici si besoin
});
},
});
export const deleteTodoOptimistic = createAsyncThunk(
'todos/deleteTodoOptimistic',
async (todo, { dispatch, rejectWithValue }) => {
dispatch(removeTodo(todo.id));
const response = await fetch(`/api/todos/${todo.id}`, { method: 'DELETE' });
if (!response.ok) {
dispatch(restoreTodo(todo));
return rejectWithValue(todo);
}
return todo;
}
);
Ici, on met à jour l’UI immédiatement (UX rapide), et on gère le rollback si erreur. C’est l’approche optimiste typique.
🧩 Conclusion
Encore un truc à penser avant de lancer un projet, mais au moins vous savez que ça existe et que ça peut changer la donne.