Software developments are those that can be installed on personal computers, on a tablet or cell phone. At Innovation Codotek we develop code that is SOLID, that is maintainable and testable, that does not require explicit documentation and that is based on known design patterns. In the end, any programmer can pick up our code and understand it easily. You buy our services, we deliver quality code. No black box, no secrets!
A code that is SOLID
SOLID is an acronym which designates 5 key concepts of object oriented programming.
- S - Single responsibility principle
- O — Open/closed principle
- L — Liskov substitution principle
- I — Interface segregation principle
- D – Dependency inversion principle
Single responsibility principle
The principle of single responsibility specifies that each module or class should only have one chosen. Compliance with this criterion provides two very important advantages.
First, because each module or class does one thing, the complexity of the software is fragmented. Simple sections of code are then easily testable. Indeed, it is essential to have test coverage that follows the development of the software. Note that creating software is not linear. We write a lot of code that we modify or destroy afterwards. Unit tests are then extremely useful for checking the code after each modification. We test for the presence of regression and make sure that the basic functionalities are still present.
Second, since each part is simple and does one thing, it is also easy to understand the code. We very often read and reread our code or that of others. A code that self-documents then has a very big advantage. Indeed, no text can compete in terms of clarity with a well-written code that reads like a story.
The code should be open for extensions, but closed for changes. Modules or base classes can be improved or specified by other classes which modify them. However, care should be taken to avoid changes or additions to these classes also necessitating changes to base classes or other classes.
More simply, it is necessary to define basic interfaces which are general in order to keep the classes independent.
Liskov substitution principle
Liskov's substitution principle means that a child class can replace its parent without the software ever stopping running.
The best way to respect this principle is to avoid inheriting from a parent class when the child class is not really of the same type. For example, abusive class inheritance contributes to an explosion of empty functions that exist only because the interface asks for them.
Interface segregation principle
The principle of interface segregation states that you should not force classes to implement interfaces that they do not use. The easiest way to recognize that you are violating this principle is to be careful when adding functions to interfaces. If an interface has too many functions, you should check whether you can separate the interface into smaller and more precise versions.
Dependency inversion principle
- High level modules should not depend on low level modules. Both should depend on abstraction.
- Abstractions should not depend on details. The details should depend on the abstractions.
Simply put, the code should minimize coupling between classes. A good way to check this is to always ask yourself which classes should be modified if you add functionality of the same type to the software. The answer should always be one or zero.
Code that is maintainable and testable
All code is changed or improved at one time or another. In fact, we spend as much time (if not more) proofreading our code as we spend writing new code. For this reason, the system must allow easy maintenance. The best way is to follow the principles of a SOLID code and take as much care in writing the code as you do in building a test system.
We're talking about a set of unit tests that can quickly verify the entire system. Do not forget about formalized systems and integration tests to be done at specific times.
Code design patterns
The use of well-known design patterns allows for efficient code structures that follow SOLID principles. So that other encoders can easily recognize the operation of a system. Here we reinforce the principles of code that is self-documenting and of code that is maintainable and testable.
Essentially, there are several types of design patterns that apply to very different situations. A good resource for understanding the techniques that Innovation Codotek uses is find here.
Here is the design process in its simplest form.
- We start by evaluating how to add code while respecting the architecture presented.
- The first version of the code in a given class or function is then written without regard to clarity or structure. At this stage, you create something new that requires quite a considerable effort in itself. Immediately polishing the code or implementing the design patterns from the start would impose an additional difficulty that would limit creativity and ultimately innovation.
- Once the code is written and functional, we create a series of unit tests. These cover all logical levels, functionalities and finally borderline cases and possible errors.
- Subsequently, we can modify the code, destroy it, rebuild it, separate it into several classes while relying on the unit tests developed. In short, we polish the code to bring out the basic concepts of SOLID programming and to ensure that the code is self-documenting.
- Once satisfied, we move on to the next problem.
Embedded codes for FPGAs or microcontrollers are, most of the time, not object oriented. Reusing the code is then more difficult. This reality does not mean that basic principles should be excluded. The code must be maintainable, it must also evolve with its entire chain of unit testing and integration. Likewise, the code must be self-documenting and explicit.
However, this type of code brings additional difficulties which can come from the limitation of languages and often, from the increased complexity of developments.
Thus, thesystem engineering carried out upstream becomes much more important. Likewise, more time should be spent doing diagrams UML to plan correctly the architecture. It is actually easier to build unstructured code in a language like Vérilog or C.
In the case of FPGA programming, special attention must be paid to the realization of state machines and some activity diagrams. These are very useful for guiding more complex FPGA code developments.