A common problem I’ve seen is programmer writing code before they understand the problem. This is common when fixing bugs. But, it can end up making the code more complex, and more difficult to understand in the future.
For example, a user reports a bug and the source of the bug is tracked down to a specific function. Then, instead of trying to think of the general principle behind what the function is supposed to do, the programmer adds another “if” or “else” to cover the specific problem they encountered.
Eventually, this can lead to long functions that have a dozen or more possible path through them. The next time someone needs to modify that function, they need to make sure their change doesn’t break any of those paths.
Another source for this problem is when someone starts detailing a technical-driven change to a program, instead of a business-driven need.
There are times when systems need to be changed, due to technical requirements. Maybe a library is no longer supported, and the program needs to change to use a different library. Maybe there’s a security problem that needs to be fixed. Maybe the business has grown large enough that scaling is a problem.
But there are also times where programmers want to work with a hot new technology and use that as a “need” to change existing, working programs.
The latest place I’ve seen this is with the tech-driven “need” to convert from “monoliths to microservices”. Microservices definitely have a place. But there are many situations where the monoliths are running fine.
In one case I personally saw, the problems the development team had were related to bad development and deployment practices, not the size of the programs. Adding microservices to their environment was just going to compound the problem by creating more poorly-written, poorly-tested, and poorly-deployed applications in an unstable network environment. But “monoliths to micro-services” was the hot buzzword, so that’s the direction the team went.