Live data from Hacker News

Applying “make invalid states unrepresentable”

kevinmahoney.co.uk

91–100 of 193 posts

Re: Applying “make invalid states unrepresentable”

#91
My favourite real-world example is something like: you have a React component which accepts the boolean props `showFoo`, `showBar` and `showBaz` to control its mode. The intention is that exactly one of `foo`, `bar` or `baz` will be shown at any given time, but that invariant is maintained only loosely, e.g. by a parent component which holds three flags in its state and mutates them in tandem inside various event handlers.

The obvious problem is that those three props can easily get out of sync if you make a mistake in updating them, and the equally obvious solution is to replace them with a single prop (e.g. `show` or `mode`) which contains a value from some enumeration — maybe just the name of the thing to show, or a numeric ID that is given meaning elsewhere, or (galaxy brain) a component. That way the invariant is maintained strongly and automatically by the representation itself.

This example sounds vacuous — who would ever use three booleans in the first place? — but in practice it’s very easy for UI code to incrementally get into this mess over time without anyone noticing. The situation is also often more subtle, e.g. the invariant is more complex than “exactly one flag is true”, which makes it harder to spot that you can model all the valid states with a finite enumeration.

Re: Applying “make invalid states unrepresentable”

#92
post #68

This is very much like database normalization, in that it has the benefit of making invalid data impossible, but the drawback of often making queries into the data much more cumbersome and usually also inefficient. As with database normalization, it is a good idea to first do it as much as possible, and then denormalize again until it is fast enough.

I have always has the idea of a database that does the denormalizations you want automatically for you.

Essentially, you keep the DB in a normalized state. You define views of the DB that you want. Then the DB keeps those views as tables for you, and the DB does all of the hard work of keeping those view tables consistent with the denormalized data. Essentially the DB does the atomicity, cache-invalidation, and cache-updating for you.

You get performance, and you get the certainty that invalid states are un-representable.

I guess the biggest blocker here is in automatically determining what fields do and do not need to be update automatically?

Re: Applying “make invalid states unrepresentable”

#93
post #49

I like the concept but I’ve seen a fair few examples of where the developers and users clearly had differing opinions about which states are invalid! Dates are a rich vein of examples. Some users will happily consider “25th December” to be a date, without any year, because it might be the name of a folder in which they store their Christmas stuff. More seriously, genealogists or historians may want to record “25th De…

This is so obvious now that you’ve said it. I can see so many possibilities. I feel as though my eyes have been opened.

Re: Applying “make invalid states unrepresentable”

#94
post #55

Earlier quoted context omitted.

Additionally, turning (startDate, endDate) into a set of dates will make the code more complex in some places. Before: SELECT event FROM events WHERE endDate After: Whatever additional complexity you add to your codebase to query end dates.

It's not that much more complex: if you do SELECT event FROM events WHERE startDate then all but one of the results (the one with the greatest `startDate`) will also have an implicit end-date prior to 2021.

Doing all the logic in SQL requires more complexity using subqueries.

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.

Re: Applying “make invalid states unrepresentable”

#95
post #94
post #55

Earlier quoted context omitted.

It's not that much more complex: if you do SELECT event FROM events WHERE startDate then all but one of the results (the one with the greatest `startDate`) will also have an implicit end-date prior to 2021.

Doing all the logic in SQL requires more complexity using subqueries. 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.

Uglier than having to find the record after the one you're inserting (so you can determine your new record's end date from the subsequent record's start date) and the record before (so you can modify its end date to match your new record's start date)?

Re: Applying “make invalid states unrepresentable”

#96
post #90

This line raised a huge red flag for me: "If the customer doesn’t have a fixed contract, it is assumed they are on a default contract" No. Don't assume, specify. Explicitly. If this is part of your specification, have a DefaultContract entity of some kind somewhere. And don't call this table just "Contracts", make it clear that those exist in addition to or overlay a default contract. It might sound like overkill, bu…

Yeah that's a lot to be said about being explicit. For example, what if even on a default contract you want to start tracking payment adherence, or maybe sales information and attributing them to sales' numbers.

Or maybe you start reporting and want reports on contracts vs default contracts.

And then things get messy. Because the real world gets messy.

Re: Applying “make invalid states unrepresentable”

#97
post #90

This line raised a huge red flag for me: "If the customer doesn’t have a fixed contract, it is assumed they are on a default contract" No. Don't assume, specify. Explicitly. If this is part of your specification, have a DefaultContract entity of some kind somewhere. And don't call this table just "Contracts", make it clear that those exist in addition to or overlay a default contract. It might sound like overkill, bu…

> If this is part of your specification, have a DefaultContract entity of some kind somewhere.

Yes, but not in the database table for contracts. That's how I read this part of the post. I would expect the assumption that if the customer doesn't have a fixed contract, they are on a default contract to be encoded in business logic somewhere in an application that uses this database.

Re: Applying “make invalid states unrepresentable”

#98
post #81
post #49

I like the concept but I’ve seen a fair few examples of where the developers and users clearly had differing opinions about which states are invalid! Dates are a rich vein of examples. Some users will happily consider “25th December” to be a date, without any year, because it might be the name of a folder in which they store their Christmas stuff. More seriously, genealogists or historians may want to record “25th De…

But then you're not dealing with dates at all, just categories which happen to have names that look like dates, no? Like you say, a "folder". But the photo file's metadata will either have a complete DateTime, or none at all, unless there is some sort of camera that is able to know what day of the year it is without knowing the year! Which due to things like leap years is impossible.

Importantly, these “date-like” things have important date-semantics. That is, it may be reasonable to expect your software to be able to handle varieties of precision or completeness of date metadata, in which case your date representation may need to be able to interact with DateTime fluidly without actually being one itself, despite it being tempting to remove these possibilities by making incomplete date information unrepresentable.

Re: Applying “make invalid states unrepresentable”

#99
post #90

This line raised a huge red flag for me: "If the customer doesn’t have a fixed contract, it is assumed they are on a default contract" No. Don't assume, specify. Explicitly. If this is part of your specification, have a DefaultContract entity of some kind somewhere. And don't call this table just "Contracts", make it clear that those exist in addition to or overlay a default contract. It might sound like overkill, bu…

> have a DefaultContract entity of some kind somewhere

This is the OO mindset described at the bottom - the odd compulsion to have a reified entity for every concept.

A lot of people have missed that the representation you persist doesn't have to match the representation you present. In this case, don't store default contracts, but present them e.g. via a database view.

Re: Applying “make invalid states unrepresentable”

#100
post #55

Earlier quoted context omitted.

Additionally, turning (startDate, endDate) into a set of dates will make the code more complex in some places. Before: SELECT event FROM events WHERE endDate After: Whatever additional complexity you add to your codebase to query end dates.

It's not that much more complex: if you do SELECT event FROM events WHERE startDate then all but one of the results (the one with the greatest `startDate`) will also have an implicit end-date prior to 2021.

This is fine for an open-ended query like the one given, because you still receive all the relevant data. But if you're looking at a range, for the same reason you have one extra at the end, you also have one missing at the beginning. And you can't just filter away missing data.
Post reply on HN