📐 Construire une app en JS
12 Dependances

Les dépendances

Nous avons écrit les fonctions login() et book(). Notre code ne passe pas encore le test.

// Injection des dépendances
const app = new App(testDependencies())
 
// Réalisation de la location
await app.run([
    login({email:"faketenant@mail.com", password:"secret"}),
    book({
        accomodationId:"accomodation-1", 
        adults:2, children:3, 
        from : new Date("2024-06-02"),
        to :   new Date("2024-06-02"),
        })
]);
 
// Le calendrier comporte la réservation
const bookings = await app.dependencies.listBookingsForAccomodationId("accomodation-1")
expect(bookings).toHaveLength(1)

Il manque encore trois choses :

  • les dépendances
  • la classe App
  • le constructeur de l'objet Booking appelé dans la fonction book()

Booking.of({tenantId:user.id, accomodationId,adults,children,from,to})

Commençons par les dépendances

Un container

Les dépendances sont un container que l'on dépose dans l'application.

Pour les tests, on va utiliser un container de test contenant les dependances optimisées : simplifiées (mais représentatives) et rapides.

Pour l'environnement de production, on ce sera un autre container.

Observons les dépendances imaginées dans nos 2 cas d'usage :

Dans book() :

  • await dependencies.bookings.save(booking);

Dans login() :

  • await dependencies.users.findByEmail(email);

Dans notre test :

  • await app.dependencies.listBookingsForAccomodationId(accomodationId)

Il suffit de ces 3 fonctions asynchrones pour construire le container testDependencies nécessaire pour notre test.

Rien de plus.

Inutile de créer des tables dans une base de données. Retardons le choix de l'ORM et même celui de la base de données. ** Retarder les choix technique = Imposer une architecture modulaire **

Compartimenter le container

Dans notre container des dépendances, on veut que ce soit bien rangé.

Lorsqu'on regarde nos 3 fonctions, deux compartiments émergent naturellement :

  • Un compartiment pour les utilisateurs
  • et un autre pour les réservations.

D'ailleurs, nos cas d'usages n'ont pas besoin de tous les compartiments.

Dans le compartiment user :

  • findByEmail(email)

Dans le compartiment bookings :

  • save(booking)
  • listBookingsForAccomodationId(accomodationId)

Pour briller en réunion, appelons ces compartiments des repository.

UserRepository

Commençons par le compartiment des utilisateurs. Nous avons besoin du compartiment de test. Alors écrivons uniquement ce code.

class MemoryUserRepository {
    _users = []
    
    async findByEmail(email) { return this._users.find(user => user.email === email)}
}

Pour implémenter findByEmail(), notre compartiment a besoin de la liste des utilisateurs enregistrés. Cette liste fait partie de l'état du système. Alors on la créé, sous la forme d'un attribut _users.

Le jour ou il faudra aller chercher cette liste dans une base de données, on créera un autre classe SQLUserRepository avec exactement les mêmes méthodes.

NB : Pour assurer la cohérence entre ces 2 classes, on utilisera TypeScript pour décrire une interface UserRepository. Mais restons sur Javascript pour l'instant.

Un problème saute aux yeux. Le tableau _users est vide. Aucun utilisateur n'est enregistré dans notre système. C'est vrai, mais laissons cela à plus tard dans la mesure ou cela n'empèche pas le code de s'exécuter.

BookingRepository

Maintenant attaquons-nous au compartiment des réservations, en procédant de la même façon.

class MemoryBookingRepository {
    _bookings = [];
 
    async save(booking) { this._bookings.push(booking) };
    
    async listBookingsForAccomodationId(accomodationId) { 
        return this._bookings.filter(booking => booking.accomodationId === accomodationId)
    }
}

Hey mais c'était facile !

Remarquons au passage que l'on manipule des objets dont on ignore tout du contenu !

Le container

Nous disposons de tout le nécessaire pour construire notre container des dépendances de test :

export const testDependencies = {
    users : new MemoryUserRepository();
    bookings : new MemoryBookingRepository()
}

Que reste-il sur notre liste ?

  • les dépendances
  • la classe App
  • le constructeur de l'objet Booking appelé dans la fonction book()

Codons la classe App pour faire passer notre test.