The Primacy of Developer Experience: Why Tooling Trumps Language Elegance
Description
A screenshot of a tweet from Dmitrii Kovanikov that presents an argument for why Functional Programming (FP) is not more popular. The core thesis, stated at the top, is 'Tooling > Language.' The tweet then lists several popular languages and the key aspect of their developer experience (DX) that makes them effective: Java has powerful debuggers, Rust provides helpful error messages, Go simplifies dependency management, and JavaScript has a low barrier to entry. The entry for C++ is conspicuously left blank, a subtle joke implying its notoriously poor developer experience. The tweet concludes that for most developers, practical DX is far more important than the aesthetic qualities of a language, such as elegant syntax or a powerful type system
Comments
79Comment deleted
The author tried to list the great tooling for C++, but the list itself resulted in a 3-page template metaprogramming error
“In C++…” - the tweet cuts off because the build’s still linking so someone can finally attach gdb. By the time it finishes, Go has self-formatted, Rust has apologized in verse, and JS is already in prod behind a feature flag. DX: 1, language elegance: segfault
After 20 years in the industry, I've learned that the most elegant monad in the world can't compete with 'right-click → Go to Definition' that actually works. We don't choose languages for their mathematical purity; we choose them because we can debug production at 3 AM without needing a PhD in category theory
The brutal truth about FP adoption: turns out developers would rather have IntelliJ autocomplete their way through a 10,000-line Java monolith at 3 AM than spend an afternoon proving their monad transformers are lawful. We didn't choose the imperative life because it's elegant - we chose it because when production breaks, 'just add a print statement' beats 'let me explain how the Reader monad would have prevented this' every single time
Java has F5, Rust has therapist‑grade errors, Go has git clone, JS has a tab; FP has a PDF
FP’s missing abstraction isn’t a new monad - it’s an IDE button that debugs, a compiler that teaches, and a package manager that survives corporate proxies; C++ is blank because the template error is still instantiating
FP: elegant types, eternal setup. Java: verbose boilerplate, instant debugger salvation
skill issues yet again Comment deleted
FP isn't popular because all FP cool features already implemented in most languages, but without FP limitations Comment deleted
what is FP? Comment deleted
Functional programming Comment deleted
I thought its Free Pascal.... Comment deleted
functional programming, Haskell, Clojure, etc Comment deleted
tco is almost never implemented in interpreted languages (yes, the two most popular ones), thus making recursion unviable, and currying in any c-like languages sucks FP is not about language features, it is about limitations and approach to programming. the limitations allow the language to be as abstract as you need while the compiler does heavy lifting with optimizations and makes your code run decently fast. the approach makes debugging almost redundant, and the remaining few bugs can easily be caught with repl Comment deleted
Tco compiles into loop, you don't need tco if you already have loop in language. Comment deleted
you can extend that logic further and get "you don't need loops if you already have goto", but that's not the way to have healthy discussions. tco is a great way to completely drop loops and is the minimum requirement that "a functional programming language" must have to be taken seriously. you can still use them (hell, ocaml lets you write pascal is you choose so), this is tangential to the functional programming if you're really interested, take some of your free time and try to dive deep into a primarily functional language. you might not like it at the end, but you'll gain a lot more understanding of how and when to use said "cool FP features" in most languages Comment deleted
What limitations? Comment deleted
they think that always having 1 argument and 1 return value and immutability is a limitation. while it's actually what makes the code reliable. Comment deleted
If only we have another way of write reliable code. Oh wait, we have Comment deleted
we have dozens. but each one of them IS a limitation to something. limitations create rules that you can rely on. you can write the C code with goto, but structural approach of repeating a defined scope while some condition is true, makes it easier to comprehend. then we face the problem of provability of computability — and replace the while loop with a for loop, because this one has a defined end. and so on. each of them is a limitation compared to goto Comment deleted
And at some point adding more limitations does more harm than profit. Btw all mutability problems is solvable without dropping mutability. Comment deleted
because you said so. and how exactly you are going to avoid mutability problems without limitations? Comment deleted
not without limitations, but with much less strict limitations. Comment deleted
then you will be solving another problems. Comment deleted
MVS? Comment deleted
And in the end most of the codes are complied to goto ☺️ Comment deleted
Its jmp, not goto😉 Comment deleted
What is the difference? Comment deleted
Goto doesn't exist in x86+ architectures Comment deleted
that's not really true FP has its share of problems, but saying it's integrated into most languages is very far from truth Comment deleted
IMO the main thing that wasn't integrated anywhere is lazy evaluation. Almost all modern FP languages have it, few others do. And that's like the core of modern FP Comment deleted
afaik even eg. some with dependent types aren't lazy Comment deleted
"In C++" Comment deleted
where is the text Comment deleted
Well. There isn't any, it's C++, aside from the compiler and the debugger, do you know any other tool? xD Comment deleted
there is debugger? Comment deleted
Cmake Comment deleted
🤮 Comment deleted
In c++ there is no standart way to do something, there always more than one options, different compilers/debuggers/package managers/build systems, so you sometimes spend hours to do things that most language ecosystem do in seconds Comment deleted
With great power comes great responsibility. And great ability to fuck up. Comment deleted
Even language itself offers 3 turing complete things c++ itself/define/template magic Comment deleted
I know right? I don't even know how to use it Comment deleted
debugging in real world: std::cout << 'anything' << std:endl; Comment deleted
Debugging in real world: My python code has nearly zero comments but logging.debug(...) statements everywhere. Just bump the loglevel in prod when you have an issue. Comment deleted
Anyway, when writing performance critical code you don't really care about how beautiful is your code what principles you use. When you have 100k cores 1% optimization can free 1k of them Comment deleted
Actually, you *do* care about how readable it is, because typical ugly performance-optimized code oh so often relies on undocumented assumptions that inevitably break the next time someone touches it Comment deleted
Been there, done that. Won't touch an optimized C++ codebase from someone who puts performance above readability with a ten foot pole Comment deleted
I mean, sometimes you have to resort to goto, which is not as "readable" as loops or conditionals, sometimes viewed as taboo, but when it works then it has to be used. C strings over str, etc. Comment deleted
Code with goto and C strings can be beautiful, I'm not arguing against that. I'm arguing against a 200 line function that uses every algorithm in existence just because it's fast Comment deleted
By all means, optimize your code as much as you want, but keep it readable and documented. The problem with codebases like GMP is they rely on barely documented assumptions for validity of optimized code Comment deleted
If that's not an option, at least keep the optimized code totally isolated and independent from the rest of the codebase, so that its correctness can be verified without cross-checking with other interfaces and implementation details Comment deleted
That where the problem lies. While trying to write optimal code, thinking about its readability is an extra burden, I can understand when people just don't do that. That's basically the very reason why people write thesis essays or forums exist Comment deleted
Unreadable optimal code deserves to be thrown away. By all means, experiment with it, make conclusions, but rewrite it before it hits prod Comment deleted
I've built a few projects based on the "optimal is better than readable" mantra. They're now barely maintainable. It's not really a bad ending, as they had limited scope and solved their problems, so there wasn't much need to touch them after finishing the project. But that's a rare case Comment deleted
these cases are as rare as cases when you have to use c++. Industry revolves around high level languages after all Comment deleted
Not when you need performance Comment deleted
bulk of the industry does not really need high performance. perf is really important in some nieches like embedded software or hft Comment deleted
bulk of the industry writes php btw Comment deleted
true, and its more than enough to move json payloads between the client and dbs, which is like 80% of the it Comment deleted
yep, json shuffling is the definition of a job for a web janitor Comment deleted
elitist rust developer “i use arch by the way” detected Comment deleted
you have probably meant "elixir dev on a nixos" But what I'm saying is true, isn't it? I don't imply any bad connotations, someone has to shuffle json Comment deleted
actually even that can become infinitely complex Comment deleted
observable real world is only finitely complex, why should json shuffling be infinitely complex? Comment deleted
ok. to put it more precisely it is always countable complex — but there can always be a more complex task. if you talk to some api and receive more data fields than expected, is it still correct data? you can receive the same fields but located elsewhere besides the branch you expected. metadata can affect complexity at any point. consistency between inner type representation and flattened JSON type system is also another pain point. yeah there are solutions to those problems, but usually if you have complete ownership over the whole communication. Comment deleted
oh, I just will ask my oracle machine about it Comment deleted
seriously though, ownership over whole communication is not realistic, and so is total determinism. I think there could be some formalizations of temporal logic via lenses for emitters and receivers as an effect system implementation, but really, do we even need this in php :^) Comment deleted
kinda yes. have you seen jsons from YouTube API? highly nested with lots of data duplication and its not even very stable, they change it whenever they like without properly describing what has changed. Comment deleted
thats a feature Comment deleted
Not what I argued against. I meant to say that "unmaintainable optimal code" is a niche within a niche Comment deleted
perhaps I do, but it is not up to me alone Comment deleted
any safe goto can be written as tail function call Comment deleted
"safe"? Comment deleted
that don't corrupt the stack Comment deleted
there is a forth dialect called factor, and it has stack effects Look at those monads: https://github.com/littledan/Factor/blob/master/extra/monads/monads.factor Comment deleted
how does github know how to highlight codes of this custom language ? Comment deleted
Github uses this lib for lang detection: https://github.com/github-linguist/linguist And judging by the Factor repo, this lang is not detected, so the highlighting is probably for the C++ or elisp instead Comment deleted
it is not a good definition for a safe goto, thats all I'm saying Comment deleted
i recently wrote program on clojure and want to say that, afaik, tooling is pretty nice. and it is written on java with good backward compatability so you can use all java things. but also it has built-in stuff like test framework which is not allways the case for older languages. so, problem is not that fp is bad, but that fp languages have older ecosystem and harder to learn. (btw, i still cannot understand why macroses in lisp are so special. looks like this is because syntax for language is so poor that macroses can look like native functions or something) Comment deleted