UP | HOME

How to deal with low effort crap.

Have you ever seen 100500 crappy dependencies (well, nothing could ever beat the degeneracy of Java) a Python or Rust project, leave alone that node_modules crap? This is because we are in the era of low-effort crappy junk-food of software.

Yes, junk-food and low-effort fast-food is the exactly right metaphor. Quickly make some crap we can sell is the current mantra of software project management. No time to do everything right, even no time to understand the problem in details.

So, what can we do? Well, we have to understand everything in all the details and then act according to just right principles. The principles has been formulated and validated by the programmers of the Golden Age (which culminated with Haskell98).

Let’s suppose that (god forbid!) lists are not built in and syntactically sugared in our language but provided to us by some npm module (which literally can be broken at any moment) or some narcissistic low-effort crate.

We have to assume that everything can be broken by idiots at any moment, just like there could be a network error at any moment. So we have to expect shit to happen.

The strategy is, just like with airplanes, is to perform a self-test, but not just component tests, but specification-validation tests.

The right principles will guide us.

For a list we have to state all the invariants and algebraic laws which this (or any other) abstraction provide or guarantee. We have to state these invariants and algebraic laws formally and validate them every time something has been changed in dependencies.

Since we do not have a specification language we can use a pure-functional language and assertions, which is an operationally defined equivalent of executable specifications (given that pure-functional languages are just pure logic).

What are those laws would be? Well, this is why you have to know and understand every abstraction you use. For a List that would be, for example, that appending an empty list will not change anything (that it is the right identity) or that consing an element to an empty list is the same as lifting.

Eventually you have to specify every known law - Monoidal and Monadic.

The important thing is that the laws and invariants has to be stated explicitly, which means that they has to be understood. Just QuickCheck generators alone won’t do (but they must be used too).

So, instead of vendoring and managing dependencies by hand, as Google does in all its projects (and for really good reasons) we can use executable specifications for every ADT or interface we use, and boy these better be pure-functional and immutable.

Notice that Google uses crappy imperative languages, and we don’t have to. We will use pure logic (which is what Haskell technically is).

Vendoring leads to unnecessary, redundant idiocies like Nix (no, a file is just right granularity and a proper abstraction and a compiler and a linker are pure functions. Do not fix what isn’t broken!), which is a cancer. Stable interfaces and FP is the principle-guided solution, not some additional tooling.

Formally define and verify your abstractions and corresponding algebras and interfaces. And you better to have these algebras.

This corresponds to knowing and verifying every ingredient in your junk food, or even better - to have it troughly lab-tested before you eat (of you have to consume other people’s low-effort crap).

It is much better, however, to be a chief.

Author: <schiptsov@gmail.com>

Email: lngnmn2@yahoo.com

Created: 2023-08-08 Tue 18:40

Emacs 29.1.50 (Org mode 9.7-pre)