“If your code is so big that you need Regions to collapse areas of it, then your code is probably too big and you should consider refactoring it”. – Copied from a forum, where someone was trying to convince Microsoft to remove “Regions” from the next release of Visual Studio
I’m sure everyone has encountered a programming task, where someone wrote a huge page or library or function, etc. and you had to maintain it. This kind-of feels like you’ve been dropped in the ocean at night. You can’t see the shore and it is hard to determine which way to swim. Even choosing to swim west, might be pointless if there is a current going east.
Fundamentally, the concept of refactoring large files into smaller files seems logical. So, when I see a really large file or function, my first inclination is to dive-in and refactor it.
I recall one particular time, when I took a large class/file and started refactoring it. I cut large chunks of code from the file and pasted it into new files and connected them back together by making calls between them. As I did this, I found that some of the code was stateful and relied on local (private) variables and properties. So I had to pass those into the functions that I just moved. As I did this, I realized that it was all becoming tightly coupled.
Once I was done, I evaluated what I had just done: refactoring this class/file took a bunch of time, I changed a lot of code (which added risk) and the finished work was tightly-coupled (not ideal). In the end, the refactored code seemed to work fine. So I guess it was maybe worth the risk. I still wasn’t sure how much value I had actually provided. It could be argued that I added or subtracted value.
So essentially, what I found is that refactoring was not so bad in functional (modular or non-OO programming). You just cut the code in half or in tenths, and you are done. However, in OO, you can’t just split up the code in “an object”. Some of the fundamental nature of OO programming is encapsulation. Encapsulation basically means that your object needs to contain all of its own code and state (variables). Splitting it up is a clear violation of OO principals, unless you are pulling the them into another class, which is independent of the other classes (loosely bound).
Sometimes an object wraps something really big. Sometimes, you can’t just refactor it and make it smaller. And sometimes, when you refactor it anyway, you end up with utility libraries and static classes and functions, that merely spread the mess around and it is no-longer very true to OO design.
Another down-side to this style of refactoring is when you refactor without consolidating any code. In that case, your code seems smaller because you have seventy files that are one hundred lines long, but still have seven thousand lines of code. When you step through the code, you start to get lost in the seventy files that your logic traverses. Good luck keeping track of that. I don’t really believe that it is an improvement of any kind.
The most certain way that you can tell that you have over-factored a function/class is when you have subs/functions where you are passing dozens of parameters into it, or if you have to use ByRef variables (you change the state of a param, rather than returning it as a result from a function). This is terrible and is evidence that your code and logic is fragmented and will be more-difficult to maintain now.
Most developers who encounter this kind of problem pick one answer: “This should be rewritten”. However, all truly experienced programmers will tell you that a rewrite is very unlikely to produce a better outcome. It will just burn through a bunch of time & money.
My point is this: some blocks of code are just big. Before you spend months working on the perfect refactor, think about the ROI that you will get. Just because “the experts are saying it”, doesn’t mean it actually makes sense or is practical in most circumstances. Please get a grip and show some judicious discernment. Then discipline yourself to pick the low-hanging fruit (if there is any). Get that done and then step away from it, and call it a day.
You don’t have to solve every problem. Pick your battles. Know when to be elite and when to be efficient.