Expert developers gravitate towards edge cases

tldr; Reflecting on 15+ years of projects, I find some of my most valuable contributions come from planning ahead for edge cases.

Simon Le Marchant
9 min read · 2024

Creative programming.

If I’ve worked alongside you on a project before, I apologize. I’ve likely stepped on your toes by shooting down an otherwise solid architecture plan, pull request, or pair programming session by pointing out a random issue that only impacts a small edge case of users. I’m often found in meetings pointing out all the things that can go wrong.

Whether it’s an unlikely combination of user input or a minor security vulnerability, my head tends to gravitate to the way things can go wrong. This can make me seem like a perfectionist, but it’s also a valuable trait for software lead. The best developers strike a balance between efficiency and mindfulness, watching for possible scenarios that might introduce bugs or degrade the project otherwise.

This isn't to say that every potential edge case should be addressed immediately and that we should go over everything with a fine-tooth comb; rather, the key is to be aware of edge cases and plan for them accordingly. Having an edge case continue to exist unfixed is okay, so long as it’s handled somehow. This could be as simple as dropping a note into Jira, GitHub Issues, a TODO comment, etc. The more edges cases are planned ahead for, the less headache your project will run into in the long-run; and writing them down is all it takes to have visibility into potential risk.

Efficiency vs. stability

So, when does an edge case matter? It depends on what you’re building - but ultimately comes down to efficiency vs. stability (or “risk”, if you look at it the other way around).

If you’re building an MVP, you’re likely in rapid feature-development mode. You have only a few weeks or months to get something out of the door, so you forego anything that isn’t mission-critical, planning to attend to it later. On the opposite end of the spectrum are enterprise-grade projects with strict quality requirements and high business impact. These are the types of projects that have anticipated 3-5+ year lifespans once deployed, where failure isn’t an option. You’ll want to prepare ahead for significantly more edge cases.

There’s no clear-cut answer here, it’s a sliding scale. Smaller, leaner projects demand more efficiency in development, whereas larger ones tend to require greater stability at the cost of slower development. I often wondered why large agencies took months to build something I could scrappily build in a week — edge cases are why.

An example: Learning to let go

Let’s jump into a bit of code that shows both higher and lower priority issues. This short snippet of JS code using the Notion API to query a list of case studies for my portfolio. I’ve truncated the handling of the response to simplify.

/**
 * Returns case studies from the Notion API
 */
getDataFromNotion = async () => {
  await notion.databases
    .query({
      database_id: process.env.NOTION_DATABASE_CASE_STUDIES,
      page_size: 100,
    })
    .then(async (response) => {
      // Handle the response
    });
};

This is sub-optimal. First-off, we should probably try/catch for API errors. That seems like a reasonable priority, as the Notion API may not always be available, and if it fails we don’t want our application to crash. In that scenario, we should return an empty array, or perhaps fallback to a cached backup.

Aside from that, I notice a glaring issue: the page_size property. We’re asking for up to 100 case studies, but we’re not properly handling pagination so we will never get more than 100 records. This needs to be fixed, right? Well, I post a full project case study once every 2-3 months. At that rate, it’ll take 15 years before this becomes a problem.

This is subtle, but important. I’m fully aware of a potential issue arising from the edge case of having 100+ case studies, but have assessed the risk and have determined it won’t impact the application in any significant way this decade. It’s low-risk, and although the code monkey inside me is yelling “fix it!”, my logical side is giving it a pass and saying “go tackle something more important”.

There’s another issue here, but I’ll leave that to the folks on Twitter to tear this code apart and tell me where I screwed up ;)

The value in recognizing edge cases early

On the flip side, there’s been plenty of times where code that myself or others have written seemed perfect, but had hidden drawbacks that needed fixing. Back to me stepping on toes, some of my most valuable contributions to projects have come from pushing back and suggesting we don’t continue - but instead pause and reflect on the code we had already written.

The pagination example above is trivial, but if this were an editorial organization with 500K+ articles that suddenly dropped from sitemaps, the impact to SEO could have been catastrophic. In other scenarios, simply thinking ahead to account for all possible edge cases allowed me to architect solutions that were significantly more flexible that we originally intended for — solving issues in the original vision that no-one else would have seen until it was too late.

This is where senior developers build value — by owning the project, understanding the intent and vision, and delivering a balance between efficiency and stability that matches the project requirements. Edge cases may seem trivial, until they redefine your project.