NestJS - Restez simple, stupide
Imaginez, un nouveau collègue commence ce matin, et il lui suffit de consommer une variable d'environnement dans votre application Nest. Heureusement, il accepte de faire la tâche, d'extraire simplement une variable via process.env. Jusqu'à ce que quelqu'un lui dise, nous n'y accédons pas process.envdirectement, mais nous utilisons plutôt le module de configuration .
Au cours des dernières années, j'ai guidé plusieurs équipes sur des projets NestJS, et la plupart d'entre elles ont simplement suivi les documents NestJS, elles n'ont pas commencé par pourquoi .
"Pourquoi faisons-nous ce que nous faisons?"
Mais j'ai affronté les bons, les mauvais et même les mauvais côtés du cadre. Et j'ai commencé à me demander "est-ce que Nest est avec nous ou contre nous ?" . Et étonnamment, j'ai conclu que certaines parties de Nest travaillaient en fait contre nous.
Face à notre ennemi
Ne vous méprenez pas, j'aime toujours Nest. Mais je suis en fait assez content que la partie Configuration de Nest ne soit pas livrée prête à l'emploi. En fait, @nestjs/config est un module central de Nest, que vous pouvez installer séparément, donc uniquement si vous en avez besoin. Et le plus drôle, c'est que sur presque tous les projets sur lesquels j'ai travaillé, le module de configuration a été implémenté pour les raisons suivantes :
- On dirait que le module de configuration est la voie à suivre dans Nest.
- Il y a pas mal de documentation disponible ( et clairement nécessaire ).
- Il suit la même structure opiniâtre.
- On pourrait l'étendre avec la validation ( une bonne pratique que j'ai vue beaucoup moins )
Ce qui manque au module de configuration
En 1 mot, simplicité . L'accès à une variable d'environnement est l'une des tâches les plus courantes au cours d'une journée et doit donc être aussi simple que possible. Ainsi, le module de configuration devrait fonctionner avant nous, pas contre nous.
Pour donner un exemple, l'accès à la propriété foodans l' appespace de noms nous oblige à implémenter quelque chose comme ce qui suit.
// app.config.ts
const appConfig = register('app', () => ({
foo: process.env.APP_FOO
}))
// app.module.ts
ConfigModule.forRoot({
load: [
appConfig,
],
}),
]);
// MyService.ts
class MyService {
constructor(
private configService: ConfigService
)
myMethod(){
// now we can finally get the env var
const foo = this.configService.get<string>('app.foo')
}
}
Nous supposons que la réponse sera un string, mais nous ne le saurons qu'au moment de l'exécution. Nous ne pouvons pas simplement utiliser notre éditeur ou IDE pour vérifier s'il app.fooexiste réellement. Une faute de frappe peut être faite en une fraction de seconde, ce qui entraîne des minutes (ou des heures) de débogage. Et la conclusion douloureuse est que ce que nous voulions réellement, c'était accéder à la app.foopropriété. Mais nous nous sommes retrouvés avec le soi-disant problème gorille-banane-jungle .
« … Parce que le problème avec les langages orientés objet, c'est qu'ils ont tout cet environnement implicite qu'ils transportent avec eux. Tu voulais une banane mais ce que tu as eu c'est un gorille tenant la banane et toute la jungle. "
— Joe Armstrong, créateur du langage de programmation Erlang
Nest a introduit une sorte de solution de contournement pour pouvoir vérifier le type d'une propriété lors de l'exécution, en passant un objet options.
const foo = this.configService.get<string>('app.foo', { infer: true })
- que nous ciblons une propriété qui existe réellement ;
- que le peluchage et la mise en évidence du code, etc. dans notre IDE fonctionnent ;
- que le type du bien, s'infère par référence ;
- et que nous pouvons utiliser la variable d'environnement en dehors du champ d'application de Nest.
En tant qu'ingénieur, nous devrions toujours prendre du recul et nous demander si nous implémentons toujours l' acronyme Keep it simple, stupid . Et comme nous le voyons maintenant, le module de configuration enfreint clairement cette loi.
Bien que je semblerais être pessimiste, si je n'introduisais pas une autre approche. Un plus pratique. Une approche qui serait encore opiniâtre, mais qui s'attaque également aux problèmes évoqués précédemment. Alors dis juste bonjour à mon petit ami :
export const appConfig = {
foo: process.env.APP_FOO
}
// and consume it elsewhere...
const foo = appConfig.foo
Et même dans des applications plus importantes, nous pourrions implémenter quelque chose de similaire. Cependant, il serait utile d'introduire un configrépertoire séparé dans une structure de répertoires qui ressemble à ceci :
├── src
│ ├── foo-module
│ │ ├── foo.controller.ts
│ │ ├── foo.service.ts
│ │ └── foo.module.ts
│ │
│ └── config
│ ├── appConfig.ts
│ └── dbConfig.ts
│
├── package.json
└── nest-cli.json
En tant qu'ingénieur, nous devrions toujours commencer par pourquoi . Nous devrions nous forcer à penser hors des sentiers battus plutôt que de continuer à penser à l'intérieur. Même si cela signifie que nous quitterions en partie un cadre opiniâtre comme NestJS.
Pour terminer avec une citation célèbre : "Faisons en sorte que l'accès aux variables d'environnement soit à nouveau génial" . Concentrez-vous sur les bananes, pas sur les gorilles dans les jungles.
![Qu'est-ce qu'une liste liée, de toute façon? [Partie 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































