2017-10-07 5 views
0

J'ai réorganisé notre moteur de disponibilité il y a quelques mois afin de faire passer notre logique d'une base de données à un micro service. A ce moment-là, la logique métier était assez simple:Comment déterminer la disponibilité combinée des salles DDD

  • Une ressource (salle de réunion, un bureau, un bureau vide, équipement) est disponible sur un laps de temps donné seulement si elle est pas déjà réservé (ex: pas d'autre la réservation en utilisant la même ressource)

  • Lorsqu'une ressource est pas disponible, les plus proches délais disponibles doivent être calculés

Pour couvrir ces besoins, je construit le petit morceau de code ci-dessous:

public class Schedule : IAggregateRoot 
{ 
    public int CityId { get; } 
    public int BuildingId { get; } 
    public int CentreId { get; } 
    public int ResourceId { get; } 

    public ICollection<Booking> Bookings { get; } 

    public Schedule(int cityId, int buildingId, int centreId, int resourceId, IEnumerable<Booking> bookings) 
    { 
     CityId = cityId; 
     BuildingId = buildingId; 
     CentreId = centreId; 
     ResourceId = resourceId; 
     Bookings = new List<Booking>(bookings); 
    } 

    public bool IsTimeSlotFree(DateTimeOffset startDate, DateTimeOffset endDate) 
     => Bookings.Any(/* Predicate */); 

    public IEnumerable<Availability> GetFreeTimeSlots(
     DateTimeOffset startDate, 
     DateTimeOffset endDate, 
     TimeSpan duration) 
    { 
     var nbSlots = Math.Floor((endDate - startDate)/duration); 
     for(int i=0; i<nbSlots; i++) { 
      /* yield return availability */ 
     } 
    } 
} 

public class Availability : ValueObject 
{ 
    public DateTimeOffset StartDate { get; set; } 
    public DateTimeOffset EndDate { get; set; } 
    public int ResourceId { get; set; } 
    public bool IsAvailable { get; set; } 
} 

public class Resource : Entity 
{ 
    public string Code { get; set; } 

    // Required for EF Core 
    protected Resource() { } 
} 

public class Booking : Entity 
{ 
    public DateTimeOffset StartDate { get; set; } 
    public DateTimeOffset EndDate { get; set; } 
    public string Status { get; set; } 
    public int ResourceId { get; set; } 

    // Required for EF Core 
    protected Booking() { } 
} 

Il y a quelques semaines, on m'a demandé de gérer des salles combinées (deux salles plus petites peuvent être fusionnées en une salle plus grande). Dans ce scénario une salle combinée est disponible SEULEMENT ses sous-salles et elle-même sont disponibles. En d'autres termes, j'ai besoin de vérifier plusieurs horaires pour déterminer la disponibilité et, malheureusement, mon niveau actuel d'abstraction ne le permet pas (un horaire, une salle).

La seule façon que j'ai trouvé est de récupérer une ressource et ses enfants (= subrooms) et ensuite créer un calendrier contenant un dictionnaire de ResourceId et des réservations.

public class Resource : Entity 
{ 
    public string Code { get; set; } 

    public Resource Parent { get; set; } 
    public ICollection<Resource> Children { get; set; } 

    // Required for EF Core 
    protected Resource() { } 
} 

public class Schedule : IAggregateRoot 
{ 
    public int CityId { get; } 
    public int BuildingId { get; } 
    public int CentreId { get; } 
    public int ResourceId { get; } 

    public IDictionnary<int, ICollection<Bookings>> Bookings 

    (...) 
} 

Je ne trouve pas cette solution vraiment élégante. Pour moi, une meilleure solution serait de récupérer les horaires et de les combiner afin de déterminer la disponibilité réelle. J'ai essayé plusieurs solutions mais j'ai fini par écrire du code spaghetti.

Avez-vous des idées sur la façon dont je pourrais re-concevoir mes agrégats pour gérer correctement ce nouveau concept?

Merci, Seb

+0

Y a-t-il des possibilités de sous-salles limitées connues à l'avance ou peut-on combiner deux pièces en une plus grande? – guillaume31

+0

Oui, ils sont connus à l'avance. Je sais quelles pièces peuvent être combinées. En fait, je stocke cette information dans un db :) – Seb

Répondre

1

Lors d'une estimation, le problème de base est que vous manque concepts de domaine dans votre modèle. Je suppose qu'il vous manque une représentation du catalogue de produits qui décrit l'inventaire disponible. Dans ce catalogue, vous aurez une entrée pour la pièce 101 et une entrée pour la pièce 102. Si ces pièces peuvent être emballées ensemble, vous aurez également une entrée pour le paquet [# 101 et # 102].

Donc, la disponibilité d'un paquet est facile - prenez l'intersection des horaires des éléments dans le paquet. Puisque vous connaissez le contenu de l'emballage, il est facile de trouver les horaires dont vous avez besoin pour vous réconcilier.

Notez que vous pouvez mettre à jour le catalogue en ajoutant ou en supprimant des packages sans affecter les réservations.

Vous devez, bien sûr, comprendre comment vous allez faire face à la réservation de plusieurs chambres. Il y a quelques possibilités; Le plus simple, et celui que j'imagine le plus familier pour vos utilisateurs, est de permettre aux agrégats de planification d'accepter des réservations qui se chevauchent, en définissant un indicateur réservé pour suivre le cas où des actions compensatoires doivent être prises. Une autre alternative consiste à réserver les paquets en utilisant le modèle saga; où le processus faisant l'orchestration de la réservation sait pour annuler la réservation des salles si le paquet entier ne peut pas être réservé.

Vous pourriez simplifier les choses en déplaçant tous les horaires dans un seul agrégat; élever la limite de cohérence à plus grande échelle (la propriété, peut-être, plutôt que des pièces individuelles); Cela écarte l'autonomie et l'échelle des grandes pièces. Presque tout modèle de domaine qui inclut la planification pour les ressources a un concept d'un jour en tant qu'agrégat séparé.

+0

Merci pour cette réponse utile. Je vais modifier mon modèle pour ajouter ce concept de package. Si je comprends bien, vous obtenez l'horaire d'un paquet au lieu de l'obtenir pour une seule ressource. Ai-je raison? Aussi le moteur de disponibilité vit dans un "micro service" et ne sait pas comment annuler/faire une réservation. Il est seulement utilisé pour obtenir la disponibilité des ressources. – Seb

0

Sans cela, vous continuerez à agréger pour toujours. Différents contextes peuvent garder une représentation différente du jour:

  • Les réservations peuvent avoir des types de chambres et les disponibilités
  • prix peut avoir le type de chambre et le prix
  • réception peut avoir l'attribution des chambres, les arrivées et les départs