Skip to content

Instantly share code, notes, and snippets.

@mfdj
Last active October 5, 2022 16:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mfdj/04c3bba06b221aa5802e349bb3e221ee to your computer and use it in GitHub Desktop.
Save mfdj/04c3bba06b221aa5802e349bb3e221ee to your computer and use it in GitHub Desktop.
Alphabetize your set items and map keys

Alphabetize your set items and map keys

This document looks at certain data-structures and makes the case for alphanumeric ordering to optimize developer experience (DX).

Strategies for organizing code

Authoring code (like any language) is about expressing ideas in an structured, intentional fashion. Obviously it needs to be correct for the computational device, and succeed as a software production, but we also want to make it comprehensible to our fellow humans.

To make code comprehensible I've observed the following stratgeies (I'm sure this list isn't exahustive, but it is tractable):

  1. Hierarchical (context dependent but relies on an intuitive grasp of what is most to least important to a reader - often mirrors actual logic of the code)
  2. Clustering/grouping (co-locating similar or related things)
  3. Insert next (just add new stuff to the bottom)
  4. Alphanumeric (very very regular, which can be good or bad depending)

The first person to create a file generally selects one or more of these strategies and makes that first commit. Before making that first commit the choices are relatively inconsequential.

Each language, framework, and specific aspects of a given application will naturally suggest prioritizing certain strategies. This document will illustrate why Sets and Maps generally benefit from alphabetical organization using JavaScript as the example language.

Sets and Maps in JavaScript

The Set data structure is new to the language, but this advice could apply to any Set-like array (i.e. an array with unique items).

const formalSet = new Set(['Jack', 'King', 'Queen', 'Joker'])
const informalSet = ['Jack', 'King', 'Queen', 'Joker'] // while not a formal Set is functionally equivalent

(Aside: JavaScript arrays inherently support "List" behavior in that they have a specific order, i.e. the order isn't a code formatting issue, it's a logical issue.)

When referring to an "Map" in this document I mean generally any Map-like data structure. So anything concerned with mapping keys to values, including "plain old JavaScript objects" but not Class definitions (although these could follow this advice in parts but probably not strictly as a whole).

We think about strategey because code will change

If a given file is never touched after the first commit then whatever initial choices the author made will probably be good enough. However, and this may shock you, software tends to change. The bigger the codebase, and the more contributors it has, the more consequential the choice (or non-choice) of code organizing strategies becomes.

In many cases static definitions of data structures can tend to be small so perscibring a certain organization to them can initially seem like bizzare pedantry. However there are often parts of the codebase (like configuration) where statically defined data-strucutres can be large, or frequntly changing. The inspiration for this document comes from props in React, but there are many, many others examples.

The main goals of choosing a particular strategy involve:

  1. Minimize choice overhead
  2. Maximise code comprehensibility
  3. Minimize code conflicts (espcially with parallel development)

Problems with hierarchical and clustering in data structures

When organizing data structures I tend to notice engineers intuitively follow a combination of logical-hierarchy and clustering. This makes sense for functions, methods, variables, that have drawbacks as data structures grow or change.

As the number of Set items and Map keys grows, the subjectivity increases, intutition diminishes, confusion increases. As you search a data structure for a particular line, it's harder to guess where it will be, and therefroe hard to choose where new code should be inserted.

Because of the insertion problem, when modifying code, I tend to notice engineers graviate too "insert next".

Problems with insert next

An obvious drawback for insert next is that it's a form of arbitrariness, i.e. the reader generally doesn't care when code was added (an if they do then source control history can answer that question much better).

An seeming advatnage of insert next is that it's very simple for writing code — just scroll to the bottom and go. However, when you consider parllel delvepoment this becomes less true.

Francesca + Jose are both working on the same lines of code in parallel — they both branch from main where set and map are in this state:

const set = new Set([
  'experiment',
  'title',
  'body',
  'wrapper',
  'head',
  'francesca-inserts',
]);

const map = {
  nextTitle: true,
  counter: 13,
  onExitApp: () => { window.location = '/go/here' },
  displayNext: (curent) => `${current}+`,
  onCleanup: (state) => JSON.stringify(state),
};

Francesca adds to set and map:

const set = new Set([
  'experiment',
  'title',
  'body',
  'wrapper',
  'head',
+ 'francesca-inserts',
]);

const map = {
  nextTitle: true,
  counter: 13,
  onExitApp: () => { window.location = '/go/here' },
  displayNext: (curent) => `${current}+`,
+ onCleanup: (state) => JSON.stringify(state),
};

Jose adds to set and updates map:

const set = new Set([
  'experiment',
  'title',
  'body',
  'wrapper',
  'head',
+ 'jose-inserts',
]);

const map = {
  nextTitle: true,
  counter: 13,
  onExitApp: () => { window.location = '/go/here' },
- displayNext: (curent) => `${current}+`,
+ displayPrevious: (curent) => `${current} 🌞`,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment