Design for Test is part of standard practice in the microcontroller industry. It is discussed in the context of software engineering as well - but it is absolutely essential to the makers of large-scale microprocessors. The key concept is that the programming interface to a CPU does not allow access to many of the internals of the chip and additional logic is therefore added to the hardware to allow test and diagnosis of the device outside the scope of normal use. DFT is necessary to handle the fact that minor flaws can prevent execution of all diagnostic self-test operations.
Some years ago I had the opportunity to apply this principle to software architecture.
The application was a data abstraction layer in a multi-tier Windows application. The app used a relational database for persistence and presented the user with a set of objects. The layers in the design were as follows:
- GUI
- Business logic
- Object model
- Abstraction
- ODBC
- Database
The part that I designed and built was the Abstraction layer and my goal was to make it as generic as possible. To accomplish this I put metadata in the database that defined the object model. The code in the Abstraction layer knew almost nothing about the business objects and their relationships to each other. It knew that there was such a thing as an object, that an object had properties, that objects could have relationships and dependencies, and what the property types could be. At first, all the other details were in data in the database that matched the expectations of the business logic. This allowed us to change the front end and the object model with little or no impact on the design or implementation of the Abstraction layer.
One way to apply the DFT principle to software is to add code that does some sort of internal self-test or consistency check. In this case, we didn't add any code that wasn't used in normal operation. In fact, we went in the other direction and stripped out any code we didn't absolutely need to get the Abstraction function to run. This led to an implementation that was very generic and concise. Even the definition of the generic data object was in the database.
Obviously some bootstrap code was needed to make this work. And in the revised and rewritten code in the second release we took out the initial bootstrap to improve performance.
The effect on test was simply that no unit test was needed for this part of the implementation. It either worked or it didn't. Like the FORTH language, which has a tiny interpreter, we started with a very compact core and built out from there.