Clean Code for Embedded Systems
Clean Code is important, clean well crafted code is easy to read, easy to maintain and easy to reuse. Clean Code is important, code that is not clean slows down development, it becomes hard to read, difficult to understand and at times becomes so bad that it is just plain dangerous to change. Code that is not clean sucks the life out of development teams, it kills productivity and at its worst has killed companies.
The term Clean Code originates from Robert C Martins book, Clean Code - A Handbook of Agile Software Craftsmanship, it and other books from the software craftsmanship movement go in to great detail on what Clean Code looks like and how to write it. However the book and most of the Clean Code material does not consider the special requirements of embedded systems.
This training course helps you to build knowledge and understanding of all aspects of Clean Code as adapted to embedded systems development in C or C++. You will learn what clean code looks like in fine detail. You will learn how to write clean code (by refactoring).
Course Structure
Four two hour training sessions, each looking at three aspects of clean code.
One half day hands on training exercise in refactoring
Training can be delivered remotely or on site
Audience
- Embedded Software Developers
- Software Developers
- Technical team leaders
- Managers that want to know more about the technology they manage
Course Outline
The first three modules are about code style, those aspects of the software that have no impact on the compiled code, only on readability. Then we have an interactive hands on session where we look in detail at Refactoring and the process of writing clean code. The remaining nine sessions look at aspects of clean code that impact the compiled code as well as the readability. These later sections are more specific to embedded systems.
Clean Code and Software Craftsmanship for Embedded Systems
Module objective: Software developers write code that works, all too often we stop once code works and is performant enough for the job in hand. Failure to take the extra step of ensuring that the code is clean, readable and maintainable causes code to rot. As code rots it becomes slower and slower to add value leading to huge costs further down the line. In this section we explore:
- The Origins of Clean Code
- The need for Clean Code
- What is good code and what is bad code
- The cost of bad code
- Responsibility
- Overview of clean code topics
Comments
Module Objective: Commented code is good - or is it? In many old code bases there was a requirement to comment every function, every parameter, every file... did that actually lead to better more maintainable code?
- Explain yourself in code
- Legal comments
- Informative comments
- Explaining intent
- Commenting standards and tools
- Comments as noise
- Comments as a code smell
- Comments and LeBlanc's law
- Commented out code
Meaningful Names
Module Objective: Consider carefully what makes a good name for an identifier. Look at examples to understand the impact that good names have. Determine some guidelines that help with generating meaningful names. Specifically we consider:
- Intention revealing names
- Avoiding Disinformation
- Distinctions
- Pronounceability
- Hungarian Notation
- Naming classes
- Naming Functions & Methods
- Consistency
- Vocabulary
- Context
"You should name a variable using the same care with which you name a first-born child.”― Robert C Martin – Clean Code
Formatting
Module Objective: Understand the importance of formatting code. Look at numerous examples of different styles of formatting. Consider what formatting rules the team believe are most readable. Consider tools to assist with formatting. Specifically we consider:
- Team rules
- Vertical formatting
- Horizontal formatting
- Line length
- Openness and density
- Alignment
- Indentation and parenthesis
- Dummy Scopes
- Naming Style
Refactoring
Module Objective: Understand what refactoring is (its not rewriting), different types of refactoring and why refactoring is critical to maintaining a clean code base.
- What is refactoring
- Types of refactoring
- Why do we need to refactor
- Sample refactoring steps
- Demonstration of refactoring
- Exercise
- Debrief
During the debrief we discuss how the team found the refactoring. The benefits of separating refactoring from adding new functionality. The impact of having full test coverage when refactoring.
Functions
Module Objective: Functions or methods are the core building blocks of software. This module looks at many aspects of function design that impact their readability and maintainability.
- Function Size
- Do one thing/One level of Abstraction
- Naming
- Arguments
- Side Effects
- Command or Query
Having looked at these aspects we reconsider how to actually write clean functions.
Objects and Data Structures
Module Objective: Objects hide their data behind abstraction, whereas data structures expose their data. This module looks in depth at the differences between the two, looks at what makes a good object and when to choose to use objects and when to use data structures.
NOTE: For C programmers this applies to you too!
- Data Abstraction
- Data Object Anti-symmetry
- The law of Demeter
- Data Transfer Objects (DTO)
- Organization considerations
Classes
Module Objective: Consider what differentiates a clean class from one that isn't. What design principles can help with producing a clean class?
- Object oriented guidance and C
- Class organization
- Size
- SOLID principles
- YAGNI
Error Handling
Module Objective: Error handling is an essential part of software design. The book clean code is clear that using exceptions is the clean way of handling errors and this module covers this. However in embedded systems we are often prevented from using exceptions for many reasons, this module covers clean code approaches when exceptions cannot be used.
- Exceptions vs Error Codes
- Write try-catch first
- Unchecked exceptions
- Context
- Scope
- Special Case Pattern
- NULL
- Clean Error codes
The module concludes with a discussion on the merits of the various approaches within the teams code base.
Boundaries
Module Objective: Boundaries in software are key to being able to make changes easily. This module considers multiple types of boundaries and considers clean strategies to decouple software across boundaries. As well as architectural boundaries source code organization into appropriate components allows us to design for changes in processor, board revisions, operating systems and tool vendors
- Third party software
- Learning tests
- Non existent code
- Architectural layers
- Clean Architecture
- Source code organization
- Vendor branches
Unit Tests
Module Objective: Unit testing is essential to ensure the multiple units that make up our software all work independently as the developer intended. But how do we generate unit tests? What needs to be tested? How do we write good clean maintainable tests? In this module we consider:
- Test driven development
- What makes a clean test
- Domain specific languages in tests
- Dual standards for production code and tests
- Tests should do one thing - but what is one thing?
- FIRST
We recommend Test Driven development training from Wingman Software
Systems
Module Objective: This module considers strategies for system issues such as startup/shutdown, scaling and architecture. The objective is to uncover strategies for separating these concerns from the operation of the components of our system. Specifically we consider
- Separate construction from use
- Separate construction from initialization
- Scaling up
- Test driving architecture
- Decide as late as possible
Emergence
Module Objective: What if there were four rules that if followed ensured that clean code was produced? What if there were four simple rules, would you follow them? This module takes the form of a discussion around four such rules.
Concurrency
Module Objective: In embedded systems concurrency is a given. In this module we look at strategies for maintaining clean concurrent code. The specific topics covered are:
- Abstract the operating system
- Separate Tasks and Runnables
- Mutex
- Interrupts
- Design in shutdown
- Defense principles
- Maintain a temporal design
- Know your tools/Monitor your system
- Testing multi threaded code