A discipline that’s become increasingly popular is documenting program operations as a means of assuring software quality. This documentation articulates the program function at varying levels of detail—all of them aimed at the developer and tester rather than the user. At minimum, the documentation captures all requirements of the software in non-textual style. This representation might consist of UML activity diagrams or other similarly precise formats.
The representation should avoid documenting implementation. For its purposes, the design and the code are disjoint entities. As I discussed in my recent column on model-based testing (MBT), this break between requirements and implementation enables MBT to be an honest way of testing; the implementation details exert no influence on the tests.
Let’s look at an extreme case that has worked exceedingly well, and then drill-down into more mainstream examples. The paragon of pre-code documentation is the team that writes code for the U.S. space shuttle. When changes need to be made to code, according to a famous article (“They Write the Right Stuff”) that appeared in the mid 1990s in Fast Company, they are highly documented in advance of any code change. The numbers are extreme. Adding GPS navigation to the shuttle required changing or adding nearly 6,500 lines of code. The team generated some 2,500 pages of documentation—specs, analysis and reviews—before any change was made.
As a result, before coding begins, shuttle code developers know exactly what changes they’re going to make. They have tests at the ready and generally find 85% of defects before formal testing of the changes begins. After formal testing, the defect capture rate climbs to 99.9%.
The example is extreme because most organizations do not have the means or time to invest in near-perfect software. In addition, most teams must deal with rapidly changing requirements, which does not exist in the case of the space shuttle.
However, argues David Parnas in a recent presentation, rigorous pre-documentation will greatly improve business software with little or no additional cost. Parnas, for those who don’t recognize his name, is a well-known beacon in software engineering. In 1972, he wrote one of the most famous papers on software architecture, “On the Criteria to Be Used in Decomposing Systems into Modules.”
He has long argued for precise pre-coding documentation of programs. As he points out, nearly every engineering discipline starts off with precise requirements documents—such as blueprints—except for software engineering, which seems to prefer muddled expressions of requirements. Parnas suggests that the documentation of a system’s function should be complete and wherever possible expressed in mathematical terms. The latter, as we know, ensures an unambiguous representation of functionality and greatly facilitates the generation of valid tests.
Parnas recognizes that the tools for documenting requirements are fairly weak and encourage a lack of rigor. As a result, he feels the key is to have surefire standards on how the documentation is prepared, so that developers can locate the necessary information when they need it.
The documents, ideally, should contain nothing but the requirements—mapping inputs to outputs mathematically—and should not contain the usual documented content (introductions, usage overviews, etc.), just a mathematical description of the function and a capture of any decisions made regarding this requirement, including the reasons for the decision.
This approach appears to have a waterfall aspect, especially in writing out all the requirements and functionality before writing any code. However, this is a false perception. Requirements can be changed, and the documentation changes with them.
I should point out that behavior-driven development embraces the document-first perspective, and it translates requirements into a series of tests, written out as scripts, which are then fulfilled by the software as it’s developed. Again, implementation is left out of the test.
Even the ultimate implementation activity, coding, is slowly cottoning to this pre-code documentation approach. Recall that test-driven development (when done on a true test-first basis) is a code design activity—hence the frequent requirement to create mock interfaces to separate implementation of the object under test from that of other objects, many of which don’t yet exist. TDD, therefore, also strives to document (via tests and mocks) the code prior to actual implementation.
There is a consistent thread here that the earlier you document requirements and functionality, the better the resulting code and the better the tests. Moreover, this discipline is neither a difficult nor expensive step. At worst, it imposes the requirement for greater reliance on artifacts, such as several UML diagram types and familiarity with mathematical notation. I suspect that the biggest change, though, is cultural: Making the documentation a central asset valued as much as the code will not be widely accepted until it is imposed.
Andrew Binstock is the principal analyst at Pacific Data Works. Read his blog at binstock.blogspot.com.