In church last week we were talking about evolution when the term "Irreducible Complexity" came up. For those who aren't familiar with the concept irreducible complexity is a term coined by Michael Behe to illustrate that complex system could not have evolved and therefore must have been created intelligently. Behe defines irreducible complexity as:
A single system which is composed of several interacting parts that contribute to the basic function, and where the removal of any one of the parts causes the system to effectively cease functioning. (Darwin's Black Box p39 in the 2006 edition)
In his book Behe uses a mousetrap to illustrate an irreducible complex system.
"If any one of the components of the mousetrap (the base, hammer, spring, catch, or holding bar) is removed, then the trap does not function. In other words, the simple little mousetrap has no ability to trap a mouse until several separate parts are all assembled. Because the mousetrap is necessarily composed of several parts, it is irreducibly complex." (Behe, 1996).
(This post does not seek to discuss the controversy of evolution vs. creationism vs. intelligent design)
How does this translate to software? An irreducibly complex software is software that cannot be easily tested. The "removal of any one of the parts causes the system to effectively cease functioning" really points to dependencies in software. Do your tests rely on a database being there? Do you get emails whenever some piece of code runs because as part of the method an email is sent?
How often have you stepped into some code and have seen a method calling database, sending an email, doing some validation, and then returning some value. Here's an example I pulled from Jimmy Bogard's post on separation of concerns:
1: [DataObjectMethod(DataObjectMethodType.Select, false)]
2: public static List<Customer> GetCustomers(int startRowIndex, int maximumRows)
4: List<Customer> customers = null;
5: string key = "Customers_Customers_" + startRowIndex + "_" + maximumRows;
7: if (HttpContext.Current.Cache[key] != null)
9: customers = (List<Customer>) HttpContext.Current.Cache[key];
13: customers =
16: c in DataGateway.Context.Customers
18: c.CustomerID descending
23: if ((customers != null) && (customers.Count > 0))
24: HttpContext.Current.Cache.Insert(key, customers, null, DateTime.Now.AddDays(1), TimeSpan.Zero);
27: return customers;
The code above will work however it's a bear to test, the code absolutely requires other items (database, HttpContext, ect) to be there in order to work. I would venture to say that the person who wrote it did not build up the code through small iterations, but rather wrote it all in one fell swoop.
In software, reducible complexity should be a goal. A reducible complex system allows for pieces to be substituted for others so you can focus on one particular area. Don't have a database in place, no problem, simply put a placeholder object in for all calls made to the database. (Yes I'm alluding to mocking). You can approach creating a reducibly complex system in two ways:
- Create the system as a whole, then reduce it's complexity
- Create the system incrementally
I prefer the former to the latter as I'm working on my TDD skillz.
While the analogies used here are not quite perfect, I do feel they illustrate the point adequately. As a developer your goal shouldn't be to simply write code. You should concern yourself with the lifetime of your application/code base. Irreducibly complex systems, while working, can also have short life spans. Think about the last time you've ever seen someone fix a broken mousetrap. All the parts are too interconnected, the mousetrap is simply replaced. If you're not careful your code may be viewed too difficult and time consuming to fix, and simply replaced.
09-02-2008 9:48 AM