Abstract When Needed
I consider myself someone who does his best to learn from past mistakes, but one thing that I continually see myself and others continue to make mistakes with is over and under abstraction. Now I am going to talk about this from a Front End Code perspective, but I feel most of this can apply cross language and stack.
So to talk about over abstraction first, I recently have had the fun of working with a control that was designed in theory to work with any data set given to it. Its first use however was with a rather complex data set, so it is riddled with conditional statements designed to check if the data it was dealing matched the complex data set or if instead it was anything else. The code for handling everything else is remarkably simple but as this code only is currently used against the complex data set we never actually see if the other code works outside of simple unit tests. In addition the code for dealing with this specialized set continues to get modified in the same file as the generic. This has made development a real pain against any new features for this “generic” control. The problem with all of this is we have realized way too late that we simply need a specialized version of this control purely for this specialized data.
With this in mind we probably should not have tried to make any of this generic from the beginning until it was needed. Then when/if another data set needed to use this control we could create a generic control that uses the base underlying logic and functionality of the specialized one. This gives us two cleaner implementations rather than one messy one. However, does this line of thinking violate the DRY (Don’t Repeat Yourself) principle? I would like to think that DRY like many things in life is not black and white. Sure you don’t want to have duplicate code, but we also want readable maintainable code so I think DRY can bend at times.
Not abstracting until completely necessary can bite you in the end though as well. In the same code base we performed similar functionality to filter on large sets of data on many different pages. This functionality, was roughly the same on each page it appeared, however the types of filters could greatly differ as well as some of the logic that happened after a filter. For this reason we abstracted some root logic but kept each of these separate and repeated a lot of code 10 plus times around the project. When we realized one day how much we were repeating our code we underwent a huge refactor to stream line how all of this worked and to force all of these components to behave the same way for consistency. The overhaul to do all of this was costly and time consuming but it made our development time so much faster after it was completed. If we had followed the abstract when needed principle when we created the second or even the third of these, and began to create a common control to handle all of this we would have saved a lot of time much earlier on and not had to make such a costly refactor.
Knowing when to abstract code and make common functions, services, and components can be very difficult and is one of the biggest decisions we as Software Engineers face when we start working on a feature. However taking a few minutes to ask ourselves a few questions can make this a lot easier for us.
Does this functionality exist anywhere else in the application?
Yes) If the answer is yes can we reuse the functionality as it stands or with some work can we make it generic to use in both places. If we can we probably should discuss that. If not then it should be asked if it could it be written better to do so or if the use cases are too different.
No) If the answer is no and we are not going to immediately reuse it for an upcoming feature, then this probably should not be made generic at this time.
This is all my opinion though from what I have learned so take it as you will as with most of what I write.












