Swizec Teller - a geek with a hatswizec.com

Senior Mindset Book

Get promoted, earn a bigger salary, work for top companies

Senior Engineer Mindset cover
Learn more

    Smart core, thin interfaces

    Here's an approach to writing code that I've been using for years and couldn't quite put into words until now. One of those "This feels wrong but I can't explain why". Now I can!

    Smart core, thin interfaces

    The best way to avoid a big ball of mud is to use small balls of mud called modules.

    But how do you structure those?

    The approach I've seen work time and again and that keeps coming up across literature, is to build core business logic modules surrounded by interfaces for different actors. Based on the actor-command-event approach to domain modeling.

    Smart core, thin interfaces

    Empirically we know that modularization leads to maintainable adaptable software. Tightly coupled components are hard to kill and experience constant churn. Loosely coupled components tend to stabilize and are easy to replace when you need to.

    The smart core understands a business domain, its events and commands, and encapsulates the logic required to make it work. Like a billing module that understands the intricacies of your payment plans, discounts, subscriptions, and so on.

    The light-weight interfaces understand how different actors want to interact with this logic. Admins need to make exceptions, consumers want clear information, the integrations API cares about fault tolerance, and your backend systems need to be notified when something happens.

    Each actor has different needs, but they must all agree on the current state of the system and follow the same set of rules for what's possible when. Push that logic to the edges and mistakes are all but guaranteed. Keep it tightly packed and you stand a chance.

    That is to say: Repeat code with abandon. Avoid repeating semantics.

    If this sounds familiar, the philosophy flies under many names:

    They're all implementation details of the same idea:

    Sanitize at the edges

    Keep your business logic contained and hide the messy details behind a pretty interface. Avoid smearing that logic into other parts of the system and validate/sanitize inputs at the edges so your deep logic has fewer exceptions to deal with.

    Like this:

    function prettyInterface(input = null) {
      if (input) {
        doTheThingWithInput(input)
      } else {
        doTheThingWithoutInput()
      }
    }
    

    Instead of:

    function doTheThing(input = undefined) {
    	const data = db.query(sql`select * from blah where ${input ? 'col = '+input : 'col is null'})
    
    	if (data && input) {
    		return `Search ${input} found ${data}`
    	} else if (data && !input) {
    		return `Found ${data} with null values`
    	} else if (!data && input) {
    		return `Search ${input} found nothing`
    	} else if (!data && !input) {
    		return `No empty values found`
    	}
    }
    

    Without the interface, your deep method has to handle all possible branches in functionality. This makes it brittle. If it doesn't handle those exceptions, then everywhere you use that method has to deal with the exceptions. This makes every change impact a large part of your codebase.

    In practice you'd make the prettyInterface function public and the rest private. This helps you fight Hyrum's law by preventing unintended use. How you do that depends on your language and team conventions.

    What's an interface?

    An interface is any pile of code that translates public commands into internal function calls. How that looks depends on your context.

    For an API it might be a short controller function that takes an API request, cleans up the inputs, and calls an internal module.

    For a consumer UI, it can be a whole backend-for-frontend with server-side rendering and oodles of client code creating the app experience.

    Cheers,
    ~Swizec

    Published on December 10th, 2024 in Software Engineering, Architectural Complexity, Scaling Fast Book

    Did you enjoy this article?

    Continue reading about Smart core, thin interfaces

    Semantically similar articles hand-picked by GPT-4

    Senior Mindset Book

    Get promoted, earn a bigger salary, work for top companies

    Learn more

    Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.

    Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.

    Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.

    Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev

    Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization

    Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections

    Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog

    Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com

    By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️

    Created by Swizec with ❤️