Mostly back to the basics. Single Responsibility Principle, loose coupling, making general, reusable code by finding the balance between abstract and too abstract.
I have become a big fan of a functional, side-effect-less style, since reasoning about smaller, self-contained pieces of code is easier.
If I have to write code that shares state (like a database), I try to make sure that the coordinating pieces are scoped. For example, even if there may be only one database for an app, I write the code as though there could be an arbitrary number of them. I find this helps prevent strong dependencies from creeping into all parts of the code base.