This may come off as a bit confusing, but it's a question that I keep finding myself asking as I pile on more and more responsibility to older systems and features that I designed previously. Trying to get to the gist of my question is a bit difficult, but I'll try to illustrate it with some examples.
A couple of years ago, I was tasked with creating a highly customizable menu editing system for our site. This menu editing system was designed with one very specific purpose, and that was to allow end users to configure custom navigation menus for specific user roles in the system. The system wasn't overly complex, or overly robust, but it was functional enough to handle every possible use case we could imagine for creating a new navigation menu. We built all of our custom logic and special handling in. We wrote hundreds of lines of code to suit our specific business rules for this piece of functionality, and we shored it up.
About a year after building the site menu system, I was tasked with developing a dynamic menu system for our mobile application that allowed us to create custom menus based on the company that the user worked for. This new system was very similar to the old system, and we decided that it was best to reuse the site menu tables and functionality. All we needed to do was expand them slightly, and they mostly suited our need. However, there were still some major differences, those were:
- The mobile menus did not exclusively use Font Awesome as their icon like our website menu did. Instead, it used images that it fetched from a static location on our web-server. It also allowed custom images to be uploaded and stored in the database. So now we needed to check if this mobile menu item populated the url field or the file field.
- The mobile menus were based off of the user's company rather than their assigned role in the system. This rendered our MenuRoles table useless for this function.
- The mobile menu didn't navigate to different pages on our website. Instead, it corresponded to certain actions in the application, but it could also launch a webview for a custom URL. We mitigated this by making an actions table and including a URL field.
Now, to avoid cluttering the main menu table with excess columns, I built another table called MobileMenuItem
that referenced our MenuItem
table. This mobile menu item table housed all of our extra columns, and we simply put in code to ignore the irrelevant columns in the original MenuItem
table. Not too big of a problem.
Next we had to update how the menu permissions were checked. Fortunately, over the last year, we also built an incredibly robust FeatureSet
function that can hierarchically check through many many different scenarios to determine which features an individual user had access to. Unfortunately, it was originally designed to simply determine if a user had access to a specific feature. These features were simply a string in the database that we accessed through constants in the code, and the algorithms we put into place merely spit out a true/false as to whether a user had access to that feature.
Fortunately, a few months prior, we had customized the feature set system to be able to fetch strings from a resource table based on which features a user had access to and which individual features had been overridden. But again, this system wasn't quite the right fit for fetching the proper menu as we were fetching strings, not menu references. So again, we adapted the system to be able to handle menus as well. Again, disregarding previously implemented features and having to code around what we had built before.
In the end, this lead to a series of 3-4 unrelated systems that were just similar enough to reuse some portions of their functionality, but we broke the specificity of those systems in the process.
So I'm sitting here today, building a 3rd Menu Editor
that customizes the home screen of our site based off of custom companies (much like the mobile application). However, it is just different enough that I have to modify the original MenuItem
table to include many properties that were included on the MobileMenuItem
table. So now I'm left with 3 unrelated menu editors with columns that are ambiguous between tables, logic that is specific to each individual system, and spaghetti code as far as the eye can see.
So my big question basically boils down to, what is the right approach? Should you completely decouple your features of your application, even though they are incredibly similar? Should you basically have potentially dozens and dozens of nearly identical tables and algorithms even though they they are only just slightly different.
Or, should you attempt to reuse as much of your other systems as possible?