6 ms·
This is very good advice and a great article. It comes up on this site now and then because of it. For those who don't necessarily program in statically typed
by dgb23 2y ago
This is very good advice and a great article. It comes up on this site now and then because of it.
For those who don't necessarily program in statically typed functional languages:
The idea transcends paradigms.
You'll find very similar notions in 80's/90's OO literature, for example in Design by Contract. I'm sure one can dig deeper and find papers, discussions and specifications that go further back.
I think TypeScript is often written in such a way where you refine the types at runtime. I assume Design by Contract has influenced Clojure's spec (Clojure is a dynamic language).
Fundamentally this is about assumptions and guarantees (or requiring and providing). Once an assumption is checked and guarantees can be made, then other parts of the program don't need to check overlapping assumptions again.
In fact I think one of the most confusing things when you read code is seeing already guaranteed properties being checked again somewhere else. It makes code harder to reason about and improve.
- Sakos 2y agoI've been going through the comments on previous posts. I think one of the biggest issues with the article is the title. It seems to act as an anchor for a lot of people to the point where they'll argue against things that aren't in the article, just implied by the title (without context). So there'll be people arguing that she doesn't want to validate at all and just wants to parse, when really the article is about where you validate your data (and what you do with the result). It is not about getting rid of all validation.
- blowski 2y agoThis is true of all famous essays. People remove the nuance included in the body and over-apply the title without really understanding it. For example "Goto considered harmful". I remember working with a very good programmer who'd used a "goto", and a much less senior one[1] rejected their PR by linking to the article. [1] I'm ashamed to say it was me, a long time ago.
- ffsm8 2y agoThat's precisely why I love to only comment things with questions, i.e. "isn't go-to considered harmful? Is this really the best way?". It gives the person making the change the opportunity to give context for their decision - and either change or spell out their reasoning for it, potentially giving me an opportunity to learn from them. Another good benefit is that it doesn't "attack" the PR author in the "non-violent communication" way
- blowski 2y agoDoesn't that seem a bit passive aggressive? See what I did there?
- Smaug123 2y agoYou can totally do this with non-passive-aggressive phrasings ("Is this possible using structured programming instead of GOTO? What went wrong when you tried, how messy does it get?")
- ffsm8 2y agoSurely it depends on both your phrasing and how you usually interact with your colleagues, no?
- atoav 2y agoWhen you have a language with a strong type system, this is one of the practical things that ultimately gives you freedom as your program gets bigger and more complex. But you have to use it. E.g. by having a Class UncheckedEmail, a Class ValidEmail and a Class VerifiedEmail and ensuring that the conversion from one to the other has to involve your email-verification process. That way you never have to guess whether the email adress is unchecked, valid or verified and there is no need for "is_email_verified" booleans that you may or may not forget to update/check. If you use the wrong thing in the wrong place your type checker yells at you, while you can focus on actually important stuff.
- mrkeen 2y agoBetter yet, skip the Valid* classes and only make classes for valid objects. 'Int' is fine. We don't need ActualInt and IPromiseItsReallyAnInt.
- noelwelsh 2y agoI think you've really missed the point.
- bvrmn 2y agoI'm curious how would look like a real example with different Email classes. It seems silly. You don't often need a VerifiedEmail. But VerifiedUser is more useful from VerifiedEmail. You could get an implicitly verified email without introducing a new type.
- TeMPOraL 2y agoBut you don't want "implicitly verified", when there exist any code to which the difference between "verified" and "not verified" matters in some way. In your own example, if you happen to use e-mail verification as proxy for user verification, then the very code that creates VerifiedUser instances would want to have VerifiedEmail as input!
- paganel 2y ago> is seeing already guaranteed properties being checked again somewhere else Because at some point those "already guaranteed properties" might "disappear", to be more exact, the process/procedure that implements and runs them might not do its thing anymore for one reason or another. When that happens, because statistically speaking it will happen, then all the other processes/scripts/pieces of code depending on that "original" validating process would be in a very rough place.
- TeMPOraL 2y agoYes, and that's what the approach from the article is trying to help with. If you're coding in a statically typed language, the "already guaranteed properties" are propagated by types, so they can't just "disappear" - there's no way to get from e.g. String to Username without going through a String->Username function that does the checks, so functions accepting Username can rely on it having the relevant properties. Of course, this stops being true when you start hacking around the checks, side-stepping the parsers entirely (say, type-casting String to Username without any check). There's nothing a language can do to stop you when you really want to do this[0] - but then, you're an adult; if you see restrictions and safety interlocks, and put effort to hack around them, then any problem is really on you. This gets more difficult in dynamically typed languages, as you have to rely more on naming conventions and programmers not being idiots, but even without a typechecker, it will be rather obvious when you're doing something that could break the chain of guarantees. -- [0] - Some can try; I've seen a Haskell paper about this idea that does very complex type magic to try and truly ensure that only the parsing function can actually construct the result type. I tried reproducing that in C++ once, but C++ just can't give such guarantees.
- ChrisSD 2y ago> Some can try Rust does this with standard types even. "Parse, don't validate" is the answer to the question: why does Rust have so many string types? Of course you can hack around this using `unsafe` but, as you say, in that case you have to put visible effort into deliberately subverting the type system.
- 2y ago