Michael proposes a code of ethical conduct for software developers.
We the members of the embedded software development community, in order to protect our customers (and their customers) from the risks inherent in our products, extend product lifetimes, lower long-term maintenance costs, and advance the integrity and reputation of our profession, do ordain and establish the following code of ethical conduct.
Check return codes. If a function can return an error code, it will almost certainly return one eventually. How will our software recover if it doesn't even know an error has occurred? We will, therefore, always check all return codes. When an error is detected, we will take whatever action is required to recover safely.
Document everything. We make dozens of design and implementation decisions each week; we forget the reasoning behind others at a similar pace. We will, therefore, document all of our reasoning in the code itself. Furthermore, we will update these comments if our reasoning changes.
Use version control. Making backup copies of source directories, commenting out code that might be needed again, and tracking changes in comments is insufficient, even when done carefully and with discipline. The use of a good configuration management tool is a must. Furthermore, we agree to always perform a diff and provide a detailed explanation for all changes each time a file is checked in.
Enforce coding standards. No matter how proud we may be of our abilities, we do not “own” the code we produce. Our employers and clients own it; we and others are hired to develop and maintain it. The true owners have the right to enforce a coding standard for our work. If they do not choose to exercise this right, we will self-enforce a standard according to generally accepted programming practices.
Run lint regularly. Compilers are more concerned with generating code than the correctness of syntax. Only a tool like lint can watch over our shoulders to ensure we do not stray into dangerous or non-portable programming constructs. We will, therefore, include lint in our development process. If we don't remove all code with warnings, we will at least understand why each and every warning remains.
Perform code inspections. Automated tools are helpful, but nothing is better than a peer review for finding logic errors. Code inspections have been shown to be many times more efficient than any other single debugging tool. We will always review our code as a group at least once before each release.
Assign one tester to every developer. Programmers make lousy testers, especially when it's their own code they're testing. For best results, one independent tester should be hired for every developer. And the testing team must maintain and rerun regression tests regularly, to certify that a new release is at least as good as the previous one.
Measure performance. Some kinds of tests are best performed by the engineers themselves. In real-time systems, we shall directly measure interrupt latency and the time it takes each of our critical subroutines to complete. An oscilloscope and a spare I/O pin are useful in this regard.
These best practices are easy to do and inexpensive to implement. A one- or two-person design team can follow them as easily as a 50-person engineering department. If you aren't doing these things already, you have no more excuses.