Kevin Seghetti's Programming page
This is just getting started, I am just pasting in things I have said elsewhere. Eventually this will get some organization.
The art of programming:
What others call Design by contract, I call TRUST NO ONE! Treat the program as a hostile environment your module has to live in. Assume nothing (or, more accurately, assume the reset of the code is out to get you and TRYING to make you fail). Every function should validate, to the best of its ability, every input and every output (if they are class instances, call their Validate functions), verify as well as you can they meet the criteria of the function. In addition, every class function should validate the class' internal state (by callings its own Validate function) when entering and exiting the function. Don't worry that excess assertions will make the program too slow, you can always build a version with assertions disabled to ship.
This leads to designing input/output parameters that have detectable invalid states. For example, if there is an enumeration of possible states, reserve state 0 as an invalid state:
Write code which is self-validating.
. In C/C++, I use assert for validation, the program halts immediately if there is anything even the slightest bit wrong. assert eary, assert often. The more assertions there are, the close to the bug an assertion will occur, making it easier to find and fix.
- Have tons of logging. I prefer a robust logging system over a code level debugger for the following reasons:
- one can jump forward and backward in time just by scrolling through the log
- comparative runs can be done (compare the code path through a function working correctly vs incorrectly)
- decouples reproducing the bug with debugging it (SQA can just enter the log into the bug report, and the developer can analyze it at their leisure, instead of having to drop what they are doing and go trace the problem right now)
- logging is much easier to accomplish on embedded hardware than a good debugger is
- logs can be captured in the field, where debugging isn't really an option
- Construct automated test suites which put the code through its paces, try for complete code coverage, exercise all boundary cases
- whenever a bug is found, first update the test suite to demonstrate the bug, then fix the bug (you know you are done when it passes the test suite again).
- The test suites should not only confirm that the code works correctly with correct input, but also confirm that the code fails when given incorrect input.
(note that some of this is similar to extreme/agile programming, I think, I haven't studied them very closely).
If all of the above is done, then it is pretty safe to refactor just about anything, since the code base will immediately tell you where the changes break things. On a code base with all of the above, I am not afraid to completely revamp a class' public interface, or rip out and re-implement a library, 2 months before beta. I have done that sort of thing many times, and in almost every case it has saved time over the course of the project. (if anyone cares to see what a working code base where I used these methodologies looks like, see www.worldfoundry.org)
Such a code base is able to adapt to change fairly well (since it quickly identifies what problems changes cause). It also lends itself well to experimentation.
for more on designing code to be easy to debug
Series of articles on improving assertions :
Here is my short C++ sales pitch:
In C, if a variable is trashed, the offending code COULD be anywhere in the codebase, since any code can write to any variable it can refer to. In C++, by making variables private member of a class, when it gets trashed the offending code HAS to be in the class (or a rogue memory pointer). So, finding bugs is GREATLY simplified, since the scope of the problem is narrow and well defined. (it is possible to write C code in an object oriented fashion such that you know what code touches what variable, but if there are multiple developers, long distance references inevitably creep in).
- Effective C++, Scott Meyers, ISBN 0-201-56364-9: this book will save any new C++ programmer many hours of grief.
- More effective C++, Scott Meyers, ISBN 0-201-63371-X
- Effective STL, Scott Meyers, ISBN 0-201-74962-9
- Industrial Strength C++, Mats Henrichson/Erik Nyquist, ISBN 0-13-120965-5: I agree with almost every rule/guideline in this book. If followed these make C++ a safer, better language
- The C++ programming language (3rd edition), Bjarne Stroustrup, ISBN 0-201-88954-4
- The design and evolution of C++, Bjarne Stroustrp, ISBN 0-201-54330-3
- Modern C++ Design, Andrei Alexandrescu, ISBN 0-201-70431-5
I haven't actually written much C++ in the past few years. For embedded devices I stick with C, and for larger systems I run Linux and glue everthing together in perl. Instead of writing monolithic applications, I write a few dozen small perl scripts, which acting together (and usually comminicating through an SQL database) implement the functionality of the device.
Other interesting articles /links :