let's say I have the following aggregate:
class Road: company_id: int # another aggregate name: str stops: List[Stop] def add_stop(stop: Stop): stops.append(stop) class Stop: precission: Precission latitude: float longitude: float address: str
This is just a minified example. Let's also say that to create stops, I need to call a third party to geocode the object. Something like:
# this returns a correctly initialized Stop object StopsDataAccess.get_by_address(address)
Now let's say that I want to add a stop to a road, so I would have an application service that would be similar to something like this:
class AddStopToRoadService: def run(road_id, address): road = RoadRepository.getById(road_id) stop = StopsDataAccess.get_by_address(address) road.add_stop(stop) RoadRepository.save(road)
As it is, I do not see a lot of problems with this approach. The problem I have is when the following domain requirement comes:
- Only stops with the precision
EXACTcan be added to a route, those that are
UNKNOWNcannot be added. Also, this can be changed by every company, so for instance, a different company can accept only
APPROXIMATEor all of them.
So, to approach this I do the following:
class Road: ... allowed_precission_types: List[Precissions] ... def add_stop(stop: Stop): if stop.precission not in self.allowed_precission_types: raise StopNotAllowed() stops.append(stop)
allowed_precission_types would be filled by the
RoadRepository. The problem I see with this approach is that that the list of allowed precision values is part of the
Company aggregate. So I'm not sure if it really fits in there. Am I breaking encapsulation? What would be the correct approach?