A couple things generally strike me when I approach a codebase -
Abstraction - will allow code reuse in many parts of an application or difference services.
Decoupling will remove dependencies between blocks of code.
For me, this is a good candidate for refactoring exercise. At the start, it can be difficult to visualize where a meaningful abstraction can happen.
When an application is in a mature state then it will be easier to see where abstraction can add value.
A few signs of bad abstraction;
code requires maintenance
code is only used once
code has a complex configuration
code requires complex set-up for testing
A great post on this is ‘Duplication is far cheaper than the wrong abstraction’.
Decoupling can promote reuse but that is a common misconception that it is the goal.
Decoupling is about making parts of a system independent from one another. There are many good reasons to do this;
should help to make parts easier to replace
should promote smaller code sets
suited to microservices
Decoupling often happens by design, making good choices will help avoid coupling.
Doing things like
MVC application patterns
These promote the idea of code independence which should also make for maintainable code.