2

Let me begin by stating I have already reviewed the following related questions, and just wanted to showcase the software architecture which I have inherited to see how opinions may vary.


So, I have inherited a highly interdependent C++ object oriented application. The original software was written by a single developer (contractor) with no oversight, and is roughly 10 years old. The company has traditionally been more hardware oriented, and the software product was designed to replace purchased third-party controllers, and give us a leg up.

I have been with the company roughly 2 years, and was originally brought on to assess the existing software, and potentially re-design. My first approach was to suggest a potential incremental refactoring. Now working with the company and understanding the products better I have come to appreciate the need of a good modular software and hardware design to support a myriad of hardware combinations utilized.

From a product perspective the company attempts to operate in a very agile environment (need to make changes quickly and gracefully to support specialized customer needs). The current software attempts to accomplish this through the use of configuration value controlled logic which significantly muddies the software, makes it bug-prone, and highly interdependent. There were never any unit tests written for the software, so the validation process consists of testing any new software on as many representative hardware variations that the group can get their hands on.

The test group is fairly rigid, given the interdependent nature of the software, that for any single change they need to re-test everything. To give you an idea of the interdependence I have attached a class inheritance diagram below.

Nightmare of Multiple Ineritance

As you can assume, this structure is a nightmare to maintain. I suppose I'd like to hear from you if you have ever encountered an architecture such as this as I tend to prefer single, linear inheritance models. It appears that the original developer utilized inheritance for functional augmentation, rather than creating members, or allowing access to other class pointers to provide the additional functionality, it was done through multiple inheritance, sometimes inheriting from up to five parent classes.

The current software is deficient in many ways. It cannot support the functional growth that the company requires. In one part this is due to current developers knowledge of the existing software, and is otherwise due to the fundamental architecture (data and execution flow). It also has areas where it is highly inefficient. Over the past two years it hasn't been uncommon for me to find busy loops, nested (5 times) for-loop structures, and poor timing functions. I have worked to improve these as I have identified them, but this type of design error is consistent in the software. It is also not only multi-threaded, but many-threaded with poor data synchronization where it even exists.

So what are your thoughts?, have you ever had to work through a similar problem?

To give you a little insight; I have been working in the specific industry in which I have encountered this problem for nine years, so I have a reasonable understanding for the requirements of the software product, and could manage a re-design as I believe is required. I have grown into a software architect through professional experience primarily over the past 5 years, so this is my first experience with a major re-work problem.

TL;DR Have you every seen an inheritance diagram like this?

Edit 1:

@gnat, Thanks for the duplicate suggestion, great description provided by @haylem and others there in the popular answer. Another unfortunate aspect of the existing software is that when I came onboard there was very poor revision control over the software, and inconsistencies in the build system. There was definitely no continuous build system in place. I have at least transitioned the scm to Git (GitLab) rather than SVN (mainly just a personal preference, easier to visualize the software), implemented a CI system with Jenkins, and helped establish development, and specifically commit rules.

One other aspect of the program that I had not previously mentioned is that the inheritance diagram you see is for the "core" software element. The software suite consists of this as its foundation, and 40-50 dynamically loaded libraries to augment the system.

In a plan to re-architect there will be hard rules for software unit testing which will be integrated into the CI system. I have not yet gotten a continuous inspection running, but that is on my list of improvements to investigate as well.

3

I went through something like this early in my career, with a shelf strip printing tool. The solution I took helped to limit the risk was the following:

  • Create interfaces (pure virtual classes) to limit interactions between the major pieces (in my case the template reading/writing and the printing engine)
  • Select one of those blocks of code for the rewrite--maintaining the contracts around my interface
  • Test the integrated solution

So while a complete rewrite would take multiple years, the most critical section that needed a rewrite to support new features took 4 months. That was acceptable to management.

The key to a successful rewrite is finding the places where we can at least put logical separation, and then limiting the scope of the rewrite to a chunk that management is comfortable with. At some point, things will be "good enough" for management. Just remember to keep these targeted rewrites tied to satisfying a business goal.

  • interesting to hear your story as well. I am pushing more in the direction of re-write due to the interdependent nature of the software as well. As you can see from the class inheritance diagram it is very difficult to introduce interface layers into the existing software. That, and the many deficiencies that the software currently has makes things more problematic. – vectoralpha Jul 21 '17 at 16:23
  • Due to firewall issues I can't see the diagram (everything on imgur is blocked). The hardest part is introducing the changes needed to introduce those interfaces, breaking the static accessors that side-step the design etc. I was lucky enough to have a few places where I could do that intelligently. You might not be able to introduce the modularity up front, but it helps to have a target design. Come up with a plan that makes sense for your project. The key is to limit your rewrite to give you the biggest reward for moderate effort. – Berin Loritsch Jul 21 '17 at 16:35
  • Sorry to hear about your firewall problems. In case you haven't had a chance to checkout the graph outside of that restriction I put it on google drive, here is a link to check that out. I am working on an intelligent modular design that allows the scalability that my company requires. There isn't a lot of software in the current system that is worth re-using in a new architecture. So a lot of what I am planning on implementing will be new. – vectoralpha Jul 25 '17 at 14:05
1

I was in a very similar spot as you inheriting a C++ project depending heavily on MFC libraries. Every change required to be made to the program were edge cases and customizations for specific clients, and many of the changes were rushed and not carefully considered as the programmers that made the changes were often dealing with multiple projects and couldn't dedicate the time or attention it required.

Fast forward 15 years later, I was put in charge of the project. Several times I tried to push the idea of rewriting it, even to the extent of working on it when there was no other work to be done. However I quickly came to the realization that if the program was going to be anywhere near offering the type of functionality as the original, it would require years of dedicated work. Putting that into perspective, assuming I did nothing but work on the project, it would still take me years to finish, and work often did come up in the meantime.

So for the company to seriously undertake a project like that, they'd essentially be losing me as a valuable resource for several years or else it would take decades for me to do the same work if I only worked on it when no other work were available. In short, it would never be cost-effective to rewrite the program, as much as I would have wanted to. Technical debt is a real issue and if nobody addresses it during a project's development, you wind up with situations like this.

My advice to you is to seriously evaluate the time it would take you to get to something close to a useable rewrite, double that time, and then if that time is still a reasonable amount of time to propose to your boss, feel free to do so. My guess is that it would still not be reasonable. Even if it were, the company doesn't stand to gain anything other than the removal of technical debt on the project, which is difficult enough to explain to the boss, much less justify.

  • Thanks for your response. I am fortunate enough to have the backing of my boss. The company is generally fed up with the complexity of the software, and it is significantly over complicated for the supported feature set. The main buy-in for a re-write is to have the software be much more flexible. On a side-note, the inheritance graph depicted above is all custom software, there are no third-party, or standard library objects in that graph. Good to know that someone else has seen a project like this before. – vectoralpha Jul 21 '17 at 13:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.