Skip to main content
added 737 characters in body
Source Link
VoiceOfUnreason
  • 34.7k
  • 2
  • 45
  • 84

Is a domain object in a valid state if it is initialised with default values using a zero arguement constructor/initialised with empty/null values?

It can be.

There is nothing against the rules about creating a valid domain object using a default constructor.

There is nothing against the rules about creating a valid domain object with empty values.

There is nothing against the rules about creating a valid domain object that lacks optional elements.

There is nothing against the rules about creating a valid domain object using nulls.

Where problems occur: creating domain objects that don't obey their own semantic algebra.

The correct implementation depends on a correct interpretation of the semantics.

It's a normal thing to take a forgiving representation of a domain concept and by steps apply additional constraints. This is one of the areas where implementation languages that make it easy to add types (ex: F#) have advantages over clumsier languages like Java.

For example, if we have a domain that cares about numbers, and within that domain are some capabilities that are specific to prime numbers, or Mersenne primes, then a natural mechanism to use is to create three different types; making explicit the notion that there are different sets of constraints to be applied to the inputs in different parts of your solution.

Number n = new Number(...)
Optional<Prime> p = n.prime()
if (p.isPresent()) {
    Optional<MersennePrime> mp = p.mersennePrime()
    // ...
} 

In this sort of design, the "validation" that the number really is a Prime would exist within Prime constructor itself. In a context where we need the additional constraint that the parameter is a Mersenne prime, we use a Prime -> MersennePrime conversion, ensuring that the knowledge of the Mersenne constraint has one authority ("don't repeat yourself").

"Make the implicit, explicit"

Is a domain object in a valid state if it is initialised with default values using a zero arguement constructor/initialised with empty/null values?

It can be.

There is nothing against the rules about creating a valid domain object using a default constructor.

There is nothing against the rules about creating a valid domain object with empty values.

There is nothing against the rules about creating a valid domain object that lacks optional elements.

There is nothing against the rules about creating a valid domain object using nulls.

Where problems occur: creating domain objects that don't obey their own semantic algebra.

The correct implementation depends on a correct interpretation of the semantics.

It's a normal thing to take a forgiving representation of a domain concept and by steps apply additional constraints. This is one of the areas where implementation languages that make it easy to add types (ex: F#) have advantages over clumsier languages like Java.

Number n = new Number(...)
Optional<Prime> p = n.prime()
if (p.isPresent()) {
    Optional<MersennePrime> mp = p.mersennePrime()
    // ...
} 

"Make the implicit, explicit"

Is a domain object in a valid state if it is initialised with default values using a zero arguement constructor/initialised with empty/null values?

It can be.

There is nothing against the rules about creating a valid domain object using a default constructor.

There is nothing against the rules about creating a valid domain object with empty values.

There is nothing against the rules about creating a valid domain object that lacks optional elements.

There is nothing against the rules about creating a valid domain object using nulls.

Where problems occur: creating domain objects that don't obey their own semantic algebra.

The correct implementation depends on a correct interpretation of the semantics.

It's a normal thing to take a forgiving representation of a domain concept and by steps apply additional constraints. This is one of the areas where implementation languages that make it easy to add types (ex: F#) have advantages over clumsier languages like Java.

For example, if we have a domain that cares about numbers, and within that domain are some capabilities that are specific to prime numbers, or Mersenne primes, then a natural mechanism to use is to create three different types; making explicit the notion that there are different sets of constraints to be applied to the inputs in different parts of your solution.

Number n = new Number(...)
Optional<Prime> p = n.prime()
if (p.isPresent()) {
    Optional<MersennePrime> mp = p.mersennePrime()
    // ...
} 

In this sort of design, the "validation" that the number really is a Prime would exist within Prime constructor itself. In a context where we need the additional constraint that the parameter is a Mersenne prime, we use a Prime -> MersennePrime conversion, ensuring that the knowledge of the Mersenne constraint has one authority ("don't repeat yourself").

"Make the implicit, explicit"

Source Link
VoiceOfUnreason
  • 34.7k
  • 2
  • 45
  • 84

Is a domain object in a valid state if it is initialised with default values using a zero arguement constructor/initialised with empty/null values?

It can be.

There is nothing against the rules about creating a valid domain object using a default constructor.

There is nothing against the rules about creating a valid domain object with empty values.

There is nothing against the rules about creating a valid domain object that lacks optional elements.

There is nothing against the rules about creating a valid domain object using nulls.

Where problems occur: creating domain objects that don't obey their own semantic algebra.

The correct implementation depends on a correct interpretation of the semantics.

It's a normal thing to take a forgiving representation of a domain concept and by steps apply additional constraints. This is one of the areas where implementation languages that make it easy to add types (ex: F#) have advantages over clumsier languages like Java.

Number n = new Number(...)
Optional<Prime> p = n.prime()
if (p.isPresent()) {
    Optional<MersennePrime> mp = p.mersennePrime()
    // ...
} 

"Make the implicit, explicit"