Back to blog

Part 4: Imperative vs Declarative: Introduction

This series of blog posts builds on our previous set on The Challenges of Repeatable and Idempotent Schema Management:

This next series of blog posts discuss different approaches to the Management of Database Schemas and the wider topic of Database Object Lifecycle Management, which covers not just data carrying elements, but all Objects and Relationships in a Database including tables, view, users, roles, functions etc. These are handled in Databases as Data Definition Language (DDL) statements (as opposed to Data Manipulation Language (DML) which are the statements for actually adding/removing/updating the data within the Database).

Imperative vs Declarative

In all domains of technology (not just data), there are 2 fundamental concepts about how you define the change in state of a system, declarative vs imperative.

In a declarative approach you say WHAT you want the state of the system to be but NOT HOW – the engine that implements the declarative definition is responsible for turning the WHAT into the HOW.

Declarative example: 221b Baker Street, Marylebone, London

In an imperative approach you DON’T define WHAT to achieve, just HOW to achieve it

Imperative example: face north, walk 1.2 miles, turn right onto Oxford Street, walk 200 yards, turn left and then it’s 245 ft on the right.

This is full of verbs or actions, “turn” and “walk” – since this approach defines the HOW. One clear difference here is an imperative approach relies on a knowledge of the start point or the current state. The Imperative example above really only works from a single location/state, following these steps from any other location will not result in the desired end state. In fact, very likely these steps can’t even be followed at all – if my starting location/state is Brisbane, Australia I can “face north” and “walk 1.2 miles”, but I won’t be able to “turn right onto Oxford Street” – at that point everything fails and I’m in an unknown/undefined state.

There are numerous other sources to read about this at different levels of detail. However, one factor that most of these miss that the imperative and declarative are not two binary options; it is a spectrum. Consider this approach:

Example: Head to London, when you get there, head to Marylebone station. Head west until you get to Baker Street. Turn right and head north approx. 0.4 miles until you see the London Beetles Store and 221b Baker street is the next building.

This is a hybrid approach – it’s clearly not a fully declarative approach – there are some explicit steps, but nothing like as prescriptive as the imperative approach, but a lot more HOW than the declarative approach. This demonstrates that fully imperative and fully declarative are two points on a continuous spectrum. One interesting observation is that this hybrid approach is actually quite a lot more like human beings work in the real world. It’s a pragmatic mix that will achieve the desired end state from pretty much any start state, but requiring a lot less expertise or work on behalf of the traveller.

Declarative Compiler

In the Declarative Example approach, “221b Baker Street, Marylebone, London” is almost impossible to be used directly by anyone – it serves as a great definition of the end state, but I need to use a Declarative Compiler to turn that into something I can use. What could I use in this case? Google Maps™ would work:

Figure 1 - Google Maps as an Example Declarative Compiler

Figure 1 - Google Maps as an Example Declarative Compiler

This is just a set of clear, step by step instructions – pretty imperative! When we passed in a Declarative goal into the Declarative Compiler, what we got out was a set of Imperative steps.

Figure 2 - Declarative Compiler
Figure 2 - Declarative Compiler

This is true of virtually all systems, human or machine. At their core they follow a set of instructions and can only follow a set of instructions. This allows us to look at a Declarative definitions not as competing with an Imperative definition, but rather as a higher level of abstraction. Systems take Imperative instructions, we can either provide those directly, or define in a Declarative way and use a compiler to turn this into a set of Imperative instructions which are then executed by the system.