Imperative to Declarative in 4 Simple Steps


Imperative programming has been the leading paradigm of software development in recent history, spanning languages such as Java, PHP and JavaScript ES5. The primary markers of imperative programming are in its reasoning style, being classically algorithmic in nature; often composed largely of for-loops and if-statements.

Nowadays, new programming approaches have evolved through far greater adoption of newer languages and utility frameworks, with JavaScript ES6 and Python being some of the foremost exponents of these ideas. These languages make it easy to write code that explains what the code achieves, rather than how it achieves it. This is a massive improvement over older paradigms, as it makes code far more readable and thus far easier to reason about.

Developers can often unintentionally obfuscate work behind the edifice of the languages we write in. Professionally, we find that it is far easier to engage with stakeholders, business experts, and QAs, when the code we have produced has a English-like structure – one that tells a story! 

Below is a simple example written in the imperative style that hits an external API to retrieve random users a set number of times, filters and maps by age and email, then saves these to a separate variable.  

imperative to declarative one

Confusing to follow! It would be much improved by being written in the declarative style. But how can we do this? Rewriting this from scratch is an option, but instead, let’s try to rewrite it one bit at a time, checking to make sure it continues to function and see where we get to.

Step 1 – Use of Filter & Map

The best place to start is by cleaning up the largest chunk of code in the snippet, where we filter our users and map them to their emails. Thinking about the paradigm we used there, wouldn’t it be good if there were such a thing as map and filter. The excellent news is there is with ES6 array methods, and we can write this using a readable chaining syntax.

imperative to declarative two

Step 2 – Default Parameters

Staying in this area of the code, we can see that we declare a constant `minimumAgeForFilter` that is set to a fallback value if none is passed in. This can be tidied up by using a default parameter.

imperative to declarative three

​Step 3 – Async/Await

The next thing to look at is all the `thens` peppered around the code. Structurally, they are there to enable control of synchronicity to our asynchronous api requests. In order to do this, previously we would have to chain them in a confusing nested strucuture. Instead, we can now use the Async/Await keywords in order to make this far easier to read.

imperative to declarative four

Step 4 – Declare constants

Looking at the routine now, we can see the results array being modified and each function simply having a return keyword. This means that there are multiple side effects occuring, and this generally makes our work far harder to reason about and understand.

imperative to declarative five


The final code can be found here. Have a look, and I’m sure you will agree it’s a lot cleaner after all that!


Curiosity is what drives us to learn and grow professionally enabling us to remain vigilant to change and the opportunities it presents for our clients. We document some of this learning and share it via our 'Insights' section.