0

When domain modelling, should a valid constraint - or "natural" constraint - be modelled, even if there are no current business processes which rely on the constraint being asserted.

As an example: A model contains a class Person, with sub-types Adult and Child. Child has the attributes father and mother, which are both instances of Adult. Here are some "natural" constraints:

  • A Child is younger than both parents. { child.age < child.father.age and child.age < child.mother.age }

  • The father is not the same instance as the mother { child.father != child.mother }

  • Father is male, mother is female {child.father.sex == male and child.mother.sex == female}

Is it appropriate, or advisable, to model these constraints even when there are no current business processes which rely on them.

I'm really interested in the balance between the desire to only model actual requirements, against the fact that it is often easier to remove a constraint than it is to add one later down the line.

Update

In some answers and comments below, the first and third constraints in my example (of the child/parent model) are said to be invalid and counter-examples are given. But the second may be worth implementing. Additionally, age >= 0 was given as an example of a constraint you might model even if not specified in the domain requirements. I understand that age >= 0 is pretty much "common sense", but there seems to be an area where unspecified constraints go from, "yep, that's worth implementing" to "I wouldn't risk it".

I would be interested in hearing experiences of where you might draw this line. @DocBrown's answer does this nicely.

13
  • 2
    You Aren't Gonna Need It
    – devnull
    Jan 21 at 18:43
  • Indeed, "the desire to only model actual requirements" points to the YAGNI principle, but I'm interested in whether there is a balance to be struck. Jan 21 at 18:46
  • An important nonfunctional requirement for practical software projects is the ability to change the behaviour in the future. So overconstraining the system like this is typically a bad idea, especially if it's unclear what your actual requirements are. Verify everything that your current code needs to work correctly (e.g. that age is non-negative). I don't think it is always easy to relax constraints later, because parts of the code might have started depending on that constraint implicitly. And in practice, many entities will be so abstract that there are no "natural" constraints anyway.
    – amon
    Jan 21 at 19:41
  • 2
    If code implicitly depends on a recognised constraint, then removing the explicit enforcement may require changes to the code which relies on it. Lets say you enforce "Child is younger than both parents" by a database contraint. Now you build code on it which takes this rule for granted. After a while, you get the new requirement that the system shall not only allow natural parents, but also adoptive parents. You can remove the contraints from the database (which is easy), but then you have to change a certain amount of code which did not deal with the edge case of the invalid constraint.
    – Doc Brown
    Jan 21 at 20:49
  • 1
    a person's age can be negative if you set the current date to before they were born, ie you have some report based on a historical time. "what was the childs age when the parent bought this insurance policy" etc
    – Ewan
    Jan 21 at 22:15

4 Answers 4

7

In the past, I have experienced both kinds of situations:

  • cases where a system contained things like constraints which were surely added in good faith, but were never really needed - and later turned out to become an obstacle

  • cases where a system missed certain constraints, which lead to deficiencies in data quality that only became apparent when additional functions were implemented somewhat later

Hence, the decision between both cases isn't always easy. Some rules-of-thumb:

  • When you don't have a real use case at hand which can verify the effectiveness and correctness of a certain constraint, you will be better off not to implement them - it's quite likely you make them overly restrictive

  • However, when you can envision a certain use case which might be implemented in the future which expects a certain data quality, modeling a constraint right now may make things easier tomorrow.

Also, have a look at how the data is coming into the system:

  • When the data will be entered manually, there is always the use case of "entering the data", which is often overlooked. This use case may benefit from strict constraints, since violations of those may be indicators for errors due to the manual process. However, we may have to accept that certain data isn't available at the time of entering it, and when an overly strict constraint blocks users to enter data, be sure they find ways to circumvent that block by entering false data.

    For example, what if you don't know if the age of a child will really be required? Will you still force users to enter some date-of-birth, even when they don't have this data at hand? The system may contain a lot of use cases which don't make use of the date of birth or age. So a more "natural constraint" might be age == null || age >= 0, not just age >= 0 - so as you can see, modeling things which feel "natural" can very easily fail.

  • When a larger amount of data will hit the system through some import process, and you want to be able to clean the data up after the import, you may allow the data to be imported first, without too much constraint checking, and then clean it up afterwards before further processing. Here, too strict constraints could block the import.

It may be a good idea to place certain constraints into the domain model description, in an informative manner, but not in a manner which pretends those constraints should be implemented necessarily as part of some validation or fixed database constraint. This is my understanding of YAGNI: during analysis of a system, documenting certain ideas for future requirements is ok, since it usually does not cause huge maintenance effort to fix the documentation afterwards. But when it comes to implementing those ideas in code, better avoid to invest any effort in things you you cannot verify by the use cases contained in the very next release of your software.

Let me add that IMHO there are no "absolute truths" about domain objects which can be modeled as "natural constraints" without any risk when there is not enough context to decide if those constraints really apply in the current system. We are building all kinds of software where domain objects might reflect certain aspects of real world objects. Still we should not take those expected "real-world properties" for granted - what in the real world seems "natural" is not necessarily "natural" in our software system, that can differ at some point.

For example, when the task is to create a software which tunnels certain data from a system A to a system B with all its original failures, then you will approach this differently than in a context where the task is to provide data of a certain quality. So before modeling constraints just because they feel "natural" to the designer, one should at least be familiar with the overall context and the overall goals of the system.

1
  • This is the sort of comparison I was hoping for, thanks. I had in mind situations where you might inadvertently have invalid data due to not having a particular constraint applied, which later on becomes problematic. Jan 21 at 21:42
3

The first constraint may be violated in the case of a legal guardian, who is not otherwise a relative. Also, it relies on having multiple age fields filled out, which may pose certain practical data collection and validation challenges.

The third constraint unwisely imposes binary gender requirements, and ignores several ways in which fertility treatments and adoptions commonly yield family households that don’t have a single mother or a single father.

Weekly exception reporting on age and gender may help you to better understand the population you’re serving, and how well your data collection processes are functioning. But I wouldn’t want to prevent enrolling or otherwise serving a user based on either of those rules, given that the business doesn’t care about those details.

The second constraint you propose does appear worth implementing. It gets at the notion of one record corresponding to one human. Requiring that they be distinct seems reasonable.

4
  • Note that the child/parent example was simply an example. I think this is where the domain becomes important. (I too would prefer to avoid a gender politics discussion) Legal guardianship and gender identification do not violate the constraints I gave, as a child will still have a mother and a father meeting those constraints even if they don't live together as a family etc. Jan 21 at 20:25
  • For example, the constraints I mentioned may be more important in a medical/ancestry context and less important in a school environment where legal guardianship is more important Jan 21 at 20:26
  • 4
    @KyoheiKaneko And this is precisely why modelling your actual domain is so important. A system for tracking school attendance will have entirely different constraints from genealogical software. But for both, reality is often so complex that these kinds of extra constraints are going to be harmful.
    – amon
    Jan 21 at 20:59
  • @amon this is a valid point which I hope will be expanded on in other answers Jan 21 at 21:04
2

Requirements change over time, so if you add "natural" constraints you may end up paying the development cost twice (once to add them and one to remove them once the requirement changes).

Additionally as J_H points out, just because you think something is valid doesn't make it so (I am going to stay our of the specifics of gender politics) the broader point is that often as developers we don't have a complete understanding of the problem domain, hence we should leave it to the domain experts to tell us what constraints are important to the business.

Like all rules there are sometimes exceptions, but most of the time YAGNI, is a good rule of thumb.

1

No.

Unless you have a requirement, do not add code. Your example being so full of holes is an excellent example of the problems treating code classes like "real" things can cause.

The Child class is not a Child, its a set of data and functions for some business or game or something which models children. The rules for the business or game are not limited by logic or real life so if you try to add these rules you are just adding future bugs.

Some good examples of where you can go wrong with these "natural" rules can be found in internationalisation.

https://shinesolutions.com/2018/01/08/falsehoods-programmers-believe-about-names-with-examples/

9
  • That's a good link, thanks. I'm not sure I agree with your thoughts on domain models though. The wikipedia entry for domain models has this sentence: "The domain model is a representation of meaningful real-world concepts pertinent to the domain that need to be modeled in software." I agree with this description - the model represents the "real-world concept" you are modelling. That is, a "Child" class represents whatever a "child" is in the domain, which may very well be a physical child with natural parents. Jan 21 at 22:35
  • i think you are ignoring the second sentence "The concepts include the data involved in the business and rules the business uses in relation to that data" DDD is about modeling business rules, its not for physics simulations
    – Ewan
    Jan 21 at 22:37
  • Domain modelling isn't just about DDD (which, I'm not attempting btw). The concepts do include those business related things, but those businesses exist in the real world which has external constraints - which may not be applicable currently in the business - but which exist none-the-less Jan 21 at 22:39
  • Business Rules don't exist in the real world. they are made up rules and can be anything. But your example shows that, even if they were subject to real world rules, programmers are not able to work out what the real world rules are.
    – Ewan
    Jan 21 at 22:45
  • 1
    @KyoheiKaneko: I think Ewan has a point, see my last edit in my answer.
    – Doc Brown
    Jan 22 at 6:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.