Designing DDD aggregates for pairing mechanism

88 views Asked by At

I'm developing an application following Domain-Driven Design (DDD) principles, and I need help modeling the following requirements:

Main Purpose:

An application to control sound Players (Speaker) within a HouseHold through RemoteControl. Think of a RemoteControl as a sound mixer with 1-N channels, Where each Channel controls different Player.

Relationships:

  • Each Player is associated with a single HouseHold.
  • A HouseHold can have one or many Players.
  • RemoteControl is not associated with a HouseHold.
  • Each RemoteControl has a list of Channels.
  • Each Channel is uniquely identified by its position (index) within the RemoteControl.

Channel-Player Pairing:

  • A Channel can be paired with a Player. This pairing designates that the Channel controls the associated Player.
  • A single RemoteControl cannot be paired with the same Player on multiple channels.
  • However, different instances of RemoteControl can be paired with the same Player, once each.
  • The goal of this pairing is to locate a Player not by its ID (PlayerId) but through the RemoteControl-Channel pair.

Remote Control Details:

  • The RemoteControl is essentially a simple IoT device with an array of volume inputs.
  • It is unaware of the players and their IDs.
  • Each request from the client includes remoteControlId, channelPosition, eventType and value.
  • Using the pairing information, the application should identify the associated Player and update its state accordingly.

This is what I came up by now: The following entities with the intention of defining Player, RemoteControl, and HouseHold as roots.

Player:

  • id
  • houseHoldId
  • name
  • volume

RemoteControl:

  • id
  • channelsCount / listOfChannels

HouseHold:

  • id
  • Map<PairdChannel,String> map/List pairs

PairedChannel: (V/O)

  • remoteControlId
  • channelPosition

Pair:

  • id
  • playerId
  • pairedChannel

And the relevant use-cases in app services might be:

HouseHoldAppService:

function pair(houseHoldId, remoteId, channelPosition, playerId) {
    houseHold = repo.getById(houseHoldId)
    if (!houseHold) throw...
    remote = remoteService.getById(remoteId);
    if (!remote) throw 
    player = playerService.getById(playerId);
    if (!player) throw 
    pairedChannel = new PairedChannel(remote.id, channelPosition);
    pair = Pair.create(pairedChannel, player.id);
    houseHold.add(pair);
    houseHoldRepo.add(houseHold);
}

RemoteControlService:

function changeVolume(remoteId, channelPosition, value) {
    pair = houseHoldService.findPair(remoteId, channelPosition);
    if (!pair) throw
    playerAppService.changeVolume(pair.playerId, value);
}

PlayerAppService:

function changeVolume(playerId, value) {
    player = repo.getById(playerId)
    if (!player) throw
    if (!player.changeVolume(value)) return
    repo.store(player)
    dispatch(player.dequeue())
}

An high-level flow of the app:

  1. Dedicated driver emit new event when speaker is found (with speaker data + houseHoldId)
  2. PlayerAppService catches this event, and create new Player domain object.
  3. HouseHoldAppService catches the PlayerCreatedEvent, and if the HouseHold is not exists - it creates it.
  4. Another dedicated driver emits event when Remote control is connected.
  5. RemoteControlAppService catches this event, and create new RemoteControl domain object
  6. The user pair Channel to Player by using API such: url: /household/:id/pair/ body: { remoteId, channelPosition, playerId }
  7. The Remote can change the volume of the paired Player using API such: url: /remotecontrol/:id/channel/:channel/changeVolume/:volume
  8. The dedicated speaker driver can always emit events to change the volume of the Player by it's id. For example: event: changeVolume, data: { playerId, volume }

I'm seeking advice and/or feedback on how to structure these relationships and implement the pairing mechanism effectively within the context of Domain-Driven Design. Any insights, advice, or code examples related to aggregate design would be appreciated.

0

There are 0 answers