How to Improve C++ Code Quality

Amir Kirsh
Amir Kirsh reading time: 11 minutes
December 13, 2021

High-quality code is code that’s nicely formatted, easy to read, simple to understand, properly tested, free of bugs, and well documented. There are plenty of advantages to having high-quality code, and it pays to make the effort. There are tips and tricks for writing and maintaining good code, along with myriad tools to assist with quality-improving tasks such as refactoring.

Code quality is a concern for developers at all levels and in every programming language, but in this article, we’ll be focusing on C++. As an experienced C++ developer, you already know that it’s a mature language with a large codebase that dates back more than 30 years in some cases. Perhaps you are looking into how to modernize legacy C++ code, or maybe you want to maximize project flexibility and scalability moving forward. In either case, C++ quality is something that deserves your attention.

Definition of C++ Code Quality and What it Looks Like

Code quality is a generic term that refers to code clarity, reliability, maintainability, and extensibility. It applies to code and programmers in any language, but there are specific aspects of C++ that are worthy of specific mention.

Throughout this post, and usually, when code quality is discussed, we assume the correct functionality of the code – that is, the code works as expected, passes all functional tests, has no seen bugs (but may have hidden bugs, especially if its quality is not high) and there is no external insight for any issues or defects.

Why does C++ Code quality Matter?

With the constant pressure of deadlines and speeding time to release, a programmer might ask whether the extra step to write high-quality code is a responsible use of time.

Code quality is a required virtue for any environment and with any software programming language, say Java or Python, but particularly for C++.

C++ is a complex language, and it’s not just us that say it. That’s why it’s so important to keep code quality: to make the code easier to read and maintain and less bug-prone.

Experienced developers that have had to take over projects, maintain other people’s code, and add new features to old projects, know all too well that good code quality paves the way for efficient development and lowers the chances for introducing new bugs into the code. In fact, it is safe to say that poor-quality code is more bug-prone and has a very limited lifetime. Either it is improved or it can’t be maintained. Unfortunately, as important as it is, code quality is often overlooked or given a much lower priority than it deserves.

c++ under the hood

Making a Team Effort

High-quality code is more easily read and understood by different developers. Consistency and well-named variables, for example, make it easier for new developers to follow the execution path and add related functionality. Proper code comments and documentation help explain not just the overall functionality, but why certain choices were made. Good comments hint at what side-effects may arise when things are changed. There’s no doubt about it: good code quality makes for good communication between programmers.

Improved User Experience

Given that applications are assumed to work correctly, how is it that high-quality code can improve user experience? The answer is feedback. For example, many well-written programs will detect errors and react accordingly. However, high-quality code will display and log a detailed error message, regardless of how unlikely the situation may be, so it can be properly identified. Conversely, cryptic error messages are a good way to leave end-users confused and unsure of what they did wrong.

Stability and Sustainability

High-quality code is robust, which means that minor changes to the codebase, or even the environment, will not break it or drastically affect its application. Consider for example a system that handles a fixed size number of elements, and this number changes in a future version. A stable system might use a named variable that refers to the size, whereas a brittle implementation might use an unnamed magic number as a constant appearing several times throughout the code. It will work well until the number is later changed, and the new developer neglects to update every instance of it. Although this scenario reads trivially, bugs of this nature are actually quite common.

Code Reuse and Interchangeable Parts

Better code quality implies more readable code, and often this is because it is modular, portable, and follows the single-responsibility principle (SRP). With C++ and object-oriented languages in particular, following the SOLID principles helps ensure quality code that is reusable and can be easily incorporated into other systems.

How does Poor Code Quality Relate to Technical Debt?

Technical debt is the term used to describe the cost of reworking a solution in the future, specifically because a simpler approach was chosen to save time at an earlier stage. Choosing a better solution takes longer during the original implementation, but results in less technical debt.

High-quality, well-written code doesn’t just make it easier to read and maintain; specifically for when mitigating technical debt, quality code improves stability and leads to fewer bugs. Moreover, errors will be easier to trace, identify, and resolve.

Code Quality Metrics

Code quality metrics are generated by a series of checks to calculate an objective score of how good a section of code is, in terms of quality. Code metrics are either quantitative or qualitative, both of which are important factors to consider when assessing quality in general.

Quantitative metrics are ones that you can measure by using a specific formula, such as the number of lines of code, or more specifically, the lines of executable code. More complex aspects can also be determined, for example, Halstead Complexity Measures and Cyclomatic Complexity.

Qualitative metrics measure code quality beyond clear-cut numbers. This makes them more difficult to measure and in many cases, subjective. Examples of this are measures of maintainability and clarity, which are based on features such as code formatting and the use of good variable names. Some metrics, perhaps those related to efficiency, will be considerably different depending on the environment, whereas a metric to judge how well documented a block of source code is, are similar regardless of platform.

There are several tools available for automatically calculating code metrics. For example, Visual Studio has specific functionality built into the IDE for calculating several code quality metrics. For a standalone application that supports several languages, including C++, SourceMonitor is a known freeware utility (though unfortunately, its author announced retiring after 20 years of maintaining this utility).

How to Improve C++ Code Quality

Code quality should not be too time-consuming, and ideally, it should not be a dedicated task. Rather, the quality of one’s code should be considered throughout development and improved when opportunities present themselves. The point is that code quality can be improved after the fact but, most importantly, it should also be considered with best practices in place during every stage of development.

Follow a Coding Standard

The first tip we have for improving code quality is to follow a coding standard. Maintaining and following a set of standards is important in any industry, and software development is no exception. Coding standards improve consistency, minimize complexity, promote efficiency by eliminating the need to get into other peoples’ mind, make it easier to fix bugs, and make code simpler to maintain.

There are many valid coding conventions for C++, such as those promoted by Google, but mixing them within a single project can be confusing for developers and lead to errors.

For example, if two different teams working on the same project use different styles, such as East const versus const West, it can be very confusing. At best, it will slow down development, and at worst, it will lead to errors. Ensuring that everybody is working with the same convention will facilitate collaborative work efforts, create a better team foundation, and ultimately lead to superior products.

Follow Best Practices

Generally, best practices are procedures followed by individuals and organizations that are deemed to be correct and the most effective for the circumstances. In the context of C++ development, this consists of following a coding standard and aligning developers to coding conventions. Best practices can be global or at the organizational level. A good example is C++ Core Guidelines, which is an effort led by the C++ community and actively led by C++’s creator, Bjarne Stroustrup.

Code Comments

Including meaningful, concise, and relevant code comments is an important part of coding and is indeed a topic on its own. The key to commenting is that the additions should make code more readable, not more confusing. In practice, if a comment can’t be made succinctly then it may indicate a problem in the code. Along the same vein, just because code comments are good, doesn’t mean the code is good.

It is important for comments to accurately describe the current code state rather than old versions of it. When bugs are fixed or code is changed, comments should be updated accordingly. Again, comments need to accurately and concisely clarify what is happening in the code, with implementation decisions and details that are not clear from the code itself, keeping in mind the target audience as your fellow programmer.

For more information on code commenting, see this article by Ellen Spertus, and check out some other important pointers by Jeff Atwood from Stack Overflow.

Refactoring

Code refactoring is the process of making changes to code to make it more efficient, readable, maintainable, and extensible, all without changing its basic functionality. Sometimes it’s as simple as wrapping a set of variables into a new class to make that code more concise and encapsulated; other times it might be a complex process that involves large parts of your codebase, especially when a refactor is needed for the addition of new functionality.

In the context of C++ code quality, refactoring should keep code improvement in mind so it would be easier to read and maintain but also harder to introduce new bugs. It should be easier to pinpoint bugs (e.g. by adding asserts, logging and pre-conditions in places where previous bugs were found) and facilitate code reuse.

Code Reviews

A code review is a process in which fellow developers systematically check each others’ code. This can be done by people in a supervisory role or by peers of the same level.

The goals of a code review include validating the program design, ensuring that all of the features have been implemented, and enforcing best practices that include coding style and convention. For instance, code reviews will help to identify areas that can be optimized, such as making the code more generic, using templates, improving an algorithm, or introducing a certain software pattern.

Static Code Analysis

Static code analysis is an approach used to assess the quality of code automatic analysis, without actually running it. In fact, this step is often done before code review and can pinpoint errors related to security, vulnerabilities, and general defects. These are things that can be uncovered by manual code reviews (described earlier), but static code analysis tools speed up the process and automatically consider things in greater depth. For example, a manual code review may not follow all relevant possible execution paths, whereas a static code analyzer may do a much better job in following execution paths across function calls.

There are some obvious limitations: It cannot, for example, determine whether the functionality is as expected because it cannot verify intent. Furthermore, if something is not statically enforceable, perhaps because the rule is subjective in nature, then the approach will not be of any assistance. For a look at some of the advantages and disadvantages of different tools, check out this comparison of C++ static code analysis tools.

The use of static code analysis tools would improve code quality, as it can identify potential bugs, even if they do not actually occur in current tested use cases. For example, something as simple as a variable type that has changed over time can lead to subtle semantic errors. Consider the following code:

Example of static code analysis

bool Ball::roll(int& direction) {
  // ...
  if(direction < 0)
    direction = -direction;
  // ...
}

Assume that this code works as expected and without side effects. Imagine, however, that through the course of development, the direction variable is changed to type std::size_t after being ported to another platform. The updated code is as follows:

bool Ball::roll(std::size_t& direction) {
  // ...
  if(direction < 0)
    direction = -direction;
  // ...
}

The problem here is that size_t is unsigned and the value will never be less than zero, meaning that the assignment code is unreachable. It may be the case that rolling the ball in reverse, specified by using a negative direction, is not supported anymore (if one expects to get a warning on that very simple error, well it certainly relates to the warning level you use; checking it in GCC with -Wextra you do get a warning, however, Clang refuses to issue a warning even with -Wextra -Wsign-compare -Wabsolute-value -Wunreachable-code). A static code analyzer should be able to highlight this semantic error.

Clearly, static code analysis can be beneficial. This is a simple error that might not be caught by all compilers and may be outside the level of scrutiny for a manual code review.

Summary

C++ code quality is an important characteristic that directly translates to better code readability, maintainability, and efficiency. Having high-quality code can improve the end-user experience, promote collaboration between developers, and pave the way for the efficient future expansion of the codebase.

Many components make up code quality, including metrics to measure it, using a popular coding style and convention, and following C++ best practices.

Using automatic static code analysis tools and insisting on systematic manual code reviews for any new pull request should also be adhered to, to achieve the required code quality.

ecosystem webinar

Amir Kirsh
Amir Kirsh reading time: 11 minutes minutes December 13, 2021
December 13, 2021

Table of Contents

Related Posts

11 minutes 8 Reasons Why You Need Build Observability

Read More  

11 minutes These 4 advantages of caching are a game-changer for development projects

Read More  

11 minutes What Level of Build Observability Is Right for You?

Read More