Finding the line between ease of implementation versus long-term considerations for maintenance and refactoring is probably the hardest thing to fine-tune over the course of a developers working-life. The singular skill that a novice developer lacks, the knowledge of when to move this line is an important fact to understand.
One crucial fact you must understand is that this line is not static it can move depending on many factors. Let’s delve into some situations where ignoring long-term planning may be beneficial.
When a feature is intended to be short-lived
There are many times when a request from business owners come down the pipe and it is fairly obvious that the feature will be short-lived or is intended to be in place for a short period of time. These can be for optimization tests, one-off client requests or to solve some pressing need.
In these situations sacrificing a good design outweighs the overhead of over-architecting a solution that is volatile. Good code is not your only concern - you are also responsible for appropriating your time correctly. It would be a waste to spend hours designing a nice system for a feature that lives for a month or is drastically altered after a short period of time.
When the cost of creating proper ownership is too high
There are many times when a new feature is similar to an existing one but dissimilar enough that it could potentially live on its own. In these cases it may make more sense to add the new feature where the existing one lives since the maintenance of that existing system is known by the developers. Creating new paradigms for a less-than-compelling reason can be more trouble than it is worth. Sometimes familiarity is more important.
When you are not in control of the timing
Less face it - ultimately we are here to serve business needs. On occasion the timing of a feature is so critical that there is no extra time to develop a feature as we normally would. I would contend that if this is happening on a regular basis that the business process needs to be changed but it is to be expected that timing can be out of our control sometimes. The last thing you want to do in this circumstance is to take on more work and have no time to see it through properly.
Your responsibility is not over
In these three examples I proposed situations where it can be okay to bypass good coding practices but that does not mean you are off the hook. In any of these examples the decision to sacrifice good coding practices must be expressed, discussed, and documented so other developers coming across the code can be made aware that there are specific reasons for it being there.
Upon merging tickets should be placed in advance for future refactoring or analysis efforts so these things don’t become forgotten. Having to constantly think about your code structure is good for the overall health of your project and the team being held accountable for their decisions will make everyone make these decisions with the care they deserve.