When I was in college (and we aren’t exactly talking about yesterday) my computer instructor – who had years of practical experience under his belt – was adamant on one point: If we passed in code that smacked of job security programming, he would cut our grade in half. His message was clear, that our code needed to be logically and clearly expressed because some day other people would need to update it, and in order to do so they would need to understand what they were looking at.
It was obvious that my instructor had been frustrated by code that was unnecessarily complex during his career. Furthermore, he attributed much of this complexity as both unnecessary and deliberate on the part of the developers who wrote the code, with the conclusion that the developers were making themselves “indispensable” by deliberately convoluting the code.
I’ve seen my share of difficult-to-understand code over the years. In my opinion, some people have the specific intent of playing the job security game. In other cases, people are almost too smart for their own good. They have a lot going on inside of their heads, and while they do a great job of keeping a mountain of variables and conditions circulating around their brains, the resultant expression of logic is almost diabolical. Yes, the code works, but it takes a great deal of time and an extraordinary intellect to unravel the intricacies of their logic.
In other cases there is an inexperienced or less than capable programmer involved. And this programmer hasn’t thought the problem through before coding and ends up throwing code at the problem until he or she can get it to work, making one heck of a mess in the process.
As a manager, if I find that we’ve missed a code review that should have prevented problems like this from making it into the production code, I’m upset! Maintainable, understandable code is a BIG deal. Allowing poor (difficult to maintain) code to find its way into the code base will drain your productivity later. I want code reviews to serve as a gate to prevent problems from making their way into the code. As part two, I’ll work with the individuals to improve or change their game, reducing the instances of poor code from being produced in the first place.
I’ve seen other problems with code, problems that have their roots in inappropriate design. One example from my own recent experience occurred when I dove into a complex issue with one of our Windows®-based applications.
The real problem with this code is the fact that messaging is being used and abused. Windows® messages are being peeked, pre-processed, forwarded, and raised – you name it and this code is doing it. Finally, the timing of when the messages are processed is also very important. All of this is being performed in the name of collecting, formatting, validating, and coordinating the (redundant) display of data.
We ran into problems when we needed to extend functionality in a very small way to meet a customer need. As we extended the functionally, we broke things in the process. I ended up working on this issue myself, but every time I fixed one problem, another cropped up someplace else. I refer to this situation as the whack-a-mole problem. As it turns out, two us of independently wrestled with the problem in similar ways and ended up with the same conclusion: Based on the current design, there was little chance that we could get everything running in accordance with the existing design.
I know what you are thinking: re-factor time, right?
Well, we are talking about C++, MFC legacy code here. And this problem is greater than a refactoring effort alone. Refactoring is one thing, completely re-designing and re-implementing is another. In fact, we are in the process of re-architecting and re-writing the business capability that this code supports in .NET, gradually moving key processing to Web Services and browser-based technology. None of this code will be carried forward, and certainly NOT in the way it is designed now.
So I settled for a well-contained, well-commented, two-line hack to get everything running and to make us whole as far as our customers are concerned. It is annoying that this circumstance exists within our code base, but I really can’t justify investing any more time or energy in modifying our legacy code because it will divert resources from our more strategic, stay-in-business efforts.
I cannot state for sure why this code is designed the way it is, since I’m not the one who designed it and I was not a part of the equation when this code was implemented. A design review should have been conducted to prevent this design from ever being implemented. This code resembles instances where I’ve seen technologies and certain approaches used because someone read about something and wanted to try it, which is not a great reason for implementing that something in production code!
This can be tricky territory, but there is a line between staying current and applying what you’ve learned and going out of your way to use technologies or approaches because you want to stuff your resume. As a professional, it is NOT okay to use the company that you work for as your personal software lab.
If you want to explore something, talk to your manager. Work on a side project that is geared at providing your organization with information and a working example of the technology. Or get assigned to a project where utilizing the technology makes sense.
But don’t compromise the maintainability of the code base – a corporate asset – by using designs and implementing things just because you want to learn about them. Be responsible. The use needs to fit the need.
By all means keep learning about technology and the industry. It’s great to know that something exists that might help your specific situation. And if it is an appropriate fit, learn about it and discover the correct way to implement it for the benefit of your project and the code base.
Software should be an organized, clear expression of logic that clearly meets the needs that the software is attempting to address right now. Maintainable software is about using a reasonable structure, one that meets the business need, yet doesn’t try to reach too far into the future. If there is a need for the software design to evolve to meet more complex needs later, evolve it when later arrives, not now.
Designing too far into the future is attempting to anticipate problems that you might not encounter, because the problems themselves might change. After all, requirements are always a moving target, are they not?