In a recent post to his site Matthieu Napoli looks at some first steps you can take to help decouple packages in your application. He describes a few considerations and methods to think about as you try to break those chains.
Decoupling packages is a hard thing. There are not a lot of options, and this blog post is about how some options are better than others.
Let’s say for example that you are writing a “package”, or library, to respond to HTTP requests (that kind of package could be considered the basis for a web framework). How do you handle routing? If you write your Router package as an independent package (which is good: small and specialized packages are more reusable and maintainable), you might not want to couple the HTTP package to the Router package: you want to leave users free to choose the router of their choice. So, what are your options to make the HTTP package and the Router package decoupled from each other?
He looks at a few different approaches including focusing on event-driven programming or splitting things along "edges" and making interfaces/adapters to hook them together. He also puts an emphasis on standardizing interfaces, even those outside of your own internal to the application (think the set of PHP PSRs).