Skip to content

4 Tactics to Break "Brian's Law"

ADMIN | 25-08-2011

Brian's Law: The code is always more broken then it seems to be. The value of code is determined by how certain it is to work correctly.

Hexagon pattern 1

Eric Zenk is a Senior Software Engineer in the CGM group at Spatial and will be authoring occasional guest posts.

"Brian's Law: The code is always more broken then it seems to be"

Making C++ code solve math problems is one of my favorite things to do. The value of code is determined by how certain it is to work correctly and how useful a problem it solves. Working correctly includes both giving the right answer and doing so efficiently. The thrill in coding stems from knowing that what you are writing or fixing works, not just in the cases you have tested but in any other case as well. Like many worthy goals, complete certainty that a computer program is correct is unattainable.

A lot of ink (and bits) have been spilled on how to verify software is correct. There is no universal answer. Programming is hard. The remainder of this blog entry will discuss some things which I find helpful in the struggle. Since I work on ACIS and CGM, many of my comments are specifically aimed towards the mathematical aspects of understanding C++ code.
Here are some tactics:

  1. Acceptance Tests: Have a large acceptance suite that exercises the code you are working on.
  2. Contract Checks: Instrument code to check intermediate states are correct.
  3. Visual Breakpoints: Instrument the code to draw intermediate states.
  4. No-op Assertions: Factor code changes into two steps
    a. a no op step which shouldn't change the result, but makes a place to add the new feature/fix
    b. a behavior changing step where you put the new functionality in.

1. Acceptance Tests: Take advantage of any data you have laying around and any models you get in bug reports. The same 3d models can be used to test many operations. The other measure of the scope of a test suite is how many different workflows it uses the functionality in; it is best if you can get as many people as possible writing tests using any workflow that seems like a customer might want to do it. This is something that is hard to do well enough: I often find customers using ACIS in ways I wouldn't expect.

2. Automatic inline testing: John Sloan has written about using contract programming and assertions to verify correctness. We have internal builds of ACIS which contain extra checking code and assertions. This allows better verification that what we are working on is correct, while not costing any extra runtime for customer builds.

I end up doing this in two ways: when initially writing new code, I put in asserts to document and test my expectations: e.g., array indices not out of bounds, factory methods create non null objects, a list sorting function should return a list that is sorted, etc. These assertions seem a bit silly but they catch many obvious problems without spending much time debugging. Asserting that a list was returned in sorted order helped me catch the fact that a comparator I wrote was returning 0 or 1 while the sorting algorithm expected +1, 0, or -1. Basic contract asserts help give confidence that you have not plugged the pieces together incorrectly.

When debugging, I use the visual breakpoints (see item 3) to form a guess about what the problem is. Once I have refined the guess to something mathematically testable, I put an assert in the code or use the debugger to test that my guess is correct. If the guess was incorrect, I try other possibilities. Once I have found the "first noticeable symptom" of the problem, I analyze what caused it, and work backwards. It takes a few iterations of modifying code and modifying the debug assertions to make the assertions correct. I usually keep whatever assertions I made debugging in the code, if they don't fail on any regression tests. As a result of using assertions for several years in the ACIS faceter, I have been able to fix a few bugs in a matter of minutes: I just load the test, it throws an assertion, then fixing the assertion fixes the bug.

3. Visual Breakpoints: The idea of a visual breakpoint is to display the model being worked on after each change so you can determine where things first when wrong. To speed the process up, we sort breakpoints into different levels of detail. For example, in the faceter there are probably about a dozen coarse visual breakpoints corresponding to major algorithm steps. There are probably fifty or more visual breakpoints for smaller steps. To diagnose a problem with the faceter, I look at the coarse breakpoints to get a rough idea where the problem is. Most of the time, the coarse breakpoints give me some ideas of what assertions to test and where. If not, I turn on more detailed breakpoints.

The following two videos were made by capturing the visual breakpoints from a test. First is the coarse breakpoints for api_align:

[swf file="http://sandbox.spatial.com/downloads/alignbreaks.flv" flashvars="autostart=false"]

Next is the coarse breakpoints and some finer grained breakpoints (which show how the mesh is build from the quad tree) of a faceter test. The code being shown for these breakpoints is the in work version of ACIS.

[swf file="http://sandbox.spatial.com/downloads/facetbreaks.flv" flashvars="autostart=false"]

4. No-op Assertions: Refactoring old code is notoriously difficult. It often happens that you need to change part of an algorithm to a better implementation. In these cases, it is important to understand when there is a behavior change and whether it is an improvement or a regression. In these cases, I usually make an intermediate, and temporary, code change where both the new and old low level function are used and their results are asserted equal. Once the methods always get the same result, or always get a better result with the new method, I can version the change and start using the new method. When accessing whether the new or old result is better, hard theory is your best friend. Understanding what properties the desired answer has allows you to judge which algorithm is better. When the older code gets a better answer, I study it further to understand how to improve the new version. In any case, having verified that low level pieces give the same answers over a significant test suite is very useful in confirming that it works.

Wrap up: Two strategies arise from all this: use the scientific method in debugging (guess what's wrong, try to falsify or confirm your guess, then iterate until you think of a good fix), instrument internal builds so that they can automatically check for low level problems you have encountered before. Do you all have any strategies you want to share?

You might also like...

5 Min read
3D Modeling
What is digital manufacturing? Here’s a simple digital manufacturing definition: the process of using computer systems...
5 Min read
CGM Modeler
Software components are like the stage crew at a big concert performance: the audience doesn’t see them, but their...
Application Lifecycle Management Flow
4 Min read
CGM Modeler
When you hear the term, Application Lifecycle Management (ALM), you likely think about the process that a software...
9 Min read
CGM Modeler
SLS in Additive Manufacturing is used to convert 3D CAD designs into physical parts, in a matter of hours.
8 Min read
CGM Modeler
There’s a lot of confusion around what the terms additive manufacturing and 3D printing mean.
4 Min read
3D Modeling
Additive manufacturing, often referred to as 3D printing, is a computer-controlled process for creating 3D objects.
5 Min read
CGM Modeler
Computational Fluid Dynamics (CFD) is a type of analysis that provides insight into solving complex problems, and...
2 Min read
CGM Modeler
WRL files are an extension of the Virtual Reality Modeling Language (VRML) format . VRML file types enable browser...
Voxel model example
3 Min read
CGM Modeler
Voxels are to 3D what pixels are to 2D. Firstly -- let’s examine what pixels actually are. Everything you see on your...
Point_cloud_torus
2 Min read
CGM Modeler
Point-cloud modeling is typically used in the process of 3D scanning objects. Rather than defining surfaces through...
Polygonal Modeling
2 Min read
CGM Modeler
Polygonal (or polyhedral) modeling is the most common type of modeling for video games and animation studios. This type...
aerodynamics-CFD
9 Min read
CGM Modeler
Computational fluid dynamics (CFD) is a science that uses data structures to solve issues of fluid flow -- like...
BREP Model example
2 Min read
CGM Modeler
BRep modeling, or Boundary Representation modeling, is, in CAD applications, the most common type of modeling. BRep is...
Feature Recognition Zoomed
5 Min read
CGM Modeler
IN THIS ARTICLE: What is FEA (Finite Element Analysis) Principles of Finite Element Analysis and Simulation Software A...
3YourMind and Spatial
3 Min read
3D Modeling
As manufacturers begin to rely more and more on additive manufacturing (AM), moving from a few select piece parts that...
Voxeldance and Spatial
2 Min read
3D InterOp
To the uninitiated, 3D printing may seem a simple process — download your CAD file and hit print. But the world of...
BIM_word_cloud_web
2 Min read
3D Modeling
The construction industry has long taken advantage of prebuilt components, from prehung doors to prefabbed roof...
Clash-Detection-fig-1
4 Min read
3D Modeling
A major benefit of constructing a building virtually is the cost savings gained by identifying errors in the design...