I remember not too long ago (I think this was about the time that React first came out) I was trying to understand what people meant when they said that it was “declarative” vs. “imperative”. Looking up the terms at the time didn’t enlighten me much. Mostly articles seemed to focus on the difference between Object-Oriented or Procedural languages and Functional languages. Since I was looking for an explanation within one (Procedural) programming language, that answer was not helpful.
Since then I’ve become a proponent of many functional programming concepts which, I think, have made my code easier to read and understand. If I had to summarize my progress, I would probably say that I’ve learned to to program more declaratively. So even if my definition is slightly different, here’s what Declarative programming means to me.
If I were to ask a chef to make me some soup, I might ask:
Could you make me some roasted butternut squash soup, please?
The chef would likely have little trouble cutting, peeling, roasting, blending, and spicing that dish. On the other hand, if I asked the same question to a past version of myself when I was in university, I would have had absolutely no idea what to do. Why? Because I’d never roasted a squash before.
On the other hand, what if I prepared a full recipe?
Could you make me some roasted butternut squash soup as described in these 10 steps?
The chef would probably look at the recipe and be able to follow it with just a glance. My teenaged self would have to examine each and every line, but he’d probably also be able to make the soup without burning anything.
The difference is that the first question is Imperative; it implies a whole subset of knowledge about cooking that not everyone will have. The second question is Declarative; it makes far fewer assumptions about the knowledge of the person on the other end and thus is more universal. Even if the chef was the one preparing the dish, it’s more likely that the soup will turn out the way I want if I provide a recipe. Because who knows? Maybe the chef likes to add heavy cream to all their soup, and that’s not something I want to eat!
Writing declarative code involves a lot of dependency injection and “pure” functions; you provide the computer all the data it needs to perform a calculation, rather than assuming it will go find that data on its own. For me, this leads to fewer bugs and easier modifications, not to mention more readable code. If you’ve ever had to trace the path of a variable around ten different files, you know what I mean.
I’m still writing imperative code; I still use classes and objects, but I also use immutable data, dependency injection, and partial application. There’s no wrong way to use a programming language, but there is always room for improvement. I can’t wait to see what I’ll learn next.