10 Lead Software Developer Principles

NM

Nicklas Millard

published January 4, 2024

I’ve collected a few principles I often use actively in my day-to-day work as a lead software developer. The principles are listed at random and some may even be conflicting, nevertheless, they’re all helpful and easily applied.

Be a domain expert

Do you know how hard it is to produce working, quality software without being an expert in the business that you’re writing code for?

You probably do know. Developers often work with businesses and domains they know nothing about. But let me tell you, domain expertise trumps technical knowledge in the majority of cases.

Having only technical knowledge you’ll be able to do the wrong thing technically correct, which is worse than doing nothing.

Seek all the domain knowledge you can. Soak it up. Write it down. Keep it at hand, all the time.

Small over large

This goes for a lot of things. It’s way easier to build small features over large ones. It’s easier to develop in small teams than in larger teams. Three people can coordinate better than six people. A system of small classes is preferred over a few large classes.

Small is often the way to go, and sometimes it’s also more difficult to create bite-size pieces. Complexity has a hard time hiding in small but is native to large.

New on hold to fix old

Building green-field projects and entirely new features from the ground up is undeniably more gratifying than fixing some old performance issue or a wacky interface.

I get it.

New is fun. It’s what gets all the attention. But, fixing things in old code, i.e. often production software, is generally more important than building new features. Customers are buying what’s already there, and if what’s there is broken, then customers will be leaving.

You can derive great learnings from bug-fixing and performance optimizations, ensuring that the new thing you’ll build is going to be even better based on those learnings.

Create tests proving bugs are fixed

The first step to any bug fixing generally starts by creating a test that uses the exact data that made the program fail. You’d want to reproduce the bug confidently. If you can’t, how can you ever be sure that you’re fixing the right thing?

Whenever I fix a bug that was found in production, I’ll try to mimic the actual circumstances as best as possible. Did we fetch data from a database? Make sure to use a real database, e.g. by using test containers. Did we call an external HTTP API? Make the same call returning the actual response that the API returned. Was a file loaded from or written to disk? Do the same.

Take it a step further. Investigate what caused the bug. Was it neglect? Was the assigned developer not skilled enough? Did we do a sloppy code review? Was it a poorly written or ambiguous user story? Were the acceptance criteria incomplete?

How are you going to prevent future bugs if you don’t know the underlying reason that causes them? Bugs don’t solely happen because a developer screwed up.

Assume people do the best they can

Assuming anything in software development is a bad idea. However, there’s an exception. Always start from the assumption that people do the best work they can, with the time, knowledge, resources, and abilities they have. People generally dislike making bad decisions, writing bad code, engaging in malicious behavior, and neglect.

Do recognize that errors and shortcomings stem from time constraints, knowledge gaps, and limited resources.

This is not to excuse a senior or lead developer not knowing what they’re doing. It’s simply to try to force nuanced thinking instead of blatantly criticizing other’s work.

On very rare occasions, I’ve heard a developer say something along the lines of “I’m not sure how this should work. We’ll let QA create a bug ticket if it’s wrong.” Don’t let comments like that slide. If you need to have an uncomfortable conversation right there and then, then have it. There’s no room for such stupidity.

I get that you might want to push it to QA to figure it out. Perhaps even often. But, take a step back, and do something else for a second. When you get back, make sure to seek out all the clarifications you need. Ask the people you need to. Show examples. Demo different approaches, and do whatever you need to instill certainty in what you do is also the right thing.

Don’t work on vague problems

Always seek clarifications early on in the development process. This core principle is a vital value that emphasizes the need to gain a deep understanding of requirements, constraints, expectations, quality level, and timeframe before commencing actual development work.

Understand the significance of the task or feature and identify the most knowledgeable individuals who can assist you. Recognize that you often encounter unknown unknowns, particularly when entering into a new domain. Maintain a proactive approach by consistently seeking clarification throughout the development process. Before you start implementing potential solutions, take a second to assess your readiness by considering the following questions:

  • Do I know who to ask for help?
  • Do I know when to ask for help?
  • Do I know the effective methods for requesting clarification when uncertain about a feature and its desired functionality?

I like to ask a business analyst or product owner “What questions haven’t you asked me to show that I understand this?”

Embrace constraints

I know I’ve just said it, but I’ll say it again: it’s very, very difficult to write any good software without constraints.

Constraints are what’s keeping us from over-engineering, gold-plating, focusing on all the wrong things, and making incomprehensible architectures and systems. Knowing the constraints of a feature makes it much easier to design, implement, and evaluate. You know its boundaries, and what should be possible. It’s easy to test and verify.

The opposite is true when it comes to building a feature and you’ve no idea of where its boundary is at. How would you ever test that?

Kill your darlings.

A principle rooted in writing, as far I know. I first heard this expression during my undergraduate studies.

To me, in software development, it means removing any code or comment that doesn’t fit the purpose or isn’t necessary. It’s perhaps your best piece of work. The most creative code you’ve written. But, if it’s only there for your self-indulgence, then it has to go.

Build for evolution early on

Think ahead. How would this feature evolve? Are we likely to swap this out? Are we going to add more options later?

Thinking ahead is cheap. Building for evolution is easier, and safer, than repurposing existing code. Thinking about extensibility points and implementing features so that they can be swapped, extended, or modified, is often a good investment.

I’d encourage every developer to get good a spotting business policies and rules. While policies generally remain rather stable, the rules that constitute a policy frequently change.

This is not a free pass to gold plate everything. Building flexible code is about anticipating, and ultimately allowing change, as well as it’s about making a deliberate effort to weigh the consequences of not allowing change.

Be a professional

Always present yourself professionally, in your conduct and technical abilities. Don’t engage in one-upmanship or competitive story-telling. Communicate with clients on their terms. Never trash-talk existing code, former coworkers, and workplaces. Refrain from engaging in blame games, blame-shifting, and scapegoating.

It’s fine to share war stories but don’t put a name on it.

Being a professional obviously isn’t a thing unique to software development, but unfortunately, I do think many software developers have the unique capacity to act wildly unprofessional in a workplace.

Let's Stay in touch

You're always welcome to reach out at nicklas@mjukvare.com!

Nicklas Millard

© 2026