Coding conventions are a necessity on development teams, but unfortunately they are often overlooked. These conventions serve multiple purposes for a team. They foster a consistency in the code which has a positive effect on the overall code quality and enable teams to bring new developers up to speed quickly. This code consistency also makes future development and maintenance significantly easier. Furthermore, the conventions provide a mechanism to determine team rules for building the software that go beyond just stylistic decisions and affect the design quality. These types of rules have a large impact on the quality of the code but also provide one of the first opportunities for a team to find its values and identity.
If you are part of a new development team, one of your primary focuses should be developing your team’s coding conventions. If you are part of an existing team working without coding conventions, you have catch up work to do and I imagine the codebase you work in reflects this. Creating coding conventions should be an immediate priority. Operating with an agreed upon set of coding standards addresses a lot of issues that commonly arise in development organizations. Too often teams are too busy rushing to meet self-imposed deadlines to slow down and build a set of development standards and practices to improve the way they work. However, it is important to remember that short-term pressure to go faster has the effect of making the entire organization slower over the long-term.
Style Guides
The goal of adopting a single style is that the code reflects a certain professionalism. It looks like it could have been written by a single developer in a single sitting. When the team commits to this single style it provides several benefits, including making them more productive and able to spot and avoid bugs.
I recommend that the first thing you do when coming up with coding conventions is adopt an existing style guide. This can help avoid a lot of discussions about the truly subjective parts of software development. Remember for style standards, consistency is favored over any single approach. So if you prefer tabs to spaces, two spaces over four for tabstops, or a K&R style variant for curly braces, be flexible in the spirit of quickly coming to a consensus. Adopting a known style also has the benefit of having preset configuration options in IDEs and enforcement in linters and other static analysis tools.
The one style rule that I would include in my coding conventions document and not leave up to the style guide is variable naming. Primarily this is because older style guides may still use variable name encoding to convey the type and scope of variables. This goes beyond just style and affects the readability of the source code.
Coding Standards
Once the team has agreed upon coding styles they should then shift their focus to coding standards. Here the team should focus on coming up with very specific rules about how the code is structured. Consider, but don’t limit yourself to, things that could easily be verified via a static analysis tool. These could include lines of code per class, lines of code per function/method, number of dependencies per class, etc. I would also come up with rules around the organization and development of unit tests since production code and unit test code shouldn’t always adhere to the same rules.
But Aren’t These Rules Arbitrary?
One argument that often arises when very specific coding rules are discussed is, “Aren’t these rules arbitrary? Why is a class with 100 lines okay but a class of 101 lines not okay?” The intent of arguments like this is usually to dismiss the validity of these types of rules for a development team. My response is that the rules are supposed to be arbitrary, that is the point of them. There is nothing inherently better about 100 lines of code versus 101 lines of code for a class. It’s about drawing a line in the sand and saying we favor small classes over large classes so this is the line that we will not cross as a team. Sandi Metz addresses these types of rules in her talk, Rules that she gave at Baruco 2013.
How to Break the Rules
In her talk Sandi Metz makes the following recommendation about breaking these rules once they are agreed upon: Any rule in your coding conventions can be broken if you can convince another developer on your team that it is the right thing to do. Preferably this would be someone you are pairing with on the problem. I usually document this in the coding conventions so it is understood that the intent of the rules is not to follow them blindly and that software development always involves trade-offs. In some situations breaking a team rule is the best decision given all of the alternatives. However, they should only be broken after very careful consideration.
Keep it Simple
It is important to keep this document very approachable so everyone on the team can have these rules committed to memory. Start out small with just style and coding rules. If an IDE can enforce the style via settings those style rules don’t even need to be documented other than maybe a link to an online style guide that has been adopted. As your team works together you will know if the coding conventions are too light and additional content must be added.
Other Things to Consider
There are several other things to consider documenting in your coding conventions if you feel that they are necessary.
Third-Party Libraries and Frameworks
If your team adopts several third-party libraries to address identical or even similar problems, consider adding agreed upon libraries to your coding conventions document. This can be used as the rationale to reject code reviews that add additional third-party libraries in favor of the agreed upon libraries.
Rule Rationale
Consider adding rationale for rules if there may be disagreement on the team. This allows the document to serve as an educational tool in your organization and will help new developers who join your team. It helps to add links to articles that explain the rationale in more detail.
Reference Implementations
If specific rules can benefit from further clarification consider linking to a reference piece of code. It could either be an open source example or better yet an implementation within your own codebase.
Make the Conventions Visible
Once you have the initial version of the coding conventions post them in area that is visible to the entire organization like a team website or blog and commit them to your VCS. Ensure that every new hire knows what they are and why they are important to the team.
Why is This So Important?
I do hear some developers grumble over coding conventions. They’ll say things like “We shouldn’t need a document to dictate how we work together” or “We have bigger problems that coding conventions can’t solve.” If you don’t see the value in coding standards I would again recommend watching Sandi Metz’s talk I referenced earlier, Rules. She makes a fantastic case for why rules on development teams are so important.
As I pointed out in one of my previous posts, Creating a Great Development Culture, teams who develop without a consistent coding standard will slow down. Bringing new developers up to speed on the team will take much longer due to the huge learning curve required to understand code that looks like it was written by teams of developers who never talked with each other let alone worked together. Furthermore, having to come up to speed on a large number of third-party tools and libraries slows new and seasoned developers down alike. Teams in these situations tend to add more developers in an attempt to go faster which exacerbates the problem as there are now even more developers working without a common set of conventions.
The coding conventions can serve as tools to help locate problem areas of the code and even avoid potential bugs. Furthermore, coming up with these rules helps to surface what the team’s values are. And a team without a set of shared values isn’t a team. It is vitally important to share a set development values and make them known throughout the organization. Preferably by documenting these values as well.
Example
In the following example you’ll see one of the coding conventions I recently wrote for a team I worked on.
Coding Conventions
Code
Classes should be small (Less than 100 LOCs)
Methods should be small (Less than 10 LOCs)
Why? Small classes and small methods encourage the Single Responsibility Principle (SRP) and separation of concerns. They are easier to test than large ones. They provide error localization that makes test failures and the functionality under test obvious. They are simpler to understand and edit because they are focused.
Methods should have a very small number of parameters (3 or fewer parameters)
Why? Methods with less inputs are easier to test. Every combination of each input is required to fully test a method. A lot of parameters is an indicator that the method is doing too many things.
Class dependencies should be injected following the Inversion of Control (IOC) principle.
Why? Dependencies injected can be replaced with test doubles for testing in isolation if necessary
A class should only contain a small number of dependencies (3 or fewer dependencies)
Why? More than a few dependencies is a sign that the object is doing too many things and most likely violoating the SRP. More dependencies makes the code difficult to test. Less dependencies encourages more focused code and encourages separation of concerns.
Constructors should not contain any logic. They should only set dependencies and initialize the object.
Why? Doing work in the constructor among other things, makes it very difficult to create an instance of the object in a test harness. See this for more info: The Bloated Constructor
Use of static classes and public static functions should be reserved only for helper methods
Why? Static functions prevent you from creating seams in the object to allow for testability. The result is large and brittle integration tests. Additionally, OO patterns to remove duplication cannot be applied to them. See these for more info: Statics are a death to testability also When To Use Static Classes in C#
Favor composition over inheritance. Inheritance is acceptable if part of a well-known design pattern (e.g., template method). If using inheritance the hierarchy should be shallow (Hierarchies should be no deeper than 3)
Why? Large inheritance hierarchies are harder to test, harder to understand the flow of execution and the consequences of code changes.
Variable name encoding should be avoided in favor of descriptive names. Characters should not be used to indicate variable scope or type.
Why? Encoded variable names is a barrier to reading and understanding the code. There is an extra mental hurdle to understand the encoding. Typically in modern languages using variable names to indicate the scope of the variable is an indicator that your methods and classes are too large. In small classes and methods variable scope is obvious.
Law of Demeter violations are only acceptable for data structures (e.g., view models, object representations of XML or JSON, etc.). Any classes with logic cannot contain Law of Demeter violations.
Comments
Comments should be avoided in favor of descriptive method and variable names
Summary / XMLDoc comments should not be used unless they are documenting an externally facing API
Why? Comments violate the DRY principle and are often not updated when the code is updated. Files with large amounts of comments add a significant amount of noise and obscure the intent and important information in the code. We prefer an effort on meaningful names over comment creation.
Region comments should be avoided
Why? Classes that require regions are typically too large. If a class can be broken in to parts by region typically those are seams for new classes. Region and Summary comments are noise in the codebase that obscures the intent of the code.
Microtesting / Unit Testing
Unit tests should be optimized for simplicity, readability, making code coverage obvious, error localization, and short execution times
No existing unit tests should be marked as ignored
Why? Ignored tests are broken windows. They provide no benefit as tests and yet still have to be updated when code changes.
Unit tests should be written for all new functionality
Why? We require an automated unit test suite to enable continuous refactoring. Further, practicing TDD yields a decoupled and cohesive software design.
Unit tests should not access the database
Unit tests should not access the filesystem
Unit tests should not interact with external services / systems
Why? These result in slow, brittle tests. Failures can occur that are unrelated to the code under test.
Unit tests should be small (~12 LOC)
Why? Unit tests should test one thing (usually this means one method). Larger unit tests are harder to understand and maintain.
Unit tests should not have an inheritance hierarchy
Why? It makes unit tests harder to understand.
Unit tests should use helper classes to create common objects required for tests.
Why? The AAA model makes unit tests easier to understand and helps developers follow a pattern that makes them easier to write.
Unit tests should contain no conditional logic or loops
Why? Conditional logic requires tests. Unless you are writing unit tests for unit tests avoid loops and conditional logic.
Unit tests can use test setup methods but only if arranging is being done in the setup. No acting or asserting in test setup methods is permitted.
Avoiding the use of test setup altogether in favor of minimal test duplication is encouraged.
When to Break Convention
All of these rules are meant to be followed but at times it does make sense to break them. The only absolute rule that we have is that any of the above rules can be broken if you can convince one other person on the team that it is appropriate to break the rule given the available alternatives. Preferably this is someone you are pairing with to solve the problem.
Creating and maintaining coding conventions is an extremely important part of every development team. I strongly encourage you to find 35 minutes in your day to watch Sandi Metz’s talk from Baruco 2013 and get started on a coding conventions document for your team if you don’t already have one.