Posts From October 2013 - Musing, Rants & Jumbled Thoughts

Header Photo Credit: Lorenzo Cafaro (Creative Commons Zero License)

I had a really tricky problem I had to solve in an application I'm developing and, after a LOT of trial-and-error and redesigns, I finally came up with a solution that worked and was somewhat safe from future developer unintentionally breaking it while maintaining related code. However, it was pretty unintuitive and I was very concerned that other people reading the code (or me reading it in six months) would not be able to easily wrap their heads around what the code was doing, thus there was a high risk of it getting incorrectly modified in the future.

So, I sat down with another senior developer on the project to go over the code and look for ways to improve the readability without sacrificing the ability for the compiler to find issues at compile time. After reviewing the logic with him, he made this statement:

"I don't think I would have ever come up with that solution."

Hmm.. To which I replied "Is that a good thing or a bad thing?". His answer (which I anticipated): "Both, I guess".

Now this is a smart guy, and I value his opinion a lot, so this response is a bit concerning and in part for the reasons I feared.

Why is this a good thing?

Well, I found a solution to a problem that needed to be solved. Straightforward enough. And it was a tough problem. So the "I wouldn't have come up with that solution" in this context meant (in his words, paraphrased): I would have just given up and not solved the problem.

Then, why is this a bad thing?

The solution was pretty complex, and used some parts of the .Net framework many developers are unfamiliar with (invoking methods via reflection, loading multiple instances of an assembly, cross-AppDomain communication), so you have to have a decent grasp of the underpinnings of .Net just to read it. And, the API for those areas of the framework are not pretty to look at -- with lots of object[] params, casting and the like. This means that not just anybody can jump into this code and "just get it", which puts it at a high risk of latent bugs being introduced, increases the cost of maintaining the code, etc. To me, this is very bad.

Given the amount of effort required to come up with this solution in the first place, I had already weighed the cost of the solution against the value and determined that the functionality really was needed in the long run and thus it's value out weighed the risk this code posed.

But after discussing with my coworker, I decided to take it a bit further and "dumb down" the code as much as possible. So I did the following:

  • made sure variable names were extremely useful in describing what they represented. This is particularly true for MethodInfo instances and delegates where the type is something like Action<Action<string, string[]>>
  • moved particularly confusing code into small, well-named methods (some with just a single line) to make the code's intentions easier to understand.
  • removed some "syntactical sugar" and replaced it with more verbose (ie: more descriptive) alternatives -- such as replacing some LINQ with foreach loops, etc. In many cases, I find LINQ to make the code more readable, but when combined with other confusing aspects of the framework, it can easily muddy the waters.
  • added meaningful comments to the code. I try not to rely on comments, since I've found that developers rarely read them, they quickly become stale as developer modify the code without modifying the comments, or use tools like ReSharper to automate the modifications. But this is a case where inline comments are helpful.

Ultimately, I am much more concerned about the long-term maintainability of this project's codebase than the "hey, look at this cool trick I did" aspect of the solution. This particular project is in a codebase that is rarely changed, but when it is, it's usually urgent. There's a need to keep things clean and compartmentalized enough that any developer, especially one who hasn't worked in this particular codebase before, to just jump in and fix things.

Maybe I over thought this, but I'm hoping the next guy who has to look at this code doesn't have to think about it much. If that's the case, I'll feel like I did my job today. And if I'm that future guy reading the code, I'll have saved myself some "what was I thinking?" grief :-)

Photo credits: David Goehring Creative Commons License - Some Rights Reserved