Swizec Teller - a geek with a hatswizec.com

    The Italian foods theory of bad software design ๐Ÿ

    You know about spaghetti code. Code so confusing it looks like a bowl of spaghetti.

    But have you heard of ravioli and lasagna code?

    I don't know why we name bad practices after delicious Italian foods, but a recent conversation about splitting up a monolith inspired me to add another โ€“ย minestrone software.

    Swizec Teller in ๐Ÿ‡ธ๐Ÿ‡ฎ avatarSwizec Teller in ๐Ÿ‡ธ๐Ÿ‡ฎ@Swizec
    Spaghetti code โ€“ unstructured
    Ravioli code โ€“ย too structured
    Lasagna code โ€“ย layered wrong

    Adding Minestrone software โ€“ย unclear domains
    Tweet media

    Here's how different Italian foods capture bad software practices. Growing up next to Northern Italy, I have cooked all of these from scratch which makes me an expert ๐Ÿ‘จโ€๐Ÿณ

    Spaghetti code

    Spaghetti code is the easiest to spot. When you have to jump around to understand how something works, that's spaghetti code.

    Commonly produced when you take clean code rules too seriously.

    Swizec Teller in ๐Ÿ‡ธ๐Ÿ‡ฎ avatarSwizec Teller in ๐Ÿ‡ธ๐Ÿ‡ฎ@Swizec
    The easiest way to write unreadable code is by splitting your functionality across 20 clean small functions.

    I asked twitter for examples. Here's my favorite

    From an article about why GOTO is bad โ€“ because it jumps around. Arrows show the flow of execution in that code.

    You can achieve similar results with function calls.

    Like this terrifying suggestion:

    Nicolas Beaussart avatarNicolas Beaussart@beaussan
    @Swizec How about a react class component that in the render function create component on the fly that access and modify the state of the patent component? And thoes components create also components within them that modify the same state

    You can do that with React hooks. But let's not ...

    Ravioli code

    Ravioli code happens when your code makes sense in isolation, but the system as a whole is confusing. Think emergent behaviors.

    We can use Conway's Game of Life as an analogy. A code example would be too long.

    Gosper's glider gun in Game of Life

    3 rules govern the next state of each cell:

    1. Any live cell with two or three live neighbours survives.
    2. Any dead cell with three live neighbours becomes a live cell.
    3. All other live cells die in the next generation. Similarly, all other dead cells stay dead.

    You can think of each cell as a well-defined class. Follows sensible rules and makes sense in isolation.

    Put them all together and you get ... an infinitely looping glider gun? Even a breeder that creates guns?? ๐Ÿคจ

    Game of Life breeder

    Yeah, confusing.

    Lasagna code

    Lasagna code happens when you structure your code in layers and forget to create abstractions. Common in module-view-controller architectures, React components, and typical approaches to GraphQL and RESTful API design.

    Here's an example I've seen time and again.

    Storage layer

    The storage layer keeps your data. A filesystem or database. Secretly it also holds your domain model, but we rarely talk about that.

    Article {
    id: uuid
    title: text
    content: text
    created_at: timestamp
    author_id: fkey(User)
    }

    Articles have title, content, are created_at a time, and belong to an author.

    Service layer

    The service layer builds on top of your storage layer and adds the business logic. This is where task-based functions go.

    function getLatestArticlesByAuthor(author_id, count) {
    return query(
    `select * from Articles
    where author_id=${author_id}
    order by created_at
    limit ${count}`
    )
    }

    Returns the latest count articles from an author. Production code would add error handling and more complex business logic.

    Controller layer

    The controller layer translates API requests to service layer function calls. Modern frameworks hide all the complexity of parsing requests and constructing responses.

    You write the glue:

    exports.latestArticles = async (req, res) => {
    const { author_id } = req.params
    const articles = ArticleService.getLatestArticlesByAuthor(author_id, 10)
    return res.send(200).json(articles)
    }

    We snuck in some business logic! We're saying that "latest" means 10. Does that go in the controller? ๐Ÿค”

    API layer

    The API layer specifies what your communication between client and server looks like. The shape of requests and responses. For RESTful APIs you put this in an OpenAPI spec, for GraphQL this whole layer is "POST a query".

    {
    "/articles/:author_id/latest": {
    get: {
    description: "Returns latest articles by author"
    parameters: {
    author_id: {
    in: "path",
    required: true,
    schema: {
    type: "integer"
    }
    }
    },
    responses: {
    200: {
    description: "OK"
    content: {
    "application/json": {
    schema: {
    type: "array",
    items: {
    type: "object",
    properties: {
    id: { type: "string", format: "uuid" },
    title: { type: "string" },
    content: { type: "string" },
    created_at: { type: "string", format: "date-time" },
    author_id: { type: "integer" }
    }
    }
    }
    }
    }
    }
    }
    }
    }
    }

    Yes, that's a lot of work to say "You'll get the full unchanged Article object from the database". It's more useful in production code.

    Client render layer

    On the client you then have to render these objects.

    const LatestArticles = ({ articles, author }) => {
    const sorted = articles.sort(
    (a, b) => new Date(b.created_at) - new Date(a.created_at)
    )
    return (
    <div>
    <h2>Latest from {author.name}</h2>
    {sorted.map((article) => (
    <ArticleListing {...article} />
    ))}
    </div>
    )
    }

    Sort articles by created_at and render an <ArticleListing> component for each. We pass the whole article object as individual props.

    const ArticleListing = ({ id, created_at, title, content }) => {
    return (
    <div>
    <h3>{title}</h3>
    <label className="created_at">Created at: {created_at}</label>
    <p>{content.substr(100)}</p>
    </div>
    )
    }

    Each article listing shows a title, the created_at timestamp, and the first 100 characters of the content as a lazy summary.

    Client style layer

    We want the created_at label to have a specific style and have chosen to use CSS because styling inside JavaScript is dirty or whatever. There are people who think like that ๐Ÿคทโ€โ™‚๏ธ

    label.created_at {
    font-size: 0.6em;
    font-style: italic;
    }

    The Lasagna collapses

    Okay dear reader, we want to distinguish between when an article was created and when it was published. How many layers do you have to change?

    I count ... all except the controller. All this work to create well-structured layers and just one has a meaningful abstraction ๐Ÿ™ƒ

    See also: A feature based approach to React development

    A modern approach to separation of concerns
    A modern approach to separation of concerns

    Minestrone software

    Minestrone software happens when you have unclear domains.

    You won't see this in tutorials because it requires a sizeable software project. You may never find a project big enough for minestrone to be a problem.

    How you cook mom's minestrone:

    1. take big pot
    2. see what's in fridge
    3. throw in a few things that look good
    4. add water
    5. boil for a while
    6. taste minestrone
    7. add more ingredients to taste
    8. wait more
    9. adjust spices (salt and such) to taste

    Then you eat that big pot of minestrone all week. There is no other food in the house. If you don't like the minestrone you are given, feel free to add more ingredients.

    How you make minestrone software

    Replace the pot with software or company and ingredients with features ๐Ÿ‘‰ Minestrone software!

    Why make a new module for a new function when there's already a fine module right there? It's even imported and everything! How bad can adding more be.

    Why make a new database table when an extra column will do? Who cares if your tables now mean multiple things.

    Why make a new (micro)service when you have all this working boilerplate in The Big One? Adding a little extra won't hurt ...

    How you recognize minestrone software

    Fast forward a few years, a few iterations, a few teams, a few team members, and you're us. Figuring out how to split a monolith into microservices, struggling to structure yourself into functional teams, stepping on each other's toes, and can't even agree on the meaning of your database tables.

    Overlapping team responsibilities is a symptom of minestrone software. Or when you need multiple teams to build 1 feature.

    At smaller scale, you've got minestrone when you can't decide what file a function goes into. That means your files (or modules) aren't well-defined. Or even when you're not sure which function or component to add to.

    Unclear business domains mean you're not sure where code goes, who owns what, what new teams you need, or which microservice makes sense.

    Writing well-structured software without a good domain model is impossible. No matter how clean your code.

    Swizec Teller in ๐Ÿ‡ธ๐Ÿ‡ฎ avatarSwizec Teller in ๐Ÿ‡ธ๐Ÿ‡ฎ@Swizec
    If your data model is good, the code is easy.

    If your data model is bad, the code is spaghetti.

    Your software is one big minestrone. The secret ingredient is love.

    Cheers,
    ~Swizec

    PS: anyone who tells you there is a recipe for minestrone is lying and has never been to Italy. Every mom and grandma makes it different

    Did you enjoy this article?

    Published on May 23rd, 2022 in Software Engineering, Lessons, Spaghetti Code,

    Learned something new?
    Read more Software Engineering Lessons from Production

    I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.

    Subscribe below ๐Ÿ‘‡

    Software Engineering Lessons from Production

    Join Swizec's Newsletter and get insightful emails ๐Ÿ’Œ on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.

    "Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. ๐Ÿ‘Œ"

    ~ Ashish Kumar

    Join 15,883+ engineers learning lessons from my "raw and honest from the heart" emails.

    โญ๏ธโญ๏ธโญ๏ธโญ๏ธโœจ
    4.5 stars average rating

    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

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

    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 โค๏ธ