If any of the requirements change, it's easy to either add more predicates or relax/even outright remove them.
I don't deny there's a certain art to that, and I can't explain it all myself. But I don't even necessarily mean amazing clever type tricks like you might see in Haskell or something, I mean that something as simple as "I've changed the definition of what a 'Customer' is in some fundamental manner, so I'm going to rename that class to 'CustomerNew', use the compiler to point me at every single place that breaks, audit it, change the local name to CustomerNew, and then, once everything is fixed, use my IDE's rename feature to rename CustomerNew back to Customer before my final commit". Many times you can get by just by renaming a field or something to similar effect, but in the worst case you may need to audit everything.
It's one of the more tedious bits of the job sometimes, but net-net this can still be a timesaver, if you account for the full cost of the trickle of bugs this sort of thing can prevent.
On the other hand, if you make your internal representation support more complexity than what you hand out to your users, there arises the question of how you simplify (probably lossily!) or break when you wind up with data that can't be expressed with the simpler interface. But you might well be saving yourself a costly data migration down the line. Also a decision with trade-offs that could potentially go either way.
Customer: 1 - 1: Set(Dates)
What if it was Customer 1 - *: Contract: 1 - 1: Set(Dates)
Overlap achieved. SELECT event FROM events WHERE endDate<"2021"
After: Whatever additional complexity you
add to your codebase to query end
dates.https://dbfiddle.uk/?rdbms=postgres_11&fiddle=50e6a963cd1db0...
(YMMV, obvs.)
SELECT event FROM events WHERE startDate < "2021"
then all but one of the results (the one with the greatest `startDate`) will also have an implicit end-date prior to 2021.It gets uglier if you need to find the contract valid on a certain date based off of a join.
These issues can be covered up with code as it will a easier to have reusable functions, but it makes the job of a data analysts much more difficult and error prone.
The timeline example is actually very telling. A lot of times you’d actually want to encode overlapping time periods at the edges.
You’d be laughed out off a meeting where a business asks about this and you smugly explain how it is unrepresentable.
I guess what I’m saying is that it might be worth over designing your system a bit to leave you some wiggle room, unless you have hard guarantees that something should be “impossible”