BattlefyBlogHistoryOpen menu
Close menuHistory

Stop running code in your head

Ronald Chen February 6th 2023

As I became a better programmer, I found myself analyzing code by running it in my head. I was simulating what the computer would do with the data.

This was an advantage back in the day when the edit-run-inspect cycle was slow due to tooling. sobs in gradle

But now, with modern tooling like vite, we have live reloading. edit-run-inspect becomes type-inspect.

With a quick feedback cycle, the computer runs code faster than I can simulate it in my head.

jest edit-run-inspect trap

This is especially evident when unit tests. Let's look at a simple JavaScript example. Let's say we are testing splitAtIndex(array, index). It returns two subarrays, split at the index. splitAtIndex(['a', 'b', 'c'], 1) ⇒ [['a'], ['b', 'c']]

A jest unit test would looks like,

test('middle odd left', () => {
  const result = splitAtIndex(['a', 'b', 'c'], 1);
  expect(result).toEqual([['a'], ['b', 'c']]);
});

But what about all the other scenarios? We need to test splitting an empty array, splitting at 0, and splitting at length. As we add more unit tests, we simulate the code in our head, then run the test. We are back to edit-run-inspect!

How can we escape this trap? How can we get back to type-inspect?

Visualizing scenarios

What if we created a workbench to visualize all the test scenarios for splitAtIndex?

The same "middle odd left" scenario is visualized:

That is so much easier to understand, and this effect would be compounded with a more complicated system under test.

To avoid duplicating the scenario in both the unit test and workbench, we can extract it into scenario.js:

export const middleOddLeft = {
  input: {
    array: ['a', 'b', 'c'],
    index: 1,
  },
  expected: [['a'], ['b', 'c']],
};

Jest can be made generic:

import * as Scenarios from './scenario.js';
import splitAtIndex from './split-at-index.js';

test.each(Object.entries(Scenarios))(
  '%s',
  (_, { input: { array, index }, expected }) => {
    const result = splitAtIndex(array, index);
    expect(result).toEqual(expected);
  }
);

The workbench visualizes the scenarios.

This can be implemented with any web framework. The key implementation idea is to iterate over the scenarios in both jest and the workbench to trivialize adding a new scenario to simply adding another export to scenario.js

Now adding a new scenario doesn't requires me to simulate the code anymore! All I need to do is add the new scenario input and any expected. I let the computer produce the actual result for me to inspect. If the actual result is correct, I copy it into expected. If it is not, it means I have a bug. I add the expected and then fix the code until expected is the same as actual.

That is too abstract, so let's go over the example of adding the split at "start" scenario.

Step 1. Add the stub scenario

export const start = {
  input: {
    array: ['a', 'b', 'c'],
    index: 0,
  },
  expected: [[], []], // wrong expected for now
};

Step 2. Inspect visualization

The actual is correct in this case.

Step 3. Update expected

Step 4. Re-inspect visualization

Remember all these steps can be done with the editor side-by-side with the visualization. There is no context switching to the visualization; the visualization is live reloading as we type.

Try the workbench for yourself. The workbench is implemented in vanilla JavaScript and jest.

Do you want to stop running code in your head? You're in luck, Battlefy is hiring.

Package monorepos
February 22nd 2023

2024

  • MLBB Custom Lobby Feature
    Stefan Wilson - April 16th 2024

2023

2022

Powered by
BATTLEFY