The Importance of Consistent Coding in Teams
isaacharrisholt
Hey folks.
Quick announcement: this is the first edition of what I'm hoping will become the continuation of my long-forgotten newsletter. I'm also finally going to give it a name, making this the inaugural edition of The Founding Engineer.
Enjoy!
Often, when you're working on a team of developers, you'll come across some code and think:
What idiot wrote this?!
While not a totally productive mindset, it's often not totally unjustified either.
I find this happens to me a lot when working on solo projects, too.
It's usually not because the code is inherently bad; usually, this type of comment pops into my head when I see code that's written in a very antiquated style. Code written in a way that we as a team have not been writing for at least three weeks. You know, the really old stuff.
But it can happen. The industry in which we work moves incredibly quickly - faster than almost any other industry on the planet - and best practices and new tools for enforcing them are created almost as frequently as new JavaScript frameworks are released. It's because of that that I'm a big believer in ensuring your team codes in a consistent, well-understood way.
I'm not just talking about the usual stuff like formatting, either. Ideally, everyone on the team should structure code in a way that makes sense to other people on the team. Ideally, the phrase we want to be thinking when we read others' code is actually:
Did I write this?
I'd like to take some time to convince you that I'm right. I'll start by explaining why I'm right, then dive into some tactics for ensuring your team produces consistent code, and outline some potential roadblocks in the process.
Also, I'm going to say this now: it's important to be really careful with enforcing a set of coding standards and guidelines in a team. Yes, code should be consistent for the reasons I'm about to tell you, but the ultimate goal is not to turn your entire team into mindless monkeys who all think and act in the same way.
Well, more than they already are, at least.
No, people need space to be creative and come up with interesting and novel solutions to problems, or we'd never get anywhere at all as engineers. With that said, let's take a look at -
The Importance of Consistency
In my head - alongside a myriad of terrible startup ideas and probably too many dreams about katsu curry - is a list of what I consider to be the three key aspects of an engineering team's life that are improved by consistent code. They are as follows:
- Onboarding;
- Maintainability; and
- Debugging
How you weigh these things will depend on your own team's dynamic. If your team is growing fast, they're probably all pretty important, but if you have a stable product, you probably won't care as much about the first. You'll also notice that none of these points are directly related to actually writing the code that we're standardising in the first place - we'll get to that later.
Oh, and quick side note, I've actually previously released a YouTube video explaining some of the concepts in this article. You might enjoy it:
Onboarding
While reasonably self-explanatory, this point is really crucial for companies that like to move fast. The sooner you can get new engineers working productively on your product, the less time and resources you have to waste on training, and the more time and resources you can allocate to doing the thing that actually matters: delighting your customers.
When you do make your next hire, you want to make the learning curve as flat as you absolutely can. If the way code is written is consistent across your organisation, it becomes much more simple for new hires to grok what's going on and piece together the plethora of components that exist in any production codebase. Think of it like knitting a blanket (every engineer's favourite pastime, I'm sure): patterns are easier to understand, predict and extend than a random jumble of messy threads that seem to paint some picture, but you're not sure what.
Maintainability
Again, this should be fairly obvious, but I see so many companies getting this wrong. If I can go into a codebase and immediately understand the structure of the code, I'm a darn site better off than if I went into it understanding nothing.
Keeping code consistent makes it easier to read, maintain and extend the code you already have. If we always use functions and never classes, great! I know I'm not going to have to go climbing up the prototype tree to find the functionality I want to break.
Similarly, if we write our web apps in a framework like SvelteKit or Next.js and we have standardised names for certain types of variables, like req
, resp
and event
, I'm a lot less likely to have to warm up my legs to go definition jumping.
And if we have a policy of always using goto
... then I know I need to start polishing up my CV and practising my interview skills.
Debugging
Nobody likes it when things break in production. You can run as many unit, integration and end-to-end tests as you like, but you'll never truly be able to account for how stupid your users will really be. They will inevitably click a collection of buttons in exactly the right sequence to burn through the thermal compound on your server's CPU and blow up a datacentre somewhere, and when they do, you have to figure out what went wrong and how to fix it.
Let me tell you, when you're sitting there at 3am, bleary eyed from watching too much One Piece before bed, you do not want to have to be digging through unfamiliar code to find a tiny bug in some obscure part of the codebase. It's much more pleasant if you can figure out what went wrong quickly, push a fix to prod, go back to sleep and enjoy your well-earned lie-in the following morning.
You're convinced by now. I know you're on my side about this. But, in the (likely) case that the space between your ears is filled with cotton wool, let me deliver unto thee some of the pleasant side effects of the above three points.
Benefits Beyond the Boring
Note: they might still be boring.
Code review
Don't you just hate having some code submitted for review, only for it to be an unformatted, spaghetti mess? It happens. Even the best engineers have off days.
It's not ideal, though. On the bright side, if code is consistent and proper procedures are put in place to ensure it stays that way, code reviews are some of my favourite parts of development. Where else do you get to nerd out about implementation details and discuss the improvements you've made to the originally-planned architecture, totally ignoring everything your team has discussed up to this point and going off on your own, doing what you think is best but ultimately making the app way more complex than it needs to be and...
Sorry, got a little carried away there.
In all seriousness, though, code reviewers' time should not have to be wasted on menial discussions like indentation, variable/function naming or casing conventions (top tip: use snake_case
). By eliminating these conversations entirely, you can focus on the bigger picture.
Writing code
I did promise I'd get here. This bit is more about mental overhead than anything else. Again, it all comes down to things just being automatic. If a team has had proper, agreed-upon conventions drilled into them, and these are supported by automated tooling, they're likely to be able to get through tasks more quickly.
Why? Because they won't sweat the small stuff. They'll trust themselves to make the correct decisions on autopilot when programming, and will be able to direct their attention more towards the problem at hand, rather than what to name the function/class/module that forms the basis for the solution to the problem at hand. Makes sense, right?
Managing tech debt
Technical debt is like that uncle that always comes to your parties and ruins things when you're having a good time. It generally stays in the background, slowly building itself up to just come in and absolutely destroy your fun. Even the best engineering teams create technical debt - it's practically unavoidable. As you learn and improve as a team, your old code will naturally look a little forlorn compared to the shiny new stuff available.
That being said, it doesn't have to be a horrible time. I love a good gardening week (keep an eye out for a future edition of TFE discussing those...), and let me tell you, they're a lot more enjoyable when you can just get stuck in to the problems you're solving. You also get through a lot more things a lot more quickly. It's just refreshing, you know?
Now is a good time to mention that having consistent coding practices does indeed extend to processes outside of the editor, too. Consistency is the key to being in the black when it comes to your codebase's savings account. Make sure you keep on top of it. I'm watching you 👀
Team morale
I think this point is often overlooked, and I'd argue it's actually one of the most important benefits of this whole exercise. When people work together in the same way, it increases the feeling of cohesion within a team, which ultimately makes the team more effective and has a positive effect on morale.
Also, having a set of standards puts an immediate stop to many potential sources of conflict. If the 'tabs vs spaces' discussion is settled ahead of time, there's no need to fight over it!
Of course, there's no reason to fight over it anyway. Spaces are infinitely superior.
Implementation
I've rambled on enough at this point about why you need to look at ensuring everyone's code follows a standard format and standard patterns. Like every great internet guru, I'm now going to give you some vague pointers on roughly where you should look to find out about implementing them, and then I'm going to disappear.
Just kidding.
I'm not even going to do that.
Bye!
Okay, okay. I'm not that much of a jerk. There are a few things you can do to make the process of designing and adopting consistent practices easier. We'll first focus on the design part - i.e. how to come up with the guidelines you want to lay down - and then we'll discuss 'maintenance' of your practices - i.e. how to make it easy for people to stick to them, and how to think about evolving them over time.
Establishing your standards
The most important thing here is to make sure that everyone involved in the discussion (we'll talk about that in a sec) agrees to uphold the standards. Not everyone has to be happy with every decision, but everyone does have to promise to follow the guidelines that come out of the meeting.
So, how do you actually design your programming guidelines?
1. Involve the whole team
Yep, that's right. If you're at a small company, this is pretty easy. Get everyone in a room around a whiteboard and just hash these out. At a larger organisation, do the same with a virtual room! Using breakout room functionality in online meeting software like Google Meet or Zoom will help a tonne here. Each group should elect a leader to report the group's opinions back to the wider team later.
Seems like a faff, but this way, everyone becomes an owner of the standards. The extra work will foster a commitment to the standards. People are more likely to stick to something they helped create, after all.
2. Use existing standards
You don't have to start from scratch! Others may have done some of the hard work before you, and you can choose to adopt that instead of having to go through and create your own entirely unique set of standards.
There might be language- or framework-specific recommendations or guidelines you can incorporate into your mode of operation going forwards. One good example is the numpydoc
standard for Python docstrings. It's commonly-used, which means plenty of effort has gone into supporting the standard. Which brings me nicely onto my next point:
3. Consider tool support
Where you can, try to adopt practices that you can easily automate the checking for. This doesn't just mean code formatting and menial tasks like that. Plenty of linters have huge plugin ecosystems for just about anything. If there's no tooling that suits your exact use case, check to see if there are existing tools you can extend to suit your use case.
For example, you might choose to write a simple eslint
, prettier
or vite
plugin to enforce certain variable names in your React codebase.
Automated tooling
And talking about tooling, that's actually my next recommendation. Where you can, having automated processes fix or flag issues will save a tonne of headaches. I know I probably don't need to evangelise too hard here, but a good set of CI jobs can really save a tonne of code review headaches.
Where possible, try to integrate these checks into your team's local workflow too. There are some excellent tools for setting up Git pre-commit hooks. These will run before each commit to ensure your code is up to scratch before it even makes it to the remote.
Common examples are pre-commit
, which has great support for most languages, and is easily extensible, or Husky for those committed to the JavaScript ecosystem.
Educating the masses
It's all well and good having a load of people in a room decide how the company's code is going to look for the foreseeable future, but what about new people who come into the company? And, unfortunately, people aren't perfect. As time goes on, standards will slip as people lose the excitement they felt when drafting the guidelines.
So how do we stop that from happening? Education, obviously! I don't mean lots of boring lectures, but it's important to remind people of the standards both more formally on a regular basis, and continually through good teamwork and spokespeople.
1. Document everything
Hopefully you've already done this, but everything you decide upon should be written down somewhere. And it needs to be accessible. Pin it to your darn wall if you have to.
It's also worth documenting (separately, in an appendix or something) the choices you chose not to make. All too often I wish past Isaac had written down the rationale behind picking one thing over another. Documentation is an easy thing to let slide though, so be vigilant!
2. Interactive workshops
Standards workshops are boring. That's pretty universal. So, don't do them! Instead, incorporate guideline reminders into other useful workshops that you should probably be doing. I'm talking about things like interactive code review workshops, management training and anywhere else you can.
3. Pair programming
Encourage pair programming in your organisation where possible. And I don't just mean the "I need help with this" kind of pair programming that occurs once every so often - have dedicated sessions where the team takes half a morning to help someone else with their problem.
Not only is this hugely beneficial from a technical perspective, it's also a great way for teams to have a wider overview of the business. Sure, you can learn what your team is doing from a stand up in the morning, but you can't truly appreciate what they're accomplishing from a 30 second summary.
Set goals for these pair programming sessions. Aim for both people to have come out of it having learned at least one thing, especially if the engineers taking part are of different seniorities. People can always learn from each other, and eventually, the standards will be discussed.
The Walls in the Way
As with any sort of change to how your team works, there are going to be some challenges with implementing a new set of standards. Not only are you changing how your team works (hopefully for the better), but you're potentially going to have to introduce some new processes to keep on top of things.
One big thing to remember is that, while you shouldn't be changing them too often, these standards should never be considered immutable. Over time, the code style in your team may change as better ways of achieving results are discovered.
Ultimately, your programming practices are there to make things easier and more productive for your team. It's natural that they will evolve. Just make sure you document any changes you make, and ensure they're properly communicated to the team.
It can be useful to have regular, but infrequent, review sessions. Get some of your team together to discuss the standards and make any updates. If you're a small company, this should once again include everyone, but I understand it's difficult for larger organisations to get everyone together regularly.
For those, I'd recommend having somewhere people can leave suggestions and have a regular meeting to review those. The meeting should be open to all, but ideally optional to most.
Also, be careful with being too strict! It can actually be destructive, leading to arguments and lots of wasted time. While people should adhere to your standards as much as possible, being too anal about small things is not productive. Again, it's probably the sort of thing that should be covered by a lint rule anyway.
Finally, there's going to be an adjustment period! Give your team some time and space to figure out the changes. It might be worth assigning one or a few people to making sure the transition goes as smoothly as possible. If you have a specific team who worries about automated tooling etc., it's probably them. If not, pick the most passionate person!
In Summary
TL;DR: come up with some guidelines, automate the heck out of them, and make sure people can access them easily and are reminded of them frequently. Then you'll be golden.
I hope at least one person found this useful, and if you've managed to get to the end of this monstrous piece, congrats! You're probably the first.
Anyway, enjoy the rest of your day, and I'll see you in the next issue of The Founding Engineer, whenever that is.
Love y'all,
Isaac