Improving Software Quality
Introduction
You now have run your own, simple, application developed for Mbed OS with Mbed Studio. Before developing a more complex application, we need to make sure that our application meets certain quality standards. This codelab aims at adding this dimension to your project so as to have sound foundations for future work.
What you’ll build
In this codelab, you will understand the required tools and guidelines for building qualitatively good software. Of course, those should be used while creating any type of software. You will also understand how to interpret the results delivered by the tools used in order to improve your work.
What you’ll learn
- How to set up the tools for ensuring certain quality standards.
- Start ensuring quality throughout the entire development lifecycle.
- Understand the different elements composing quality and how to interpret the results provided by the different analysis tools.
What you’ll need
- You need to have completed the Getting started with Mbed OS.
- You need to have started the C++ Basics and completed the related exercices.
- You need to install a number of additional software components as documented in the codelab.
- You need
python3
to be installed on your machine. In case it is not already installed, download the installer from this link. For Windows users, you may also follow these instructions.
Enforcing a common coding style: clang-format
In most cases, software is developed by many contributors. Imposing a common coding style can improve the readability and maintainability of the code of and by all contributors. Code consistency is also important for code reviews, where different contributors revise code written by others.
In this course, we will use clang-format
, which is a relatively easy-to-use
tool for enforcing a common code style for your projects written in C++.
Installation
Head to clang-format
- LLVM Download
Page, download and install the
appropriate package.
A direct link to the installer for Windows is given here. For other operating systems, you may issue the following commands:
- MacOS:
brew install clang-format
- Linux:
sudo apt install clang-format
Run a first clang-format
operation
For using clang-format
, you first need to create a configuration file named
.clang-format
at the root of your project - where you will run the
clang-format
tool. This file contains various configuration parameters such
as:
---
BasedOnStyle: Google
IndentWidth: 4
---
Language: Cpp
ColumnLimit: 90
AlignConsecutiveAssignments: true
DerivePointerAlignment: false
PointerAlignment: Left
BinPackArguments: false
BinPackParameters: false
IndentAccessModifiers: false
clang-format
are described
here.
From this documentation, you should be able to understand the options used in
the configuration file illustrated above.
For using clang-format
, you may then run the command clang-format -i
main.cpp
. In this command, -i
means that the file is edited in place. This
means that if clang-format
detects required changes in the file, it will
modify the file with the required changes. Without the -i
option,
clang-format
simply outputs the modified file on the console without modifying
the file itself.
Guideline checker: cpplint
cpplint
is a
command-line tool used for checking that C++ code follows the Google’s C++
style guide.
The guidelines cover a wide range of rules, ranging from notation to dos and dont’s for writing C++ code. The overall goal is to make the code more readable and more robust.
Whether it is a good idea to apply Google guidelines for our project is certainly a good question. At this point, it is important to apply one guideline and it is up to debate whether this is the best tool among existing ones.
Installation
You simply need to enter pip3 install cpplint
for installing the cpplint
tool on your system. Run cpplint --version
for checking that the installation
was successful.
Run a first cpplint
analysis
Before running your first analysis, you may add the file “cpplint.cfg” at the root of your code repository, with the following content:
linelength=90
filter=-build/include_subdir,-whitespace/indent,-build/namespaces,-build/c++11
cpplint
and the configuration
is applied for all files analyzed in this directories and in the
sub-directories.
To see a list of all category filters in cpplint
, you may simply type cpplint
--filter=
(with no argument). This will list all available filters. Available
options may be listed with cpplint --help
. Options may be entered in the
command line or in the “cpplint.cfg” file.
Once you created the configuration file, you may simply enter cpplint
main.cpp
. On Windows, if the tool is not found, check that it is indeed present
in your $PATH
.
Run an example that produces errors/warnings
One of the common errors detected by cpplint
for C++ programs is the use of
C-style type casts. The error is detected because in C++, one should use the C++
type cast operators rather than C-style casts (e.g. (int) value
). This makes
conversions more robust and better documented. For more details, you may read
the task of the embedded C++
lessons dedicated to the conversion
topic.
For demonstrating how cpplint
detects the issue, it is enough to add the
following code in your main()
function.
int val = 3;
float fval = val * 4.0;
val = (int) fval;
cpplint main.cpp
with the modified “main.cpp” file, you should get
the following error message:
main.cpp:21: Using C-style cast. Use static_cast<int>(...) instead [readability/casting] [4]
val = static_cast<int>(fval);
cpplint
.
Issues detected by cpplint
There may be issues flagged by cpplint
that may seem not trivial. If some
issues are not clear to you, you may:
- check Google’s Styleguide concerning the rationale of the rule
- have a look at the Styleguide Script as it may help the understanding
- disable a rule with the
--filter
option, with a clear written justification.
Copyrighting your work
No matter what software one writes, a copyright shall always be specified -
no matter whether open source or proprietary in its nature. With cpplint
, in
case you forget to apply this rule, the following error will be shown ” No
copyright message found. You should have a line: Copyright [year] <Copyright
Owner>
” in any file containing code.
An example of such copyright can be found below:
/**
******************************************************************************
* @file : monnalisa.hpp
* @brief : pensive woman module
* @author : Leonardo Da Vinci <leo@davinci.net>
* @date : 19. March 1503
******************************************************************************
* @copyright : Copyright (c) 1503
* Haute école de peinture de Florence
* @attention : SPDX-License-Identifier: MIT OR Apache-2.0
******************************************************************************
* @details
* Pensive woman module for impressing humankind
******************************************************************************
*/
Static C++ Code Analysis: cppcheck
cppcheck
is a static analysis tool for
C/C++ code. It helps to detect bugs based on pre-defined rules that may be
adapted to different needs - also for embedded software.
Static analysis means that the analysis happens on the code itself and not on a running program. It focuses on detecting code that:
- may produce undefined behavior,
- uses patterns that may be dangerous, or
- do not follow the defined coding style.
Installation
In order to install it, head to cppcheck
-
Download, download
and install the appropriate package (while ignoring Windows warning as the
installer is not signed) - make sure you install Python Addons as well.
Do not forget to add the application to your $PATH
(as the installer is
not doing it for you…).
Run a first cppcheck
analysis
For our first analysis - to ensure all works - we will make use of the blinky program written in the Getting started with Mbed OS codelab.
Run the cppcheck
tool and inspect the results. You can run the
tool for analyzing the “main.cpp” file by entering:
cppcheck main.cpp
The analysis should run smoothly and you should not get any warning.
Run an analysis that produces errors/warnings
If you add the following two lines in your main()
function:
char a[10];
a[10] = 0;
cppcheck
again, you should get the following error:
main.cpp:25:7: error: Array 'a[10]' accessed at index 10, which is out of bounds. [arrayIndexOutOfBounds]
a[10] = 0;
cppcheck
.
It is important to point out that this bug is also detected by the compiler. When compiling the modified code, you should indeed see the following warning in the compile output:
[Warning] main.cpp@25,6: array index 10 is past the end of the array (which contains 10 elements) [-Warray-bounds]
Fixing issues found by any of the tools
It is important that any fix/bug correction made to your code are done using the
proper git branch
process. For this purpose, you need to:
- Create a dedicated branch on your repository: you should create a different dedicated branch for a specific code release and you should name it accordingly.
- Fix the identified issues in this branch: no other changes should be implemented in this particular branch and in particular, implementing fixes and features should not be mixed.
- Commit your changes: add a clear commit message for each specific change implemented in this branch. Remember that small commits are usually better than larger ones. So, you should commit one change at a time and not all changes at once.
Putting all together: pre-commit
You are now capable of checking your code and of implementing fixes to it by
following the proper git
guidelines. We still need to make sure that any
change in the code goes through the entire continuous checking pipeline. How
can one ensure this?
One way would be to check it centrally using a CI/CD pipeline on a git
repository, but that would be late (and consume energy for nothing).
One probably better approach is to use pre-commit
, that does exactly what its name
implies. pre-commit
allows to run a serie of checks prior to committing.
Installation
In order to install it, head to https://pre-commit.com/ and follow the instructions.
Using it
So, once installed, we add all the tools seen so far in the pre-commit phase by following these instructions:
- create a “.pre-commit-config.yaml” file at the root of your
git
project with the following content:
files: ^main.cpp
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: check-yaml
args: [--allow-multiple-documents]
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: 'v14.0.6'
hooks:
- id: clang-format
- repo: https://github.com/cpplint/cpplint
rev: '1.6.1'
hooks:
- id: cpplint
- repo: local
hooks:
- id: cppcheck
name: cppcheck
require_serial: true
entry: cppcheck --enable=all --suppress=missingInclude:* --inline-suppr -i mbed-os --std=c++14 --error-exitcode=1
language: system
- add
.pre-commit-config.yaml
to yourgit
repository - install the hooks with
pre-commit install
- run the command manually by issuing
pre-commit run --all-files
- if you did a good job in fixing the issues manually, all will be green.
For a better understanding of pre-commit
configuration, answer to the
questions in Configuring
.pre-commit
.
That’s it!. From now on, all code changes will undergo the specified checks.
Wrap up
At this point, your git repository should contain the following:
- the code developed in the Getting started codelab.
- the test programs developed in the Testing MbedOS codelab.
- the configuration files for all tools presented in this codelab, including the “.pre-commit-config.yaml” file.
The code should be compliant with all adopted rules and you should be capable of
implementing features and fixes to the program by following all guidelines and
applying the appropriate git
process.
If you have accomplished all of it, you are ready to deliver the project, phase 1.
Metrics and static analysis - Going beyond
Although we will use the above tools throughout the course, there is a multitude of other metrics that will help you assess the code quality. Scitool Understand offers you many metrics or static analysis options. Free academic licenses exist for the tool and you are free to explore this further possibility.