Inversion de dépendances : Changer de librairie dans Next.js

Publié le 24 juin 2024
Baptiste Drillien avatar
Baptiste Drillien
Développeur front-end

Dans cet article, nous allons voir pourquoi et comment mettre en œuvre l’inversion de dépendances pour faciliter la transition entre différentes librairies.

Dans de nombreux projets utilisant Next.js ou React, le choix des librairies est crucial. Il arrive qu’une librairie devienne dépréciée : il faut la remplacer.

Une forte dépendance peut rendre la maintenance et les mises à jour du code complexes. Un très bon exemple serait les librairies de manipulation de dates.

Le problème de la dépendance directe

Lorsqu'on utilise directement une librairie dans un projet, on crée une dépendance importante à cette librairie.

Si un jour on décide de la remplacer par une autre, on se retrouve à devoir réécrire du code. Ce refactoring s’applique à chaque endroit où la librairie est utilisée.

Cela est dû à l'absence d'inversion de dépendances, ce qui nous mène à un code rigide et difficile à maintenir. Les modifications demandent donc plus de temps et d'argent. 💰

Exemple de dépendance directe avec une librairie de dates

La librairie moment a longtemps été une librairie incontournable et très populaire pour la gestion des dates en javascript. L’utilisation directe de la librairie dans le code signifie que nous faisons appel à moment à chaque fois que nous devons manipuler une date :

article.tsx
1import moment from "moment";
2
3export const Article = ({ date }) => {
4 const formattedDate = moment(date).format("DD/MM/YYYY");
5
6 return (
7 <article>
8 <p>Date de publication : {formattedDate}</p>
9 </article>
10 );
11};

Dans cet exemple, moment est directement utilisé dans notre composant. Si nous voulons passer à une autre librairie, nous devons modifier chaque instance de moment dans tout notre projet.

Exemple d’une librairie populaire dépréciée

Bien que moment se soit positionnée comme librairie majeure pour les manipulations de date, ses développeurs ont officiellement annoncé en 2020 que la librairie était dépréciée.

Ils ont donc encouragé la migration vers des alternatives plus modernes pour les nouveaux projets.

Malgré tout, comme on peut le voir sur ce graphique, moment est longtemps restée populaire face à des librairies plus pertinentes comme par exemple date-fns :

landing page Leroy Merlin

Cela signifie que bon nombre de projets devront finir par changer de librairie de dates dans le futur. Voilà pourquoi il est important de limiter les dépendances.

hexa web logo
Hexa web
Des conseils pour un projet web ?
Nous contacter

Appliquer l'inversion de dépendances

L'inversion de dépendances consiste à dépendre d'abstractions plutôt que d’implémentations.

En d’autres termes, cela signifie que notre code devrait dépendre d'interfaces ou de contrats, et non d'implémentations spécifiques.

Étape 1 : Créer une interface pour les dates

Nous allons commencer par créer un type qui définira les méthodes dont nous avons besoin pour manipuler les dates dans notre projet :

date.ts
1export type DateService = {
2 format: (date: Date, format: string) => string
3 addDays: (date: Date, days: number) => Date
4 addMinutes: (date: Date, minutes: number) => Date
5 isToday: (date: Date) => boolean
6 formatDistanceToNowStrict: (date: Date) => string
7}

Étape 2 : Implémentation de date-fns

Dans cette étape, nous implémentons date-fns avec DateService afin de pouvoir l’utiliser dans le projet.

date.date-fns.ts
1import { DateService } from "@/modules/shared/date/date"
2import {
3 format as formatDateFNS,
4 addDays as addDaysDateFNS,
5 addMinutes as addMinutesDateFNS,
6 formatDistanceToNowStrict as formatDistanceToNowStrictDateFNS,
7} from "date-fns"
8
9export const DateFns: DateService = {
10 format: (date: Date, format: string) => formatDateFNS(date, format),
11 addDays: (date: Date, days: number) => addDaysDateFNS(date, days),
12 addMinutes: (date: Date, minutes: number) => addMinutesDateFNS(date, minutes),
13 isToday: (date: Date) =>
14 formatDateFNS(date, "yyyy-MM-dd") ===
15 formatDateFNS(new Date(), "yyyy-MM-dd"),
16 formatDistanceToNowStrict: (date: Date) =>
17 formatDistanceToNowStrictDateFNS(date),
18}

Étape 3 : Configuration des dépendances

Ici, nous configurons les dépendances du projet en utilisant des abstractions pour gérer les opérations sur les dates.

Cela nous permet de centraliser la gestion des librairies et de faciliter les futures modifications.

Il suffit de modifier ce fichier de configuration pour changer de dépendances dans tout le projet.

dependencies.ts
1import { DateService } from "@/modules/shared/date/date"
2import { DateFns } from "@/modules/shared/date/date.date-fns"
3
4export type Dependencies = {
5 date: DateService
6}
7
8export const dependencies: Dependencies = {
9 date: DateFns,
10} as const

Étape 4 : Utiliser l’interface dans le code

Maintenant que tout est configuré, il suffit d’appeler nos méthodes via notre objet dependencies dans notre code.

Ainsi, lorsqu’on modifie la dépendance dans notre fichier de configuration, cela impactera tout le projet.

article.tsx
1import { dependencies } from "@/config/dependencies";
2
3export const Article = ({ date }) => {
4 const formattedDate = dependencies.date.format(date, "dd/MM/yyyy");
5
6
7 return (
8 <div>
9 <p>Date de publication : {formattedDate}</p>
10 </div>
11 );
12};

Conclusion

L'inversion de dépendances est un principe puissant qui permet de rendre le code plus flexible et plus facile à maintenir.

En l'appliquant, nous pouvons changer de librairie sans avoir à modifier chaque instance de la librairie dans notre code. Cela nous permet de suivre les meilleures pratiques de développement et de garantir la pérennité de nos projets.

Ce pattern facilite également la testabilité du code. Il devient plus facile de mocker une dépendance.

Enfin, avec cette approche, le code reste propre, modulable et facile à mettre à jour.

Échangeons sur votre projet web

Présentez-nous votre projet web, nous vous recontacterons dans les prochaines 24h.