The topic is refering to the solution bellow and wonder what drawbacks it has in a generic context and also in a particular context.
Questions to be answered:
- What kind of architecture should be picked for this kind of problem/application in java world? (generic context)
- What drawbacks has the following way of modeling the app?
- Is the solution proposed acceptable for given context? (particular context)
Generic context:
We have the kind of application with a main pipeline with stream processing. Let's call this app AnimalSpecialDayCycle. Think to this like "a special day to an animals hotel".
Animals will come one by one and hotel will make a special day for them, by serving them food, train them, breed and a good sleep.
Lets consider an anemic domain model like:
Animal
- gender
DigestingSystem
- type (vegetable|meat)
- foodReservesLevel
MuscoskeletalSystem
- membersTypeSet (legs|wings|fins)
- hasTail
- musclesPowerLevel
ReproductiveSystem
- type (eggs|insemination)
Mood:
- energyLevel
- happiness
Proposed solution:
We split this app in different modules (separate apps) which comunicate between them through a common domain model called "Animal" (which is converted to JSON|XML).
Modules:
EatModule
EatServiceInterface (with method "eat(Animal)")
- MeatEattingService
- VegetableEattingService
TrainModule
TrainServiceInterface (with method "train(Animal)")
- FlyableTrainService
- RunningTrainService
- SwimmingTrainService
BreedModule
BreedServiceInterface (with method "breed(Animal)")
- EggsBreedingService
- InseminationBreedingService
SleepModule
SleepServiceInterface (with method "sleep(Animal)")
- FlyableSleepingService
- LaydownSleepingService
- StandingSleepingService
- UnderwaterSleepingService
Example of animals and service implementation they use:
- Dog (MeatEattingService, RunningTrainService, InseminationBreedingService, LaydownSleepingService)
- Horse (VegetableEattingService, RunningTrainService,
InseminationBreedingService, StandingSleepingService) - Aligator (MeatEattingService, SwimmingTrainService, EggsBreedingService, UnderwaterSleepingService)
- Parrot (VegetableEattingService, FlyableTrainService, EggsBreedingService, FlyableSleepingService)
Now, I am proposing to extend the Animal domain model in each module like:
public class AnimalEattingModel extends Animal {
public EattingServiceInterface eattingServiceInterface;
public void eat() {
eattingServiceInterface.eat(this);
}
}
The same for the other modules.
When an animal enters in a module and we create the object from JSON|XML (or whatever fromat has the message from previous module), we also set the proper implementation of service for that module.
(E.g.: if a Shark gets into the EatModule, we will set on its eattingServiceInterface field, the proper implementation for its type.)
Practically, I am looking for a way of keeping polymorphism but to split the behavior from object state, keeping the anemic domain model.
Advantages I see:
- decoupling business behaviour in its own classes, being able to easy modify them
- polymorphism and avoiding complex "ifs" structure and messy code in this service oriented arhitecture and anemic model
Downsides:
- dependencies: domain depends on service and service on domain
Particular context:
We developed the kind of app from above from scratch and let's say we are 50% done (serious effort was already invested).
We need "Animal" object in every module, because at the end of the module, we send an "event" with the "new state" of the Animal object.
I am not happy with the way of things are going on. Now when we are developing, we just hit a lot of "ifs" in our code.
We do not have subclasses because when I proposed to create them, it was answeared back that we should not create a subclass just because we have different values on one field, field which may be used only one time to do an "if" statement in one of the modules.
Now I consider what we need is polymorphism, but there is no chance to move away from SOA and anemic domain model, so I was thinking to the solution above.