Breaking down how a code style guide can help speed up engineering teams
Jul 11, 2022
Every developer has their own unique style and approach to writing code. Our styles come from how we’ve learned to code, our previous experiences, and a bit of our own personalities. But, we also need to consistently work as in teams and often in large and complex organizations. This means dozens, or hundreds, or thousands of unique coding styles working together and potentially clashing in a single codebase.
If your team is all working with different approaches, different styles, and different preferences this can start to create problems. In order to operate effectively as a team, you need to be able to unify these divergent approaches so that all of the code you’re dealing with is relatively easy to understand, easy to extend, less prone to bugs, and more maintainable.
Most teams already have systems in place to help standardize their code - typically informal rules and standards emerging during code reviews within smaller teams. But, as teams and complexity grow, these informal best practices aren't enough and you need a more explicit approach. At Google, they’ve explicitly laid out their approach to creating consistent Python code for their open source projects in their Python Style Guide.
Let’s take a look at what the Google Style Guide is, how they’ve structured their rules and guidelines, and what different engineering teams can learn from it. And then we’ll quickly take a look at how you can build your own style guide and best practices into code with Sourcery.
Before we dive too much into the Style Guide itself, I want to call out a quick difference between what counts as Style and what counts as Formatting. There is some overlap between them, but as a general rule of thumb, Formatting is specifically focused to the aesthetic aspects of code - ranging from line length, to spacing, to use of quotes and brackets, etc. A Style guide may include some of these elements (eg in the Google Style Guide, large pieces of section 3 are focused on Formatting elements), but is primarily focused on the more structural aspects of your code as we’ll discuss below.
For handling Formatting issues there are several great Python Formatting tools including:
Google’s Style Guide is made up of more than 40 sets of “do’s and don’ts” for use within Python and is broken into two key sections - Python Language Rules & Python Style Rules. Broadly speaking the Language Rules are used to define how Google approaches using (and importantly not using) and structuring different elements of the Python language within their code. This is a critically important aspect to a Style Guide for teams that have different levels of experience in a given language, because it helps provide guide rails around the code structure and on what type of advanced language feature your team should and shouldn’t use.
For example - section 2.19 says you should not use any Python Power Features while 2.10 says you can sparingly use Lambda Functions (provided that they’re relatively short).
Section 2.19 - Google’s Python Language Rules explaining why not to use Power Features
The Style Rules section is more focused on formatting and stylistic practices that the code should follow - ranging from section 3.2 focused on line length to section 3.16 focused on naming practices.
Section 3.2 - Google’s Python Style Rules setting guidance on Line length
Across both sections of the style guide there are three main reasons or classes of recommendations:
Like most style guides, the Google Style Guide creates two types of recommendations for approach when coding - rules for how to structure your code and guidelines for how to structure your code. A rule is an explicit mandate around how to structure your code with minimal if any exceptions, while a guideline is a strong suggestion which may have exceptions.
Having a blend of rules & guidelines within a style guide is important because there are aspects of code structure which could potentially lead to huge headaches if there is variation. But for most recommendations, it’s useful to give your team leeway to move outside of them in specific situations. Otherwise, if everything is a strict rule, then there may not be enough flexibility for your team to operate and it can lead to frustration.
Section 3.1 - recommendations around semicolon are examples of explicit rules
Section 3.18 - recommendations around function length is an example of a guideline that gives broad suggestions for length, but leaves flexibility for individual functions.
The Google Style Guide only has a few recommendations that would fall into the “avoiding danger” category and they tackle a blend of areas. They are primarily around preventing bugs from being introduced, but section 3.8.2 also introduces some interesting rules around licensing and IP requirements, which can be critical standards within open source projects.
2.5 Global Variable [Guideline]
While not fully banned, Global Variables are strongly discouraged from being used because of their risk to changing module behaviour during their import. This is a prime example of a recommendation in a style guide being used to discourage a style of coding that could significantly increase the bug risk in the project.
2.12 Default Argument Values [Guideline]
Putting in place simple guide-rails (but not blanket bans) throughout the style guide can help to reduce the risk of critical errors. It’s ok to use default argument values, as long as you’re not using mutable objects as default values.
This is another section of the style guide designed to limit bug risk, but rather than creating a requirement because the primary use case is a risk, Google has a rule not to assume the atomicity of built in types because of the risks around edge cases.
2.20 Modern Python: from future imports [Guideline]
Many of Google’s open source projects need to be compatible with a wide variety
of Python versions. They recommend using from **future** import
statements to
help make runtime version transitions smoother. This recommendation is probably
somewhat between “Avoid Danger” and “Enforcing Best Practices” as it both helps
with reducing the risk of potential bugs and is reinforcing a best practice
around using new functionality.
3.8.2 Modules [Rule & Guideline]
Critical requirements in a Style Guide don’t just relate to how the code needs to be structured, but also can relate to business requirements, IP requirements, and managing security/reputational risk. As part of the broader Comments and Docstrings section of the Style Guide, Google lays out a clear requirement for every module to include a license boilerplate.
3.11 Files, Sockets, and similar Stateful Resources [Rule]
Beyond bug risk and business risk, another important parameter to consider in your Style Guide is ensuring best practices around code performance. Here, Google requires explicitly closing files and sockets (and other similarly closable resources) when finished using them to make sure you don’t inadvertently eat up resources.
Both for testing and automatic documentation, the Google Style Guide requires
that all the functionality of an executable file live within a main()
function
and that the code always check if if **name** == '**main**'
before executing
the code. This carries over an important aspect raised in 2.5 that you should
not be executing code directly on import.
If you require or recommend that your team use certain tools or linters it is useful to explicitly outline that in your style guide. Here Google lays out the recommendations (and limitations) for using Pylint.
We all rely on imports (both internal and external) frequently and having inconsistent approaches to handling import structures can lead to confusion and make it more likely that we introduce bugs into our code in the future. Google lays out explicit requirements for how to import modules and packages and in which limited situations you can import a module as an alias.
Similar to the above rule, the Google Style Guide also has explicit rules for how to import packages clearly. In order to eliminate confusion, they require that you import each module by the full package name.
Defining how you handle cases around exceptions, errors, and logging are all important aspects to a style guide because inconsistency here can very quickly lead to your code becoming overly complicated and tricky to understand. Here Google has laid out a series of explicit conditions that exceptions need to follow.
2.6 Nested/Local/Inner Classes and Functions [Guideline]
Nesting functions can cause serious issues for code readability, but there are also use cases where they can be quite useful. This recommendation is an interesting example of how it can be important in a style guide to take a neutral position on issues, because it eliminates debate around whether you should or should not be always doing something. In this case - it is at the developer’s discretion for when to use nested local functions or classes, with a few explicit exceptions where they are discouraged.
2.7 Comprehensions & Generator Expressions [Guideline]
This recommendation helps create very explicit guidelines of when comprehension or generator expressions are ok to use - they need to be simple cases and need to fit in one line, otherwise they should not be used.
2.8 Default Iterators and Operators [Guideline]
I mentioned earlier that one key piece of a style guide is which built in features of a language you should leverage and which you should avoid. When it comes to default iterators and operators for supported types, the Style Guide strongly recommends that you use them because of their simplicity and efficiency.
Similar to the above rule, the Google Style Guide encourages the use of generators because they give simpler code.
2.10 Lambda Functions [Guideline]
As with nested functions, the Google Style Guide says it’s ok to use lambdas, but only in specific situations and doesn’t necessarily encourage their use. It suggests that anything that is longer than one line is a bad use case for a lambda.
2.11 Conditional Expressions [Guideline]
Throughout the Google Style Guide a fairly consistent theme exists. You should use Python functionality that helps to make your code shorter and more convenient for simple, one line use cases, but probably not for more complex situations. The same holds true for conditional expressions.
Like the above few recommendations, the guidelines around Properties are focused on making sure that they are not used in cases where they would make things significantly too complex (eg where they wouldn’t match the expectations of typical attribute access and not implementing your own property descriptor). But, like the above recommendations, they don’t discourage the overall use of properties
2.14 True/False Evaluations [Guideline]
All of the sections of the Python Language Rules have a Pros and Cons section around why you may or may not want to use a given feature of the language - and this recommendation might have my favorite con - “May look strange to C/C++ developers”. Overall they recommend using the “implicit” false in Python wherever possible, but the con they lay out is an important one to think about when you’re structuring your own style guide. Make sure you consider who is going to be contributing to your codebase and what their backgrounds are and how that might influence how you should structure your best practices.
2.16 Lexical Scoping [Guideline]
Compared with some of the previous recommendations which had heavy caveats, this one is relatively straightforward - it is ok to use lexical scoping.
2.17 Function & Method Decorators [Guideline]
Rather than spending much of the section focus on whether or not to use decorators (it says they’re ok to use judiciously), most of this section of the Style Guide focuses on how to handle decorators when you are using them - especially on how they fit into other guidelines within the Style Guide.
Within Google there are thousands of developers writing code in a variety of languages and they have different levels of expertise and comfort with Python. Here, developers are explicitly told not to use “Power Features” of Python because they can be difficult to understand for developers who a) aren’t familiar with them or b) are revisiting the code later. When you’re building your own style guide it’s important to consider what variation in experience you will have within your team and what types of features you want your team using.
2.21 Type Annotated Code [Guideline]
Interestingly, type annotation is a topic that’s covered in two separate sections of the Style Guide - here in the Python Language Rules section and again in the Python Style Rules section. This piece of the guide is relatively straightforward, simply stating that type annotation and type checking is strongly encouraged.
3.15 Getters & Setters [Guideline]
This is another section that encourages the general use of certain type of functionality in your code - in this case getter and setter functions - but only where the access is complex (not more broadly).
I won’t go into as much detail on some of the consistency points and why they’re useful as I have for the previous sections, because many of the more formatting focused recommendations are relatively straightforward.
Don’t terminate lines with semicolons or use semicolons to have 2 statements on the same line.
With a few exceptions, the max line length should be 80 characters.
In general you should use parentheses sparingly
Use 4 spaces for indentation.
Have 2 blank lines between top level definitions, 1 blank line between method
definitions and the class line and first method, and 0 blank lines after a def
line.
Here the Google Style Guide lists a series of restrictions on when there should not be whitespace.
Only include the relevant shebang line (#!/usr/bin/env python3
(to support
virtualenvs) or #!/usr/bin/python3
) on files that are going to be executed
directly
3.8 Comments and Docstrings [Guideline] (see 3.8.2 Modules under Recommendations to Avoid Danger)
Structuring comments and docstrings consistently are important to driving the overall consistency and readability of a project. Here the Google Style Guide goes into detail on the formatting and structure of how to approach docstrings for a variety of cases, comments.
Inconsistency around string formatting can quickly make code cluttered and a pain to try to read through. In this section, the Google Style Guide sets out clear guidance around consistency of structuring strings (both long and short strings and f strings) and lays out clear guidance around how to structure and format logging and error messages.
An important piece of managing a complex codebase is thinking about how you manage known issues or known future improvements. Here is an explicit definition of how you should use TODO comments - especially who is referenced in the TODO and what that means.
3.13 Imports formatting [Guideline]
In section 2.2 there is a series of clear recommendations as to how to handle imports and how to structure them. This is instead focused on import formatting and sets definitions that imports should be defined on separate lines, that imports should be at the top of files, and that they should go from generic to specific.
Similar to the last several recommendations, this section is focused specifically on formatting and structuring your code so that you only have a single statement on a given line.
Names are hard. And inconsistent naming can create havoc within a project. That’s one of the reasons I really like this section of the Google Style Guide. It outlines what types of names to avoid (single character names, offensive terms, specific characters to avoid, etc), gives naming conventions to ensure consistency, and gives guidelines for naming different aspects of your code.
3.18 Function Length [Guideline]
You could create a wide variety of recommendations in your style guide around code quality requirements (eg length, complexity, working memory, etc.). Here, Google lays out a suggested limit to function length (40 characters) but also recognizes that there are exceptions where you may need to violate that. I like this approach of giving a strong suggestion, but not making it a strict rule for any code quality based section of a style guide.
3.19 Type Annotations [Guideline]
Not to be confused with 2.21 Type Annotated Code, this section sets out a series of guidelines around how to annotate your code and some broad guidelines on when and when not to annotate your code
Google has tens of thousands of software engineers on their team - so you might be thinking that having an explicit style guide is clearly good for a company with that level of complexity, but doesn’t make sense for smaller organisations. But, regardless of company or team size, the same truth is going to hold - the time spent reading, interacting with, and maintaining a section of code is going to be orders of magnitude more than the amount of time that you’re going to be spending writing it. This means that any gains your team gets from initial speed in writing your code in whatever way works best for each individual quickly gets eaten up by the long term costs of dealing with those clashing approaches.
If your team doesn’t already have a set of explicit (or consistent, but implicit) code standards, best practices, and/or guidelines that you are following then the Google Style Guide is a great jumping off point. Look at the full set of recommendations and see which fit well into your team’s approach, and then remove or add in any rules that would be more relevant for your team. Remember, there isn’t an objective set of right and wrong recommendations to have in your team’s Style Guide, it’s more important that your team is all going off the same playbook and it is helping your code become more consistent and effective.
Turn your team’s best practices and style guide into code → Get a Demo