“Codemodable”: The elegant code that grows with you

·3 min read

When you start a greenfield project, AI allows you to ship at the speed of thought. However, as your project grows in size, your code may not evolve as quickly as you would like. It doesn't have to be this way. Andrew and I would love to refer to such code as "elegant," which has a straightforward definition.

The term "codemod" refers to a tool that assists developers in making systematic changes to their source code. A codebase becomes more "codemodable" when it is structured in a way that allows for these automated modifications to be performed easily and reliably. With that, fleet-wide modernization becomes possible, and that’s crucial especially as the size of codebases grows exponentially thanks to AI.

Here are some factors that can make code more or less amenable to codemodding:

Consistency

If the code follows consistent patterns and styles, it's easier to apply a codemod because the tool can predictably identify the parts that need changes.

More codemodable: Functions and methods follow a consistent naming convention, making it easier to target them.

function calculateTotal() { /*...*/ }
function calculateDiscount() { /*...*/ }
function calcTotal() { /*...*/ }
function getDiscountAmount() { /*...*/ }

Complexity

Simpler, less complex code with fewer dependencies is typically easier to modify with a codemod.

More codemodable: Simple, single-purpose functions.

def add(a, b):
return a + b

Less codemodable: Nested functions with complex logic.

def calculate(a, b, option):
if option == 'add':
def add(x, y):
return x + y
return add(a, b)
# More complex logic...

Test Coverage

Having a comprehensive suite of tests allows developers to ensure that the codemod has not broken any existing functionality.

More codemodable: Code accompanied by tests.

function add(a, b) { return a + b; }
console.assert(add(2, 2) === 4);

Less codemodable: Code with no tests.

function add(a, b) { return a + b; }

Modularity

Code that is modular and composed of small, single-responsibility functions or classes is easier to target with codemods because changes can be isolated to specific modules without affecting others.

More codemodable: Code organized in modules or classes.

class Calculator {
add(a: number, b: number) { return a + b; }
}

Less codemodable: All logic in a single file or function.

function calculate(a: number, b: number, op: string) {
if (op === 'add') { return a + b; }
// More operations...
}

API Stability

If the code relies on APIs that are stable and backward compatible, codemods can be written with the confidence that the API contract won't change unexpectedly.

More codemodable: Using well-established libraries or APIs.

import requests
response = requests.get('<https://api.example.com/data>')

Less codemodable: Using custom, frequently changing APIs.

import myCustomApi
response = myCustomApi.get('<https://api.example.com/data>')

Abstraction Level

Code that operates at a higher level of abstraction may be easier to codemod because changes can be made at the abstraction level rather than having to account for many low-level details.

More codemodable: High-level abstractions.

public interface IShape {
void Draw();
}

Less codemodable: Low-level, detailed implementations.

public class Circle {
// Complex drawing logic involving graphics primitives
}

Making code more "codemodable" often involves cleaning up and refactoring the codebase to improve these aspects, which not only facilitates the use of codemods but generally leads to a cleaner, more maintainable, and more robust codebase.

Start migrating in seconds

Save days of manual work by running automation recipes to automate framework upgrades, right from your CLI, IDE or web app.

Get started