I read a bit about DDD since at work I came upon a web application, supposedly written according to DDD principles.
Some things which I see however in this application look to me totally absurd. As I understood, the main point of DDD is about "ubiquitous language" shared by analysts and developers alike, such that the software artefacts roughly correspond to the notions/nouns/verbs/.. in the "ubiquitous language". This should allow for a more rapid translation of analysts requirements into functioning software, since, again roughly speaking, one has to think less about how to model analysts requirements, and maintenance is easier.
However what I see in the web application I came upon is that, for example, what would otherwise be modelled by a simple enumeration, such as
public enum Car{
AUDI,
BMW,
VOLVO
}
is modelled in the code by three different classes Audi, Bmw, Volvo.
Likewise calls to essentially the same service, e.g. CarService.buy(Car car)
, with different parameters values, are made by defining a separate class for each of these service calls, AudiService.buy()
, BmwService.buy()
, VolvoService.buy()
.
Is this a typical way to write DDD applications?
1 Answer 1
Is this a typical way to write DDD applications?
No, but maybe.
You are absolutely right that we don't normally create a class, or a class system, for every value of a property. In most implementations, something like a car make would be treated as an opaque label, with no distinction in behavior based on the value of the label.
So I would normally expect an implementation like:
class Make {
public final String name;
boolean IsEqual(Make that) {
return this.name.equals(that.name);
}
}
You might use a flyweight, rather than a wrapper around a primitive, for cases where the range of values is well understood and unlikely to change on short notice.
But... part of the point is to be tailoring the domain model to the needs of the specific business. The fact that Make is an opaque value in my domain doesn't mean that it is an opaque value in all domains.
Separate classes for Audi, BMW, and Volvo would certain make sense in a case where each of those Makes was tracking different state, or had different rules about how the data might change over time.
It just looks like someone said "ok, since it is a DDD application, let's model with class hierarchies what would be otherwise modelled with enumerations".
final class BMW extends Make {
BMW () {
super("BMW");
}
}
It's not wrong, but it looks weird; I wouldn't expect to see this sort of thing in the domain model without some additional evidence of its necessity.
A place where you might see something like this is one where you are leaning on the type system to ensure the correctness of multiple interacting parts.
class ExchangeService<M extends Model<M>> {
void swap(M lhs, M rhs);
}
class BMW extends Model<BMW> {...}
class Audi extends Model<Audi> {...}
void example(ExchangeService<BMW> exchange ) {
// COMPILE TIME ERROR
exchange.swap(new BMW(), new Audi());
}
switch
,if
etc. E.g. does each manufacturer/vendor have unique finance logic on how the car is actually paid for (allthough even then it seems a bit much, and maybe the correct abstraction is the finance policy itself, not the car manufacturer)? But generally, if they are getting seperate classes, there must be at least a conceptual difference, not just a requirement saying "for now we sell audio, bmw and volvo only".