Scalable architectures / Code management, tip 1: imperative vs declarative
Julián Mulet
Posted on December 17, 2022
Cover attribution: Namroud Gorguis en Unsplash
Programming techniques and languages have evolved to make reading more intuitive for people, moving from a more #imperative approach, focused on how the task is processed, to a more #declarative one, focused on what is being processed.
This evolution is constantly changing and, therefore, it happens that what 20 years ago was considered declarative today is likely to fall more in the category of imperative.
In this article you can see two examples of this transformation. The first case starts from the #assembly language of a CPU and the second case from the #css markup language.
Evolution of general purpose languages
The for loop
// for-loop.asm
// source:
// https://eclecticlight.co/2021/06/29/code-in-arm-assembly-conditional-loops/
//
// here an imperative example of a classic for-loop
// written in ARM assembler code
// and the maximum index in X4:
MOV X5, #1 // start index = 1
MOV X4, #5 // end index = 5
for_loop:
// do_something
ADD X5, X5, #1 // increment the index by 1
CMP X5, X4 // check whether end index has been reached
B.LE for_loop // if index <= end index, loop back
// next code after loop
/*
* for-loop.c
*
* here you can show the declarative version of previous
* assembler example, nowadays this language C implementation
* is an imperative example:
*/
#include <stdio.h>
#define ARRAY_LENGTH(array_var) (sizeof(array_var) / sizeof((array_var)[0]))
void main(void)
{
int number_collection[] = {1, 2, 3, 4, 5};
size_t collection_length = ARRAY_LENGTH(number_collection);
int index;
for (index=0; index < collection_length; index++) {
do_something_with_number(number_collection[index]);
}
};
// for-loop.js
// here a declarative modern functional version of a
// ECMAScript 6 loop
const miscCollection = [1, 2, 3, "hello", "world"];
miscCollection.forEach((itemInCollection) => {
doSomethingWith(itemInCollection);
});
Evolution of CSS markup language
The abstraction layer
/*
* auto-layout.css
*
* Auto layout, imperative legacy css
*/
.horizontal-center-center {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
.horizontal-right-center {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
.vertical-bottom-center {
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
}
/*
* auto-layout.scss
*
* Auto layout, more declarative version because of
* use of semantic scss mixins
*/
@mixin auto-layout-base {
display: flex;
}
@mixin auto-layout-horizontal {
@include auto-layout-base;
flex-direction: row;
}
@mixin auto-layout-vertical {
@include auto-layout-base;
flex-direction: column;
}
.horizontal-center-center {
@include auto-layout-horizontal;
justify-content: center;
align-items: center;
}
.horizontal-right-center {
@include auto-layout-horizontal;
justify-content: flex-end;
align-items: center;
}
.vertical-bottom-center {
@include auto-layout-vertical;
justify-content: flex-end;
align-items: center;
}
/*
* auto-layout.css.ts
*
* full semantic vanilla-extract version
* https://vanilla-extract.style/
*/
import { mixVariants } from "@Utils/styles/mix-variants.css";
import { StyleRule, styleVariants } from "@vanilla-extract/css";
const base: StyleRule = {
display: "flex",
};
const horizontal: StyleRule = {
...base,
flexDirection: "row",
};
const vertical: StyleRule = {
...base,
flexDirection: "column",
};
const horizontalVariants = styleVariants({
center: [
horizontal,
{
justifyContent: "center",
},
],
right: [
horizontal,
{
justifyContent: "flex-end",
},
],
});
const horizontalAlignVariants = styleVariants({
center: {
alignItems: "center",
},
});
const verticalVariants = styleVariants({
bottom: [
vertical,
{
justifyContent: "flex-end",
},
],
});
const verticalAlignVariants = styleVariants({
center: {
alignItems: "center",
},
});
export const autoLayout = {
horizontal: {
center: mixVariants(
horizontalVariants.center,
horizontalAlignVariants
),
right: mixVariants(
horizontalVariants.right,
horizontalAlignVariants
),
},
vertical: {
bottom: mixVariants(
verticalVariants.bottom,
verticalAlignVariants
),
},
};
// AutoLayoutDemo.jsx
//
// This auto layout demo show examples of how to
// consume all above different style types
import legacyStyles from "./auto-layout-legacy.css";
import scssStyles from "./auto-layout.scss";
import { autoLayout } from "./auto-layout.css";
export const AutoLayoutDemo = ({ ...other }) => {
return (
<article>
<section class={legacyStyles["horizontal-center-center"]}>
<p>Horizontal Center Center</p>
</section>
<section class={scssStyles["horizontal-right-center"]}>
<p>Horizontal Right Center</p>
</section>
{/*
finally, the bellow example use the vanilla-extract
compiled css resources. Vanilla-extract is not a
runtime performance penalty tool like styled-components
or other similar inline styles tools
*/}
<section class={autoLayout.vertical.bottom.center}>
<p>Vertical Bottom Center</p>
</section>
</article>
);
};
Thank you for taking the time to read and share your thoughts.
Posted on December 17, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
December 17, 2022