Meditations on Tech Stacks


Technical stacks are one of the most controversial things in software development. This is because they relate directly to the capability of an individuals prowess and to their career. "Smart" stacks are considered to be beyond the grasp of the "Not very smart" software developers; and correspondingly, those in "smart" stacks have a tendency to look down on the "less smart" developers. I would like not to comment on the definition of "smart" here. That is too ill defined, but if you've been around, you know this perception exists.

It's my observation that the best software engineers - genuine old-school type hackers - easily transcend and switch stacks with relative ease. But anyway.

Right now I'm spinning up a new project - it will be a Web API interacting with a PostgreSQL backend. Nothing "fancy". This gives me a chance to look at the stack system with very concrete requirements.

Therefore, I can take a slightly different analysis today in the never-ending discussion. Consider the common stacks today for doing web work:

  • Microsoft C# (MVC)
  • Java (Spark/Spring//etc)
  • Go
  • Clojure
  • Python (Flask/Django)
  • Ruby (Sinatra/Rails)
  • Node

Of these, the first 3 are typed in "unwell-typed" languages; the second are practically untyped.

For my at home work, I have a simple requirement: code I write should never be adjusted unless the domain has changed. Library change shouldn't happen; language change shouldn't happen; corporate strictures shouldn't force me to rewrite my code. The time I have to do at-home work is extremely limited, and there no sign of that changing. Testing needs to be minimal - I don't have time to write large volumes of unit tests. Therefore, each line of debugged code is a jewel.

Don't break the jewels

The direct implication is that this requires a type system: less code to maintain between sitting down and production-quality function. I don't have time to study reams of code to understand what I was thinking the last time I touched this code months ago. Less time in debugging existing code.

Concise code wins

If code breaks, I can take up to two weeks to fix it - I am often busy on a given weekend. Can't afford to have upstream changes break it. Can't afford to have edge conditions that weren't covered in compile time come in and kick my butt.

Correct code wins

Note, this is probably applicable for a startup with a well-defined project. Can't say, I havn't worked in that area before.

Circling back to the list of 7 stacks above: the only stack that might fulfill the above conditions for stability is Java. However, Java is verbose; its type system is very poor; and its ability to walk into null pointers is ridiculous.

So I've put together a list of stacks that have better engineering.

  • Java 8
  • Haskell
  • Rust
  • Ocaml

All of these have web and SQL (postgres) libraries. All have a reasonable ability to be concise. Unfortunately, Java has (1) verbose code; (2) weak type system; (3) corporate sponsorship. Of these, the first worries me more: bugs and lines of code are a well established connection, and I don't need bugs. Correct Code Wins. More lines of code take more time to write. It's pushed to the bottom of the stack.

Haskell is a solid language with a great library base. Unfortunately, it often requires time to understand specifics: laziness at the language level is complicated in interactions, and monads are legendarily hairy. I don't have time to play puzzle games with type systems, something the Haskell community enjoys. I'll probably have to write my own (stupid and simple) code in order to do the job in a simple fashion. It's down the possibility stack; not off the table, but "ehhh". I'll rank it next to Java.

Rust is the new-comer in the language space. I've worked with it off and on for years. It does the job of being "better C++" quite well, and there's a growing community of web developers using it. Unfortunately for this purpose, it is a pointer-based language, and you wind up thinking about memory lifetimes. This is not relevant for the domain I'm at here: API->Logic->SQL. And, Rust tends to take time to untangle the memory graph. As a "right tool for the job", Rust loses the web war pretty badly. The libraries are evolving and probably will be amazing in time... say... two years. But sanity would suggest I would be updating the libraries regularly. The jewels will be broken. This is probably worse than Java for me!

OCaml is left standing. OCaml libraries are also immature, but it doesn't have the troubles of Rust at the language level - or that of Haskell or Java even.


Time to learn a new stack.