INDUSTRY INSIGHTS

Programming Lessons from a Carpenter

Srikanth V. (author photo)
Srikanth V.

VP Technology

Here’s a fairly straightforward insight: good code should be easy to read and understand.

I’ve found that using analogies to explain complex concepts helps make them more tangible and relatable. So here’s a slightly less straightforward insight: writing code is a lot like woodworking. 

To illustrate why, let me introduce Ravi, a skilled carpenter. By observing how Ravi works, we can draw parallels between his efficient practices in carpentry and the principles of clear, maintainable programming.

Lesson #1: Minimize the Tools You Carry

Ravi only brings the tools he needs for the task at hand, avoiding unnecessary clutter.

Key Takeaway

Pass only the parameters that are directly used in a method and avoid redundancies.

Lesson #2: Give Clear Names

Every tool in Ravi’s workshop has a clear, descriptive label such as ‘screwdriver’ or ‘oak plank’. This helps everyone understand their purpose immediately.

Key Takeaway

Use meaningful names for methods and variables, and follow conventions.

Lesson #3: Group Tools for Reuse

Ravi keeps commonly used tools, like measuring tapes and clamps in a shared toolbox for easy access.

Key Takeaway

Group reusable logic and constants into utility classes. For example, rather than defining validation methods separately across the codebase in multiple places like this:

public boolean isValidEmail(String email) {

    return email.contains(“@”) && email.contains(“.”);

}

public boolean isValidUsername(String username) {

    return username.length() > 3;

}

We can move this logic into a dedicated utility class for better reusability and maintainability: 

public class ValidatorUtils {

    public static boolean isValidEmail(String email) {

        return email.contains(“@”) && email.contains(“.”);

    }

 

    public static boolean isValidUsername(String username) {

        return username.length() > 3;

    }

}

This way, any part of the codebase that needs validation can simply call `ValidatorUtils.isValidEmail(email)`, reducing redundancy and improving consistency.

Lesson #4: Use Reliable References with a Whiteboard

On his whiteboard, Ravi writes some key values. For example, he has Table height: 75 cm written in permanent marker on it. These values never change, so his team can trust them. Temporary notes such as Cut 4 legs are written in erasable marker and may change as needed.

Key Takeaway

Constants reduce cognitive load when reading code by providing stable, unchanging references, unlike variables, which require closer tracking.

Lesson #5: Keep Work Focused

Ravi focuses on one task at a time, such as cutting wood or assembling a frame, without mixing multiple steps.

Key Takeaway

Keep methods focused on doing one thing well. For example, instead of mixing validation, user creation, and email sending in one method:

public void registerUser(String username, String email, String password) {

    if (username.length() < 3 || !email.contains(“@”) || password.length() < 8) {

        throw new IllegalArgumentException(“Invalid input”);

    }

    User user = new User(username, email, password);

    database.save(user);

    emailService.sendWelcomeEmail(user);

}

We should separate concerns:

public void registerUser(String username, String email, String password) {

    validateUserInput(username, email, password);

    User user = createUser(username, email, password);

    sendWelcomeEmail(user);

}

 

private void validateUserInput(String username, String email, String password) {

     // validation logic

}

 

private User createUser(String username, String email, String password) {

    User user = new User(username, email, password);

    database.save(user);

    return user;

}

 

private void sendWelcomeEmail(User user) {

    emailService.sendWelcomeEmail(user);

}

Each method does one thing, making the code clearer, easier to modify, and testable.

Lesson #6: Use Universal Tools

Ravi uses a clamp that works for all plank sizes, regardless of the project.

Key Takeaway

Use static methods for utility functions that don’t depend on instance variables.

Lesson #7: Make Work Easy to Understand

Ravi’s plans and instructions are so clear that anyone can step in and understand what’s happening without asking questions.

Key Takeaway

Write self-explanatory code. Add comments only for non-obvious logic.

Lesson #8: Improve While You Work

Each time Ravi works on a new project, he reorganises his tools and fixes inefficiencies, saving time in the future.

Key Takeaway

Refactor old code when adding new functionality to reduce technical debt. Technical debt refers to the time teams think they save when they prioritise speed over good code only to be met with projects that need to be refactored later.

Lesson #9: Break Big Tasks into Steps

Ravi breaks large tasks into smaller, manageable ones. For example, he first measures, then cuts, and then finally sands the wood.

Key Takeaway

Keep methods short and break down longer ones into smaller, reusable helpers.

Lesson #10: Handle Errors Gracefully

Ravi keeps a toolkit ready with backup materials (extra screws, spare planks, and a quick-fix adhesive) for when things go wrong during a project. If a plank splits or a nail bends, Ravi immediately uses his backups to fix the issue and keeps the work going smoothly, without panic or delay.

Key Takeaway

Handle errors in code gracefully by having backup logic or fallback mechanisms. Log clear and meaningful error messages to make debugging easier later.

Lesson #11: Don’t Rush to Perfect

Ravi doesn’t try to perfect his work right away. He starts simple and makes improvements only when needed.

Key Takeaway

Avoid premature optimisation. Optimise only when bottlenecks are identified. For example, instead of trying to optimise too early by using caching and complex data structures before knowing if performance is an issue:

private static final Map<String, Boolean> validationCache = new HashMap<>();

 

public boolean isValidEmail(String email) {

    if (validationCache.containsKey(email)) {

        return validationCache.get(email);

    }

    boolean isValid = email.contains(“@”) && email.contains(“.”);

    validationCache.put(email, isValid);

    return isValid;

}

We should start simple and optimise only if needed:

public boolean isValidEmail(String email) {

    return email.contains(“@”) && email.contains(“.”);

}

Later, if performance actually becomes a problem, then we can optimise further. Remember, the carpenter can sand away rough edges, but they can’t sand away a wobbly table. And a programmer can sand away messy code, but they can’t sand away syntax errors.

Leave a Reply

Your email address will not be published. Required fields are marked *