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

    Followup answers to Forget complicated code, focus on the system

    A few readers wrote in with questions after reading Forget complicated code, focus on the system earlier this week. Here are my answers.

    An anonymous reader writes

    The topic is frequently discussed, but rarely well. The outside research you put in shows and helps to make this insightful, rather than just another rehash.

    ❀️

    Then asks:

    Why are the 2 utility files on the right a code smell?

    They're talking about these files from my example of running Madge on a production React app.

    Util files found in code
    Util files found in code

    The problem with util files is that they're pure architectural complexity. The filename tells you nothing about what's inside and the dependency grows through your code like a weed.

    Worse: You'll inevitably find all that DRY was premature. You're falling prey to the DRY vs SoC dilemma and choosing to dedupe code that looks the same, but means different things semantically.

    When you inevitably need to evolve these utils in different directions for different areas of your code, it's a mess.

    What is a file neighborhood?

    Neighborhoods are a concept in graph theory, but really I got mixed up with cliques.

    Neighborhoods describe nodes that are connected. Cliques describe sets of nodes that are more connected than their next neighboring nodes.

    Cliques in a graph

    Since we're talking about a graph of file connections – file clique/neighborhood. A group of files that are more tightly connected to each other than to the rest of the system.

    Great questions anon!

    W. A. asks:

    Is there a meaningful difference between architectural complexity as summarized here and the complexity of a supersystem?

    Like a view where the code file relationships have become less relevant and there's multiple services & front ends?

    Little difference. You trade in-your-face complexity of a large monolithic codebase for non-deterministic stochastic behaviors of a swarm of cooperating agents.

    Draw a graph and you'd see the same. Cliques of files (internals of a service) sparsely connected to each other (API calls).

    I'll let this fun video explain why microservices don't save you from architectural complexity:

    Great question W. A!

    Another anon asks:

    when you have architectural complexity ... how do you detect it?

    You could use a codebase visualizer, but few people do. The clearest warning sign I've seen are files that start like this:

    const { ErrorBuilder, CodeError } = require("@asktia/tia-errors");
    const insuranceCoverageService = require("../../services/insurance-coverage");
    const payerService = require("../../services/insurance-coverage/payer-service");
    const clinicInsuranceService = require("../../services/insurance-coverage/clinic-insurance-service");
    const { Models, tiaSerialize, modelIsEmpty } = require("../../models");
    const eligibilityCheckController = require("./eligibility-check-controller");
    const moment = require("moment");
    const DrChronoSync = require("../../dr-chrono/dr-chrono-sync");
    const mentalHealthSummaryService = require("../../services/insurance-coverage/mh-summary-service");
    const {
    EligibilityErrorService,
    } = require("../../services/insurance/eligibility-error.service");

    See all those ../../? That's a sign the code isn't structured to group related files together.

    how do you fix it? how do you prevent it from coming back?

    A lot goes into this. I'm writing a whole book!

    In essence πŸ‘‰ you have to structure your code to match the business domain you are modeling. Vertical slices work best. Layers are good for plumbing.

    The commonest failure mode is to force arbitrary separation where it doesn't belong.

    Thanks anon!

    SD asks:

    What is transitive dependency?

    A dependency with multiple hops.

    A -> B -> C. If C depends on B and B depends on A, then C depends on A.

    This is important to get a true picture of your architectural complexity, but few tools take it into account when visualizing code. Alas.

    Thanks for the questions, keep 'em comin ❀️

    Cheers,
    ~Swizec

    Did you enjoy this article?

    Published on August 10th, 2023 in Software Engineering, Complexity, Architecture, Reader question,

    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 ❀️