The "Simple, elegant type system is all you need" bias
Tags: programming, webdev, javascript, typescript
Published: 2022-02-19 15:20:51

This [**Spaghetti code**](https://dev.to/latobibor/series/6426) article will be on the soft side as in soft-skills as I am going to talk about a very frequent and very typically engineering bias that leads to spaghetti code. This article is about a human bias, it is not a _JS article_ nor `React` though all my examples will be in this language or in a pseudo-web framework.

## "Do not disturb my circles!"
Originally from Latin ([_"Nōlī turbāre circulōs meōs!"_](https://en.wikipedia.org/wiki/Noli_turbare_circulos_meos!)) it is said to be a quote from Archimedes, almost his final words, shouting at an invading Roman soldier while he was minding his geometrical studies in the sand.

> The _"Do not disturb my circles!"_ bias is when we _assume we can provide an elegant type system_ of which _can cover all use cases_. When the **real use cases** show up, instead of adopting or changing the system completely, we push back, question or hack these new requirements into the _no-longer_ **beautiful type system**.

Maybe this bias has a better name, however I am not literate enough in the psychology of biases to know it, so hereby I will name it like this.

## Examples
Let's say the engineering team is presented a handful of design slides. Every slide is covering some problems the users face: there is a `title`, a `description` and an `action` to take in form of a button.

**Engineer A** will now propose that _"Uh um, very easy! All I need is this simple structure:"_

```javascript
const userSolution = {
  title: 'Some title',
  description: 'This is where the description will be.',
  action() {
     // TODO
  },
  actionText: 'Press the button'
};
```

They then proceed and create an entire system based on the assumption that in fact this is the type at heart. Multiple layers of tests are written. The layout is set in stone:

```html
<slide-title>{title}</slide-title>
<description>{description}</description>
<button on-click={action}>{actionText}</button>
```

Weeks later the UX report comes back:

_"We tested the prototypes and a couple of changes will be needed:"_
- One slide will have an alternative `action`
- One slide will not have a `description` or `title` but an entire `video` instead and a link below
- One slide will have a clickable icon instead of the button, no text
- An there will be a "rich slide", where an interactive custom built "widget" will be placed between the `title` and the `description`

### The reaction
I have seen many reactions to this scenario, most of which is **toxic** to the codebase or to the product:
- **Denial:** _"Is this really what people need? They will get confused because the system is so varied now!"_ The more confrontative devs will do it, with the occasional deep sighs, that they are forced to ruin their code with this mess.
- **Condition-mania**: in which every possible property is added as an `optional` value. The entire codebase is now a mess of `if-else` and `description && <description>...</description>` blocks, it is hard to see what the end result will look like
- **Chicken typing** 🐥: it's like 🦆 duck typing just worse: the duck typing is based on flimsy guesses, existing properties are reused with totally different meaning, say if the title has the word `video` in it, then it must be the `video` slide: `if (title.contains('video') { slide.description = <embed video={slide.decription} />`
- **Math cowboy**: finds the _greatest common divisor_ of all types and actions and runs with it. Looks smart at first but totally obfuscates any system. (See below).

Sometimes all 3 will appear, so there is a product compromise like a _"Description"_ header remaining on the page even though there is now clearly a video being embedded there. The code is littered with ugly conditional-fixes and superfluous guesses what to do based on a moving target.

### The math-cowboys
Let's see an example:

``` javascript
// OK, so now my structure can look like anything
// then use Map
const textSlide = new Map();
textSlide.set('title', 'This is smart slide');
textSlide.set('description', 'This is smart description');
textSlide.set('action', () => {});
textSlide.set('actionText', 'Press the button');
```

Looks smart, but **it is extremely hard to use**: for every `property` now you have to test whether it exists. You will never be sure how many different slides exist since the real world handful cases are now replaced by infinite possibilities. The system now must be carefully analysed before anything is changed.

And why? The `math-cowboy` did not want to get bothered adjusting their system later.

**Fun fact:** I knew a guy who ignored the `class` system of `Java` and used `Map<String, Object> map = new HashMap<String, Object>();` to cover every case. 

Polymorphism? Ha! That is so constraining. Let lesser people work instead.

## One possible solution
_Generally_ I think it is a good stance to write _simple_ and _easy to refactor_ code when the user needs are not properly understood yet. No need to write future-proof, but instead something straightforward and easy to change.

That way when change comes you will be OK with the idea to redo your system grounds up maybe.

_In the concretion_ with the case above my battle tested solution is to anticipate early the polymorphic nature if real world cases with a trustable duck typing system in place.

I have written about this in my [Toxic optionals](https://dev.to/latobibor/toxic-optionals-typescript-55bj) article, but here's a very short refresher if you don't want to click.

**First iteration**

```typescript
enum SlideTypes {
  Text,
}

type TextSlide = {
  type: SlideTypes.Text;
  title: string;
  description: string;
  action: { 
    text: string;
    effect: () => {};
  }
};
```

**Second iteration**

```typescript
enum SlideTypes {
  Text,
  Video,
  AlternativeAction,
  RichSlide,
}

type TextSlide = {
  type: SlideTypes.Text;
  title: string;
  description: string;
  action: { 
    text: string;
    effect: () => {};
  }
};

type VideoSlide = {
  type: SlideTypes.Video;
  videoUrl: string;
  action: { 
    text: string;
    effect: () => {};
  }
};

type AlternativeAction = {
  type: SlideTypes.Text;
  title: string;
  description: string;
  mainAction: { 
    text: string;
    effect: () => {};
  };
  alternativeAction: {
    text: string;
    effect: () => {};
  };
}

// ...
```

All these slides can now get a **sub-component** where there is no `conditional magic` and are _short_ and _super easy_ to read.

And later on the page when you need to output the specific slides you just do a good ol' `switch-case` (I know it's very old-school):

```typescript
switch (slide.type) {
   case SlidesType.Text:
     return <text-slide data={slide} />;
   case SlidesType.Video:
     return <video-slide url={slide.videoUrl} action={slide.action} />;
    // ...
}
```