In contrast to the imperative programming, declarative programming is about describing what you're trying to achieve, without instructing how to do it. Read on and check out my presentation on programming paradigms.
The idea of imperative programming goes way back to 1950s, which is when the first high-level programming languages have been created. With 72 vacuum tube transistors and 18K of memory at disposal, the programs must have been as performant as possible. The only way to achieve it was to write programs in terms of step-by-step recipes for computer to execute.
However, let's stop here and look at the following, typically imperative example:
This code seems overly complicated, considering it just downloads, parses and handles some remote data. As the project evolves and developers add more steps — the Pyramid of Doom quickly emerges.
What is the alternative, you might ask?
In contrast to the imperative one, declarative programming is about describing what you're trying to achieve, without instructing how to do it.
Let's convert the imperative example above into a declarative one (using promise-like constructs):
Woah, this is much more legible. What's even better — wanna add a step? No problem! Just add one line to the stream:
Immutable objects are generally much easier to work with. Such objects can only be in one state, which cannot be modified across threads. You may share them, clone them, or even cache their data — all of that without worrying about them becoming stale.
You might be amazed how many easy-to-make and hard-to-detect bugs could be entirely eliminated by using immutable data structures.
Imagine you're debugging an unknown view controller, perhaps written by a team member. You find that a function F sometimes behaves differently for the same input parameters. After some examination, you find that it uses a public property x.
Then you look for places that modify x (inside and outside the view controller) and find that there are five of them. Good luck finding out which one is the true source of the bug. :)
This is why state is evil. Because literally anyone can change it, it cannot be relied upon.
Every time you had to restart an application or the computer to fix a problem, you were a victim of state gone out of control.
Let's face it — it's not clear what the above code is doing without examining it line-by-line. This typical flaw is derived from the very definition of imperative programming — that instead of declaring what you are trying to achieve, you tell the computer what it is supposed to do.
In case you're wondering how do further simplify the above example, here's a more declarative version of it:
Much simpler, isn't it?
Because declarative programs are generally simpler and safer, such projects are more maintainable and enjoyable for developers to work on.
It's not easy for a new team member to jump into a project with lots of mutable state, unclear procedures and implicit dependencies, though.
We're all used to the imperative paradigm. It's what all of us have been taught while learning to code, and that's the main reason why this age-old style is still dominant in modern programming languages. However, as software projects become more and more complex, it is more important than ever to write safe, understandable and scalable code — something undoable using classic approaches.
I strongly encourage that we, the developer community, take a second look at our imperative-oriented habits, see its shortcomings and challenge ourselves to try something completely opposite.
So that next time we're about to implement some functionality, we ask ourselves whether it can be written in a declarative manner, without any variables, loops, conditionals or callbacks.
You'd be surprised at how many times the answer is yes.
This is an excerpt from my talk at February's infoMEET conference: "Programming Paradigms — which one is the best?" Check it out below: