The biggest change to my coding style in the past few years has been to opt out of the most expressive solution if it will fall apart in a cut-and-paste situation.
Many new features are variations on old features. The incremental cost of implementing one so that I can cut and paste the next half dozen is small. The cost of refactoring to a generalization after that is also small. But the cost of poorly generalizing early and having to reimplement feature one and everything it touches in order to make feature two possible is quite painful.
This becomes more obvious when you have different codebases with similar features that might want to share from time to time. A formally generalized solution becomes a big dependency, as it relies on a heavily specified problem. A slightly too primitive solution flows between codebases freely - plug in new primitives and it runs.
Many new features are variations on old features. The incremental cost of implementing one so that I can cut and paste the next half dozen is small. The cost of refactoring to a generalization after that is also small. But the cost of poorly generalizing early and having to reimplement feature one and everything it touches in order to make feature two possible is quite painful.
This becomes more obvious when you have different codebases with similar features that might want to share from time to time. A formally generalized solution becomes a big dependency, as it relies on a heavily specified problem. A slightly too primitive solution flows between codebases freely - plug in new primitives and it runs.