Join the discussion
Write your take first — we'll ask for email only when you're ready to publish.
- Hacker News
- The word simple is used here a way I'm having trouble wrapping my head around.
This specific usage appears to come from this linked talk, Simple Made Easy:
https://www.youtube.com/watch?v=SxdOUGdseq4
My reaction to the Unix pipeline was that, the reason it exploded in complexity is because the pieces were too simple. They were insufficiently expressive.
But the word is used in a different way here, and I'll have to watch the talk to understand what exactly is meant. (Something like orthogonality?)
by andai - Using "length of the correctness statement + length of its proof" works quite well as proxy for complexity of a component (the longer, the more complex).
Copy pasted functions with subtle changes mean you cannot reuse the proof (DRY). Giant functions with lots of if/else statements however might cause a branch explosion in the proof. The right abstraction removes lots of assumptions that a proof could depend on, limiting the search space and often forcing elegance (this also applies to math, eg. when reasoning with abstract groups instead of integers). The wrong abstraction might force case distinctions on consumers of the abstraction.
by Gehinnn - Important to note as well, is that "simple" isn't "lesser" or "dumber", it can be "more" and "wider", yet still "simpler".
Expectedly, Rich Hickey explains it best, watch the "Simple Made Easy" talk if you haven't before, one of the few talks I probably watch bi-yearly: https://www.youtube.com/watch?v=SxdOUGdseq4
Few things, concepts and ideas have changed as much of my programming mind as Hickey's talk and ultimately Clojure have done over the years.
Wish we had new amazing Hickey talks to link to, maybe it seems he's about the hang up the hammock perhaps?
- > Unix pipelines are not simple
But they are.
UNIX Pipes do not mandate having to use tons of different programs with stupid commandline options. I simulate them in ruby itself; method chaining works in a very similar way, but I built a pseudo pipe around it. The idea was more to have an object oriented shell, e. g. combine good ideas from UNIX pipes and the MS powershell.
They are simple if you design them well and have them be flexible too. The reason UNIX pipes were awkward is because they delegated onto many different programs such as awk or sed with their own strange rules. Nowhere does it say you HAVE to use such awkward tools. Use better tools and the idea of piping becomes simple, similar to (a more flexible variant of) method chaining. Just without being tied down to a specific object per se (I do use the pipe-handler master object to handle the pipe instructions; each pipe instruct I call cmdlet, e. g. shorter for commandlet, as this is how I like to think about this in terms. This also combines e. g. virtualdub + avisynth ideas. I loved them when I used windows. The idea behind avisynth is great - not necessarily all of the syntax, but the idea that all multimedia audio can be operated on at all times in flexible ways.)
by shevy-java - > The reason for this is that in Rust, a struct couples type-checking to a fixed data representation. You can't get one without the other.
> Clojure decouples data representations from type checking.
This is funny to me because seen from the other side, (this) Clojure couples runtime type information to data structures: you're no longer allowed to define a data structure that doesn't have some runtime type information attached. A fixed static structure is just the consequence of not adding dynamic type information.
Meanwhile in Rust you can get type-checking ‘without’ a fixed structure by using trait objects.
by Twey - Great piece, very straightforward examples, although I did have to squint for quite a while to grok the Closure portion.
I am currently building a piece of very modular software and it has been the hardest-to-design project of my entire career. I would never be allotted this amount of time-effort at any job I have held to make something this robust and clearly defined. Many aspects of this project have taken 3-5 rounds trying-and-trashing to get an abstraction that is uncomplicated.
This is precisely why vibe coding is so successful for building tiny isolated scripts, and so disastrous for anything else. It's just really dang hard to build something large and simple.
by hankbond - > There's no native Unix equivalent to frequencies, this sort | uniq -c is the closest we can get. Not only is it less performant (it has to collect the full input into memory before continuing), but it ties aggregation to ordering.
One of the core features of the Unix command-line is that it is user-extensible. If there's no "native" command equivalent to frequencies, you can write your own, and it will be given the same first-class treatment as any other binary in your PATH. This is entirely in keeping with the Unix philosophy of simple implementations.
by Snarwin - Strong resonance with the famous essay "The Rise of Worse is Better" [1], which contrasted the (better) "MIT/Stanford style of design" with the (worse) "New Jersey approach".
MIT/Stanford:
> Simplicity -- the design must be simple, both in implementation and interface. It is more important for the interface to be simple than the implementation.
New Jersey:
> Simplicity -- the design must be simple, both in implementation and interface. It is more important for the implementation to be simple than the interface. Simplicity is the most important consideration in a design.
TFA maps "simplicity" to "MIT/Stanford simplicity" (simplicity for the user) and "smallness" to "New Jersey simplicity" (simplicity for the developer).
I wonder if the root of the tension between the two schools comes down to the ambiguity of the user/developer distinction. Developers are also users. Simplicity of implementation is helpful to developers when they are working directly on implementation, while simplicity of interface is helpful to developers when they are using other developers' work.
by getnormality