The commercial motivation was always the correctness guarantee, but the yak-shaving exercise of building the system offered the satisfaction that purely commercial concerns could not provide.
Now, in the dawn of the age of LLM coding, I find the agents are "unreasonably effective" at coding to declarative systems. The entire reference for the data format or DSL can fit in context, and LLMs are naturally more reliable against a constrained system. Compare to CSS, highly unconstrained, where I find code duplication, then conflict, then the inevitable `!important` flags begin to proliferate.
Yet, as anybody who enjoys the benefits of declarative systems will tell you, it can be lonely. The world prefers a general purpose imperative system. I believe the biggest reason is that the open-ended imperative system does not force us into a mapping exercise before we get to work. The code is like a whiteboard, where ideas are tried and modified in flight.
But I'd like to hear from others. Which do you prefer and why? In what situations?
[1] http://web.archive.org/web/20201014024057/https://www.youtub...
I was trying to figure out what you meant by "declarative" because CSS is declarative. (My understanding is: "declarative means you say (declare) what you want, but not how to get it." Usually SQL is the poster child of declarative languages.)
I think you're really talking about a mix of preferring data (vs actions/calculations) and DSLs (which aren't necessarily declarative)
Eric Normand has some thoughts you might appreciate:
- How a problem might take 1000 SLOC to solve directly, but only 10 SLOC with a DSL (plus up to 500 SLOC for the DSL itself; still fewer lines total) https://ericnormand.me/podcast/magical-leverage-languages
- Data vs calculations vs actions: https://ericnormand.me/podcast/what-is-an-action
---
I think data can be very powerful. For example, someone explained to me:
> I've been helping my non-tech father with Home Assistant. I've honestly been shocked with how far "community extensions" + "user configuration" can take you. Every time we hit a bug, I go "time to hit github" but without fail chatgpt and him are able to tweak a setting to get it working.
If you make your system configurable (config==data), you can skip the whole compile/build step!
It may be easier to describe "what I'm really talking about" by going more concrete. For a browser app, we have two declarative languages and one imperative. A tool like React with jsx allows me to think entirely in terms of code, folding the HTML into code, and tying off CSS to be dealt with on its own. It's a delightful simplification at first glance, that happens to leak like a sieve and forces people to become React programmers instead of browser programmers. I tend to think it is successful because it lets us think in terms of telling the computer to do things, and imposes no required mental model on how you craft your components. React says, "make it more imperative, use more code, think of your HTML in terms of code."
So I go the other way, where I add data binding attributes to HTML. A server request that modifies data always gets a response in terms of data that a small bit of framework code uses to update the DOM according to the data bindings. It is highly constrained in the same sense as SQL, there is only a small fixed set of allowed operations.
This is what I mean by declarative. My HTML data binding attributes say what should be displayed, no app code required. Naturally there are more details, but that should make the idea clear. The driving motivation is performance and developer ergonomics. Performance is amazing. Ergonomics, I can't say - it's easy for me, but I wrote it.
But solutions like these do not gain traction usually. I believe it is because people prefer the open-ended nature of React, which does not require a mapping exercise into the supported patterns before it can be used.
This is probably what I was trying to say about declarative vs imperative. React does not constrain my choices (not at first glance), and allows me to mix declarative HTML into my code. I can write any code I want, and like an LLM, I can fix anything with more code. Declarative solutions, like my own HTML data binding attributes, constrain the user to fixed supported patterns, which may not map to how the programmer thinks of the problem.
Declarative code has low cyclomatic complexity per unit of business logic. It also tends to have low state management demands (which the functional devotees will tell you is the root of all evil).
You can use a DSL or other abstraction so that you can declare what will happen in what circumstances, in a way that’s succinct and easily comprehensible. And all the repeatable loops and conditionals that make the declared thing happen in the appropriate circumstances are under the hood and needn’t be concern or be loaded into mental context by the person designing or updating the requirements.
It’s not the right solution to every problem, but when you can apply it effectively it’s a huge win.
However, agents and most SWEs are trained on imperative (wrapped in procedural/functional/OOP paradigms), and most will default to imperative because it’s familiar.
As I get deeper in my career I find myself gravitating toward a style that’s declarative where possible, falling back on functional, and then only when necessary imperative/procedural/OOP. It’s nice that many modern languages allow you to mix and match features of all those paradigms.
TL;DR: Mental load is the bane of programmers everywhere, and declarative programming minimizes mental load.