Live data from Hacker News

Applying “make invalid states unrepresentable”

kevinmahoney.co.uk

121–130 of 193 posts

Re: Applying “make invalid states unrepresentable”

#122
post #27

While this is great if you know exactly what you want to achieve, it does “lock you in” those constraints on a more fundamental level. More times than I can count I’ve seen business requirements change to require those “unrepresentable” states, and since you’ve now designed you whole data model around it you need to add awful hacks to make it work. The timeline example is actually very telling. A lot of times you’d a…

You could always split your types into frontend and backend types where the backend ones are more open and the frontend ones are more restricted. I don't necessarily mean FE/BE as on the web. A lot of code is only interested in shuffling around data anyway, the shape is fairly uninteresting.

Kind of like internal data/algorithms and external interface in OOP?

Re: Applying “make invalid states unrepresentable”

#123
post #53
post #26

In general I agree that it's nice to make invalid states unrepresentable, but I'm not sure if I agree that this counts as a fundamental "invalid state". There is nothing about contracts which require that you can only have one active at the same time, or that that current one must be open ended. From a practical point of view it might be advantageous if you maintain only a single contract with a customer at all times…

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

I like to call this, "speculative complexity". I've seen many cases where speculative complexity was added, and persisted for a long time, for reasons that fundamentally mispredicted the way the system would evolve and actually inhibited that evolution.

Re: Applying “make invalid states unrepresentable”

#124
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…

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

The article addresses that concept:

> It is sometimes still useful to represent the periods as a sequence of start and end dates. It is trivial to project the set of dates in to this form. As long as the canonical representation is the set, the constraints will still hold.

Re: Applying “make invalid states unrepresentable”

#125
post #86

Earlier quoted context omitted.

Sum types are one of the main things I miss when working in Python. Is anyone aware of any good ways of adding sum types to Python?

I'm not sure you would consider this a good way, but one can implement (unchecked) sum and product types in any language with lexical closures via Scott encoding[1]: # data Pair a b = Pair a b def pair(x, y): return lambda f: f(x, y) # data Either a b = Left a | Right b def left(x): return lambda l, r: l(x) def right(y): return lambda l, r: r(y) v0 = pair(2, 3) v1 = left(7) v2 = right(9) # case v0 of { Pair x y -> x…

Wow, this looks clever. (maybe a bit too clever)

I'll need to read more about it, thanks for the pointer!

Re: Applying “make invalid states unrepresentable”

#126
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…

This might make sense for a transport schema because you can receive messages from the past or the future but it does not translate to internal program state or database schemas where this is not the case.

Making invalid states unrepresentable is basically the process of taking human-checked invariants and turning them into type-checked invariants. This reduces the likelihood of bugs and guides humans to use the system correctly.

Re: Applying “make invalid states unrepresentable”

#127
post #27

While this is great if you know exactly what you want to achieve, it does “lock you in” those constraints on a more fundamental level. More times than I can count I’ve seen business requirements change to require those “unrepresentable” states, and since you’ve now designed you whole data model around it you need to add awful hacks to make it work. The timeline example is actually very telling. A lot of times you’d a…

Even "hard guarantees" are worthless. All it takes is one client with a checkbook to change business requirements.

Re: Applying “make invalid states unrepresentable”

#128
post #37

Not certain I get the needless attack on OOP in this text. The error could just as well have happened in any alternative to OO. What is needed is the realization that there is that there is a schedule that needs to have full control over the times to not create coordination issues. That is a realization that is utterly independent of the OOP-ness of the eventual solution.

It's as if OOP code negates putting thought in designing a solution, absolute nonsequitur for me.

Re: Applying “make invalid states unrepresentable”

#129
post #120
post #52

Earlier quoted context omitted.

The YAGNI (you aint gonna need it) principle overrides the DRY principle imo.

This is partly why I've found it helpful to wait until there are at least 3 identical (not nearly identical) implementations of something before trying to make a more generic/abstracted version of it.

I think these rules of thumb are... okay. But I think it's more helpful to go back to how DRY was initially defined ("Every piece of knowledge must have a single, unambiguous, authoritative representation within a system") and ask whether what I'm dealing with is actually "a piece of knowledge." There can be 10 identical copies, and if they just happen to be identical but they represent different things that might change independently, they should probably remain 10 identical, independent copies. Alternatively, if there are exactly two places something occurs in the code, but if they're out of sync the result is a broken system, you should think about unifying.

DRY is too often treated as purely (or principally) syntactic, when that's actually much less useful.

Re: Applying “make invalid states unrepresentable”

#130
post #113

Earlier quoted context omitted.

I agree that this is an issue, but I think the answer is simply using a very flexible basic data representation (which admits invalid state) and then using predicates to refine it. e.g. starting with a list of (start,end) intervals and then adding predicates for valid intervals (start If any of the requirements change, it's easy to either add more predicates or relax/even outright remove them.

If you play your cards right, you can even get your type system to alert you to every place in your code that needs to change when you change the constraints. 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 'Cu…

[deleted]
Post reply on HN