Ted Kaminski
tedinski.com · Personal blog · on HN since 2018
Ted Kaminski writes essays on software design, abstraction, type systems and language design, including the expression problem and function coloring.
What HN saysHN commenters cite it for the expression problem and the wizard-versus-engineer divide, and one links its critique of SOLID principles.
52HN people shared it
11linked it in comments
50stories submitted
980story points
6 months agolast shared
2018people per year2026
Most-shared posts
- 1Programmer as wizard, programmer as engineer (2018)4 people · 168 points · first shared 2018 · 74 comments on HN
- 2Data, objects, and how we're railroaded into poor design (2018)4 people · 102 points · first shared 2018 · 52 comments on HN
- 3Design duality and the expression problem (2018)4 people · 18 points · first shared 2018 · 8 comments on HN
- 4'Function Coloring'4 people · 7 points · first shared 2023 · discussion on HN
- 5How humans write programs3 people · 6 points · first shared 2018 · discussion on HN
- 6What would an object-oriented language without inheritance look like?3 people · 3 points · first shared 2018 · discussion on HN
- 7The one ring problem: abstraction and power (2018)3 people · 2 points · first shared 2021 · discussion on HN
- 8How did we end up with containers?2 people · 136 points · first shared 2018 · 74 comments on HN
- 9Backpressure (2019)2 people · 73 points · first shared 2021 · 17 comments on HN
- 10Fuzzing vs. Property Testing2 people · 64 points · first shared 2019 · 7 comments on HN
- 11Deconstructing the “Unix philosophy”2 people · 6 points · first shared 2018 · 1 comments on HN
- 12The end-to-end principle in distributed systems2 people · 5 points · first shared 2024 · discussion on HN
- 13Notes on the expression problem and type design (2018)2 people · 3 points · first shared 2024 · discussion on HN
- 14Testing at the Boundaries (2019)2 people · 2 points · first shared 2019 · discussion on HN
- 15What can we learn from how compilers are designed?1 people · 225 points · first shared 2018 · 84 comments on HN
What HN people wrote when they linked it
zogrodea · 2024-07-24
I had the same opinion with async/await, that it's nice to know a function performs IO and will wait before continuing. Makes it clearer when to use Promise.all to make multiple requests in parallel and wait for all of them to finish before continuing (faster than making calls sequentially).
I kind of wish the languages I use had Haskell's IO monad too, to separate functions in terms of the type system, but that's slightly different.
You might like this article (which is my personal favourite about function colouring). https://www.tedinski.com/2018/11/13/function-coloring.html
oxff · 2022-05-14
Writing a toy compiler, the entire pipeline end-to-end, for a language no matter how small. I can't think of another exercise that covers so many good issues to solve, and good practices for solving them.
The two I like to recommend are:
- PLAI: https://cs.brown.edu/courses/cs173/2012/book/
- Essentials of Compilation: https://wphomes.soic.indiana.edu/jsiek/
For general software design, this blog is quite golden: https://www.tedinski.com/archive/
chriswarbo · 2019-01-30
> It is quite well studied and solved in various languages
I wouldn't say the expression problem is "solved"; various languages pick different tradeoffs, but the underlying problem is still there.
The best description I've seen of this is at https://www.tedinski.com/2018/02/27/the-expression-problem.html
miki123211 · 2019-10-20
This is yet another example of the divide between wizarding and engineering[1]. When you're a small startup, what matters is the expressiveness of your language, and the ability do do a lot of things very very quickly. Type safety, performance, readability, those things don't matter. You're just a bunch of engineers who know the whole codebase inside out, you're pretty certain of what you're doing. In short, you're wizarding. If you grow big enough, this approach slows you down greatly, and you need to switch to engineering. You sacrifice some speed for making the codebase more understandable to a larger group of people, you can no longer assume everyone knows all the code, you write unit tests, need types and dislike metaprogramming because of the confusion it creates. This is why languages like Python, Ruby, Lisp or Smalltalk are amazing for small startups, but Java is what enterprises use. They're different ends of the wizarding/engineering spectrum. I wish there was a language that let you move gradually from one end to the other, exactly when you need to.
[1] https://www.tedinski.com/2018/03/20/wizarding-vs-engineering.html
dzjkb · 2026-04-21
here's a nice critique of SOLID principles:
https://www.tedinski.com/2019/04/02/solid-critique.html
gf000 · 2025-05-03
You need just the right amount of expressivity in a language, so that it is hard to abuse, but still allows writing easy to use libraries.
Java has went over this evolution, implemented generics, lambdas, etc and I believe it strikes a very good balance in not being overly complex (just look at the spec - it's still a very small language, compared to its age, unlike C++ or C#).
Go tried to re-invent this evolution, without having learnt Java's lessons. They will add more and more features until their "simple" will stop applying (though I personally believe that their simple was always just simplistic), simply because you need some expressivity for better libraries, which will later on actually simplify user code.
Also relevant: https://www.tedinski.com/2018/01/30/the-one-ring-problem-abstraction-a…
ncruces · 2024-07-04
With the advent of coverage based fuzzing, and how well supported it is in Go, what am I missing from not using one of the property based testing libraries?
https://www.tedinski.com/2018/12/11/fuzzing-and-property-testing.html
Like, with the below fuzz test, and the corresponding invariant checks, isn't this all but equivalent to property tests?
https://github.com/ncruces/aa/blob/505cbbf94973042cc7af4d6be6266454bb2…
https://github.com/ncruces/aa/blob/505cbbf94973042cc7af4d6be6266454bb2…
svieira · 2023-06-05
See also: https://www.tedinski.com/2018/11/06/concurrency-models.html which is the first article I've ever seen that says that `m:n`-style-green-threads are bad and good at the same time.
TL;DR - he says that "doParallel" and "doConcurrently" are separate operations with distinct semantics that designers of programs must care about and that conflating the two (especially the common "doConcurrently-and-often-but-not-always-in-parallel") is one of the most common causes of bugs in programs that need to make progress in multiple threads of execution.
ktpsns · 2023-01-16
I guess there is no easy answer for that. Here is an interesting blog post which resembles closely my opinion: https://www.tedinski.com/2018/11/13/function-coloring.html
Edit: And of course there are alternatives such as Go or Zig: https://kristoff.it/blog/zig-colorblind-async-await/
matfil · 2019-02-01
The big one for me: how strongly do you equate "programming" with "engineering", and to what extent do you value other approaches (in the spirit of [1])?
To what extent are ways of working circumscribed by tooling choices?
"What are you selling?" (and is it something I can believe in) is pretty important too.
[1] https://www.tedinski.com/2018/03/20/wizarding-vs-engineering.html
remexre · 2020-06-05
Sure, I mean more like there'd be some interface ByteStream, and probably another interface TerminalInput extends ByteStream; TerminalInput would then contain the especially terminal-related signals (e.g. sigwinch). If a program doesn't declare that it wants a full TerminalInput for stdin, the sigwinches would be dropped. If it declares it wants one but the environment can't provide one (e.g. stdin is closed, stdin is a file, etc.) it would be an error from execve().
Other signals would be provided by other resources, ofc; e.g. sigint should probably be present in all programs.
---
In general, my ideal OS would have look something like [0], but with isolation between the objects (since they're now processes), provisions for state changes (so probably interfaces would look more like session types), and with a type system that supports algebraic data types.
[0]: https://www.tedinski.com/2018/02/20/an-oo-language-without-inheritance…