TrainingConferencesAbout UsContact UsAdvertiseSQE.comRSS Feed

StickyMinds.com: brain food for building better software

Log In
 Clarify Your Search Criteria

Tips on Using Our Search Feature(s)
 
StickyMinds.com Home
ResourcesTopicsCommunityPowerPass
Home  >  Topics  >  Test & Evaluation  >  Detail: The Accidental Complexity of Logic



The Accidental Complexity of Logic

By Kevlin Henney

Send This Content to a FriendGet a Short Link to This ContentPrint This Content

Summary: Much code complexity and no small number of program defects can be traced back to confusion over logical expressions and the expression of logic. Find out how you can get that complexity under control.

HP Pillars of Application Quality
Logic lies at the heart of computation. Boolean algebra guides much of the course of a program's flow. It is the stuff of programming. It is also, as Kernighan and Plauger noted in The Elements of Programming Style, the source of occasional confusion: "Boolean algebra is not used nearly as widely as ordinary arithmetic, so we must write logical expressions more carefully lest we confuse the reader." They wrote this thirty years ago, but our ability to be confused has not lessened any in that time.

Much code complexity, many programming thinkos, and no small number of program defects can be traced back to confusion over logical expressions and the expression of logic. In spite of our best aspirations and the relative simplicity of Boolean algebra, this is not the kind of thinking that comes instinctively to humans--even programmers.

In many ways this state of affairs can be considered ironic. In formulating the calculus that bears his name, George Boole was pursuing an ambitious goal, as indicated in the title and opening of his 1853 work, An Investigation into the Laws of Thought: "The design of the following treatise is to investigate the fundamental laws of those operations of the mind by which reasoning is performed."

In practice, although we use Boolean logic correctly and effectively much of the time, the shortfall between the way we think and the needs of code presents sufficient opportunity for incorrect and unruly code to creep in.

Dead Code Walking
Consider the fragment in listing 1a, which is based on some code I saw a few years ago.



Because the body of the loop is unreachable, this becomes a rather longwinded way of writing the fragment in listing 1b.



Given the chaos and low quality of the project as a whole, it is exceedingly unlikely that the illusory, lines-of-code productivity boost that the dead code gives was intentional.

Omitting a not, or including a surplus one, or using an or where an and was meant, or vice versa, are common examples of errors that take code down the wrong path. Unit tests can be a great help in such situations: Staring at a piece of code for too long, you may possibly fool yourself into thinking that your inverted logic is correct, but a simple assertion is less easily duped. Of course, in the project in question there was no coherent form of testing--manual or otherwise--at any level, and because of the application's high coupling, unit tests would have been pretty much impossible. Code review is a complementary way of uncovering such defects and would have been a suitable alternative. Code reviews do not have to be formal, and an informal pair walkthrough is often less time consuming and less threatening than walking through code in a meeting with many others.

Seeing the Forest for the Trees
Simple thinkos are one source of error, but another comes from accidental complexity--making things more complex than necessary so that it becomes difficult to see what is going on. Consider the fragment in listing 2a, which is based on code I ran across (well, tripped over) many years ago.



The code didn't start out this way. It probably made sense originally--and even after a change or two--but eventually an addition led to a contradiction, which means the code reduces to the snippet in listing 2b.



Or, more concisely, to the code in listing 2c.



Signal to Noise Ratio
But unclear logic is not just about defects and dead code. Code can be functionally correct but developmentally poor. Clumsy logic also introduces accidental complexity, making the process of reading code more labored than it should be. The code in listing 3a includes a redundant check.



In this particular case, another programmer suggested the "simplification" shown in listing 3b, but it is not exactly an improvement.



Instead, for such a simple case, group conditions that have a common result, as shown in listing 3c.



Should the condition become longer than is either reasonable or readable, extract and name a method that represents the whole condition rather than disassembling the logic into an if else tree.

Boolean-to-Boolean Converters
One particularly common and noisy kind of construct is what a conference attendee I once met referred to as the "Boolean-to-Boolean converter," a name that nicely sums up the redundancy of such constructs. These are often characterized by extensive use of true and false literals and control flow structures. They all can be reduced to much simpler expressions. Here is a typical example of an identity converter:

          if(found)
                  return true;
          else
                  return false;

Which is nothing more than:
          return found;

And here is an elaborate negation:
           if(enabled)
                   enabled = false;
           else
                    enabled = true;

Which is sometimes written slightly more compactly as:
            enabled = enabled ? false : true;

This still reduces to something simpler and more direct:
           enabled = !enabled;

Listing 4a is a slightly more nested example.



Its jagged formation still reduces to something briefer and more direct, as shown in listing 4b.



Sometimes a truth is established on one line, only to be restated using literals in repetitive form across subsequent lines as shown in listing 5a.



Listing 5b demonstrates that both the decision structure and the use of the Boolean literals are unnecessary.



Perhaps one of the most pervasive examples of a Boolean-to-Boolean converter is the explicit comparison of Boolean results against Boolean literals:
             if(checkCacheExists() == true)
                    ...

The result of explicitly comparing a Boolean against true makes it no truer than it already was. Such tautological phrasing is often a consequence (or a cause) of imperative names that should follow a more predicate-like naming style. Rather than naming the action, name the truth that is being acted on:
            if(cacheExists())
                    ...
Names beginning with check, validate, and verify are typical candidates for such renaming.

Flag Waiving
Overreliance on flags leads to code with a lot of raw Boolean literals--often an indicator that logic can be revisited and simplified. Consider the example in listing 6a.



It simplifies to listing 6b.



Similarly, listing 7a represents an impressive attempt to mask a one liner.



The separation of declaration from initialization introduces more noise on top of the flag-driven logic. From all this we can extract the delightfully brief listing 7b.

Conclusion
In each of these cases it is worth keeping in mind that it is not necessarily ignorance or sloppiness that has led to unnecessary or incorrect logic, and it has nothing to do with the programming language--the examples may have been presented in Java, but they were based on published and production code in a variety of languages. Nevertheless, to paraphrase the author Martin Amis, it is terrible to see a programmer being beaten up by a programming language. Revisit, review, and revise. Truth (or falsehood) will out. {end}

What examples of logic have you seen that, on revisiting, have proven to be either incorrect or reducible to something far simpler?

Join the conversation below or start a new one in the Member Comments section.


About the Author
Kevlin Henney is an independent consultant and trainer based in the UK. He provides consultancy and training in programming techniques, software architecture, and development process. He is co-author of two recent books on patterns, A Pattern Language for Distributed Computing and On Patterns and Pattern Languages.

Back to Top
 
 

Member Comments
Add Your CommentExpand Comments
 
Comment:    
by John Voris 6/18/2008

Here is one area of nested logic that I sometimes use. It ensures that the code follows an english language construct, rather than forcing the code into an unnatural boolean logic contruct that does not mirror the spec nor how a lay person might describe the behavior.


Often the best way to write the logic statement is to insert an "else". It may be inefficient, but the path through the code then mirrors the English description. Insertion of the "empty else" is allowable if the intent of the code is improved. Traceability of intent is a big SOX requirement in many industries.


The alternative, with proper...Read On

 
 
Comment:    
by Robert Miller 5/16/2008

I agree in principle with the thesis of the article, having seen many of these types of errors over the years. However, I don't quite agree with all of the simplifications to the code that the author suggests.

One of the goals of good coding practice is to write understandable and maintainable code. Sometimes this means writing more than the absolute minimum code needed so that the intent of the author is made more clear.

For example, I wouldn't necessarily return a complex expression as in listing 4b. I think it is clearer to create an intermediate variable with a descriptive name, set it to the appropriate value, and...Read On

 
 
Comment:    
by Llarry Amrose 5/12/2008

Good examples of something I've seen here. We had a developer when I started (11+ years ago) whose code we are still having to clean up after. He seems to never have tried to fix anything by removing code, but only by adding more. If he came across a logic error, he'd add a negation to some part. If that didn't do the trick, he might add another, and another... In once place, he had 6 "NOT"s together. In another place, he decided the "Enabled" property wasn't sufficient, so he defined a "Disabled" property as well, then had trouble keeping them in sync...

 
Back to Top

May We Suggest...
Show All

Articles & Papers

Templates

Links

Books

Tools

Related Products
Testing Training Courses
Software Testing Certification, Systematic Software Testing, Test Management, Mastering Test Design, Just-in-time Testing

Software Engineering Training
Mastering the Requirements Process, Requirements Modeling, Introduction to the Capability Maturity Model Integration, Business-Driven Software Measurement

Agile Software Development Training
Scrum Master Implementation Workshop, User Stories and Estimation in Agile Development, Design Patterns Explained, Practical Test-Driven Development
Marketplace

Census: Web-based Bug Tracking and Defect Tracking
Track software bugs, defects, enhancements, support calls, and more. Issue tracking software that is scaleable, fully customizable and integrated with VSS. Includes e-mail notifications, role-based workflow, change history, and Crystal reporting.

Web based bug tracking - AdminiTrack.com
AdminiTrack offers an effective web-based bug tracking system designed for professional software development teams.

Check Out IT Certification Preparation Materials
Sign Up With SkillSoft & Get Access to Training Materials for Over 50 Professional Certifications.

The Very Best in Pairwise Test
Testcover.com - Compare our test case efficiency, response time, and ease of use. Simply the best!

Bug Tracking On-Demand
Looking for the reliable, convenient, secure and completely web-based issue tracking system? BUGtrack allows unlimited number of users, projects and bugs as well as unlimited customer support for a low flat rate.

Get your product or service listed here.
Subscribe to Better Software Magazine
Subscribe to Better Software Magazine

First Name:

Last Name:

Email Address:


Home   |   Resources   |   Topics   |   Community   |   PowerPass



© 2008 StickyMinds.com. All rights reserved.
StickyMinds.com is a division of Software Quality Engineering.
Privacy Policy    Terms & Conditions    Link to StickyMinds.com    Feedback


Red Gate Software

STARWEST 2008

 
Agile Development Conference 2008