DEV Community

Cover image for Scalable architectures / Code management, tip 1: imperative vs declarative
Julián Mulet
Julián Mulet

Posted on

Scalable architectures / Code management, tip 1: imperative vs declarative

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
Enter fullscreen mode Exit fullscreen mode
/*
* 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]);
    }
};
Enter fullscreen mode Exit fullscreen mode
// 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);
});
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode
/*
* 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;
}
Enter fullscreen mode Exit fullscreen mode
/*
* 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
    ),
  },
};
Enter fullscreen mode Exit fullscreen mode

// 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>
  );
};
Enter fullscreen mode Exit fullscreen mode

Thank you for taking the time to read and share your thoughts.

Julián Mulet

Top comments (0)