Overengineering

Engineering problems are hard. Not NP-complete hard (although sometimes they are), but rather technologically hard. For this same reason we need to solve them with an engineering approach. Code smells, low performance and poorly automated processes, among other problems, are good candidates for problems to be tackled with an engineering mindset.

There’s no denying that solving these problems is necessary and in some cases, critical. But how do we know when we’re overengineering them? Here’s a real life example.

ProblemWe want to have a unified deployment script, that works for all of our applications.
Thought process: We already have a script that does most of the work, but we want to use it for new application A. The script, however, needs to support deploying application A with curl instead of scp. We should augment the existing script to make it more powerful by supporting application A.
The result: A generic, catch-all script that effectively supports the new project, but looks kind of like this:

deployment.script -version=1.0 -user=admin -password=admin -url=http://url.com/target -file1=/path/to/file1 -file2=/path/to/file/2 -anotherPath=/path/to/another/path -yetAnotherPathThatIsNeededForApplicationAnly=/path/for/application/a -someRandomLegacyParameter=scxpr55 -webServer=apache -include=includeExpression -exclude=ExcludeExpression …

You get the idea.

Without having to look at the file, you already know that is going to be full of if/else statements or some other switching directive, which complicates matters. There’s even an urban legend of a big software company (I don’t know which one) that had to patch and recompile the Linux kernel to support more command line parameters than the shell allowed them to. This is mentioned in Jez Humble’s Continuous Delivery book.

What if we could modularize the script a little bit? We don’t necessarily have to be coding in an object oriented language, but if we can slice the logic into different sub-operations (configure, package, push) then clients can grab only the pieces they need and run with them. We can still share the common logic but bisect and decouple unrelated logic.

Proposed solutionHave multiple, smaller scripts that do well defined actions:

  • package.script –target=/target/path
  • test.script #no parameters
  • deploy.script –artifact-to-deploy=/path/to/file –target-server=target

Obviously, this a very simplistic example, but I hope the point is not lost. Just because we’re cleverly using parameters and flags doesn’t necessarily mean that we’re engineering the correct solution, it just means we’re trying to modify the minimum amount of code, which doesn’t always scale.

Actually it’s not about the flags and parameters (that apply to this example only) but it’s about not trying to solve everything with code. If the first thing you do when you see a problem is think about the lines of code that you need to modify, then you’re probably going to end up overengineering it. Step back, look at the full picture and carefully think about making a quick fix, specially if you’ve touched the same portion of the code several times to accommodate for new features.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: