Live data from Hacker News

Applying “make invalid states unrepresentable”

kevinmahoney.co.uk

161–170 of 193 posts

Re: Applying “make invalid states unrepresentable”

#161

This is good article. But the second example seems to suffer from the defect of the first. Removing default contracts and representing fixed contracts as intervals leaves it possible that these fixed contracts can overlap....which is probably...undesirable? In that case, applying the remedy of the first example (a set of dates, and inferring that every 2nd (even zero length, to account for adjacent fixed) interval wi…

> In that case, applying the remedy of the first example (a set of dates, and inferring that every 2nd (even zero length, to account for adjacent fixed) interval will be default,) introduces another bug where if you lop off any random date in that set or list, you invert everything.

This is a good point, and something I usually describe recoverable problems versus non-recoverable problems. If I make start/end dates in the first example instead of just a set of start dates, then I can always create application-level or database-level constraints that don't allow either overlapping or incomplete segments. When business rules change, I can delete the constraints and update the business logic as necessary with no change to underlying data structures.

However, if I miss implementing a constraint and it erroneously allows overlapping or incomplete segments, I can easily run a query to identify all such invalid entries. Then I can then investigate and decide how to fix them.

However, if I go with the start-date-only set-based approach, and miss implementing a constraint, and it leads to a deleted date creating incomplete segments... I'm screwed. There will be no query you can do to identify incomplete segments to investigate or fix, because all segments are assumed to extend to the next start date. You can irreversibly lengthen one segment by deleting another, due to a forgotten constraint preventing you from making the change.

These could both be errors on the developer's part, depending on the requirements at the time, but one data design may lead to more non-recoverable issues than the other. Add in the flexibility of the former approach, and I'd probably be more likely to implement the former approach than the one proposed.

Re: Applying “make invalid states unrepresentable”

#162
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.

> 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.

Just a small note, as we're talking about assumptions, but this is clearly untrue. Consider - for decades, humans wore watches that knew the day of the month, but not the month - you were just expected to turn the day forward on the 1st day of months following non-31 day months. Similarly, we can imagine disposable cameras that ask the user for the current day on first use and simply assume leap years don't exist, and require the user to correct the date for any leap years. You might call this a silly design, but systems often have to interact with external systems that have silly designs. I believe I actually owned a toy PDA (a device for a child, not an adult) that did not have a year back in the 2003 or so.

Re: Applying “make invalid states unrepresentable”

#163

I'm not sure that this is what I think about, when I think of "Making Invalid States representable" (A concept that I practice). That said, it's an excellent, commonsense article that describes a highly usable approach to information architecture. I also agree that OOP programmers have always considered their designs to "represent the 'Real World'™." In my experience, I use OOP constructs to represent many things tha…

Um..."unrepresentable". :P

Re: Applying “make invalid states unrepresentable”

#164
post #156

A large fraction of the comments are about how if you do this and then someday your requirements change you might have to redo your underlying data structures or databases, with the implication being that you should therefore make those as general and flexible as possible. That reminds me of an interesting point I saw in a book whose title and author escape me. He said one of the reason you encounter so many bad desi…

There is a trick that I wish all senior staff knew but we find ourselves having to teach as a matter of routine.

1) Don't advertise what you're not selling

2) Don't sell everything that you've made

It's possible to write software that has a public contract that allows only a subset of states that the internal system allows. You can use this to support one customer that has a requirement that is mutually incompatible with another customer's, but you can also use it for migrations. One should be able to create an API where the legal values in the system are strictly limited, but the data structures and storage format may have affordances to support migration.

That doesn't necessarily solve the problem of communication between services and migrating these changes into a running system, but it's a useful tool. If you've ever had a coworker who insists on your service call diagrams looks like a tree or an acyclic graph, this problem is certainly one of many reasons they may be insisting on this. With a DAG there is an order in which I can deploy things that has a prayer (but not a guarantee) of letting all of the systems understand each other during each increment of deployment.

People have come up with alternative solutions for this problem by employing sophisticated sets of feature toggles, and in some ways this is superior, but it trades the number of steps (each of which has a potential for human error, and consumes calendar time) for increased reliability on average.

Re: Applying “make invalid states unrepresentable”

#165
post #158

Earlier quoted context omitted.

Also in genealogy: - estimated dates - calculated dates (e.g. someone was 30 in 1870, so he was born in "calculated 1840") - unreadable or unavailable months or days (typically recorded as 1980-00-13) - time ranges with all of the above as boundaries e.g. "after 1760-03-00 and before calculated 1800" - plainly incorrect dates, but that's what the document says (1865-02-30) - no dates (some software tries to enforce p…

All plausible and scary. It sounds like a recipe for a system where the different qualities of dates are their own entity, and anybody doing a date-search needs to provide some criteria on the degree of specificity or certainty they require. For that matter, someone might want to do a text-based search on dates: "This damaged photo shows 196_-_1, which could be at least 20 different months..."

There's also another dimension to that uncertainty. Dates are typically attributes of events involving one or more people in various roles, and these events are (hopefully) attached to one or more sources. The type of sources you use affects the confidence of various attributes of the event (like dates or participants).

In my area of research death records are typically a bad predictor for date and location of birth. When the records were managed by the churches (until after WWII pretty much), priests did not want to pester grieving family for the exact date of birth, so they relied on approximate age. Naturally the subject of the death record would not typically point out errors. On the other hand marriage records required looking at the actual birth records (sometimes mailed across the country), as these contained notes on all marriages of the individual (this was done to ensure monogamy).

Is it on the genealogist to consider this confidence when specifying the date of the event, or should the software intervene? Due to complexity, the former is the industry standard. But maybe there are some brave (or stupid) people who will try to take it into account in the future.

Re: Applying “make invalid states unrepresentable”

#166
post #53

Earlier quoted context omitted.

> Multiple times I've designed systems where I've reduced the representable states to the minimum, and when some requirements change I realize I have to re-design the full system. Yes, if requirements change, you change the design and code to support the new requirements. Compromising the consistency and maintainability of the current design to accommodate a hypothetical future requirement change is a bad trade-off I…

> since you can't predict the future That's one of those statements that makes sense, but is often not true. Very rarely does a client comes to me with a feature request that does require a pretty significant design change, but most of the time they're changes that were foreseen. Using this current article as an example, I love the way that they're storing the intervals to guarantee that they can't overlap. That's aw…

> What I would likely end up doing, though, is use that as the underlying representation but still return individual interval objects through the query API with a start and end date on each interval.

How the model you present to the user is represented in the database is an implementation detail.

Re: Applying “make invalid states unrepresentable”

#167
post #65

So Google's protocol buffers have this feature called "required" fields, which enforce schema in the type system. You should never use it. Never. It's one of those things that sound good until you're a few years into the project. Similar to how you should never be using meaningful IDs as primary keys for objects, always use meaningless fingerprint-like integers. Or how all integers should be signed unless you're dead…

I may be in the minority, but after happily using protobuf for years, I believe that there's nothing inherently wrong with required fields - instead, what's "wrong" is the protocol buffer API. Namely, when constructing a protobuf, theoretically, there might be two different ways: (A) first gather all the fields, and then construct the protobuf from these fields; (B) first construct an empty protobuf, and fill in the…

This isn't actually the issue with required fields (some languages, like java and (usually) python, use a construct-once style).

Imagine you have an innocent `required` field. You have a producer and a consumer of that field that communicate over the wire. (or instead of the wire, imagine a database).

You send or store an instance of that protobuf. Now let's say that you want to make the field optional (or remove it). With an already-optional field, this is easy. You stop setting it, and maybe eventually you clean it up.

With a required field, however, you can't do that. If any of your clients don't have the newest schema version, you can't unset the field (so imagine that you support mobile clients who may never update). Or if there's middleware you don't know about that introspects your proto. Even if you do the dance right and update your server and client before not setting the new field, you could crash outdated middleware that you didn't know about. Whoops!

Or with the database, you now need to dual write or something complex because if you need to roll-back to an older version, you'd be unable to read the protos that don't include the required field.

Required doesn't do well over time. It has nothing to do with setting the values.

Re: Applying “make invalid states unrepresentable”

#168

Earlier quoted context omitted.

https://capnproto.org/faq.html#how-do-i-make-a-field-require... Required now means requires forever because people can't migrate safely. But technically you can change a protocol descriptor from required to optional, which is invalid (usually, in a distributed non-transactional system (the common kin) but nothing stops you from doing it. So why not make required forever? Well, do you really want to commit to anything…

Protocol buffers already require you to commit to some things forever, like the type of a field, or whether two fields belong in a oneof together. I’m not saying that “required” was a great feature, but it’s not exactly unique.

No they don't. An optional field can be deprecated and replaced with a different field. This can be done to change the type (also some types can be changed, although you probably shouldn't).

Required usually cannot be deprecated.

Re: Applying “make invalid states unrepresentable”

#169

Earlier quoted context omitted.

I may be in the minority, but after happily using protobuf for years, I believe that there's nothing inherently wrong with required fields - instead, what's "wrong" is the protocol buffer API. Namely, when constructing a protobuf, theoretically, there might be two different ways: (A) first gather all the fields, and then construct the protobuf from these fields; (B) first construct an empty protobuf, and fill in the…

This isn't actually the issue with required fields (some languages, like java and (usually) python, use a construct-once style). Imagine you have an innocent `required` field. You have a producer and a consumer of that field that communicate over the wire. (or instead of the wire, imagine a database). You send or store an instance of that protobuf. Now let's say that you want to make the field optional (or remove it)…

[deleted]

Re: Applying “make invalid states unrepresentable”

#170
post #158

Earlier quoted context omitted.

All plausible and scary. It sounds like a recipe for a system where the different qualities of dates are their own entity, and anybody doing a date-search needs to provide some criteria on the degree of specificity or certainty they require. For that matter, someone might want to do a text-based search on dates: "This damaged photo shows 196_-_1, which could be at least 20 different months..."

There's also another dimension to that uncertainty. Dates are typically attributes of events involving one or more people in various roles, and these events are (hopefully) attached to one or more sources. The type of sources you use affects the confidence of various attributes of the event (like dates or participants). In my area of research death records are typically a bad predictor for date and location of birth.…

I implemented a [private] genealogical data entry system based on the GenTech data model, which has a "surety scheme" entity, designed to capture perceived uncertainty. I also added a "Fuzzy Date", where every date-like value was decomposed into all its constituent components (year, month, day, hour, ...), all optional. It could also capture a range of such fuzzy dates, so it was possible to enter a "date" such as "The first of a month no earlier than 1950 and before June 1990". There was a loooong list of validation constraints to attempt to prevent contradictions being entered, and I think I caught all the cases, but...
Post reply on HN