Description

The circular dependency problem between Pages and Users is due to each class implementing part of a larger notification feature. Once again this was not obvious when the two classes were coupled together via Singleton instances. Although the Single Responsibility
Principle (SRP) would encourage us to have a separate Notification class, our primary job right now is to disentangle Pages and Users. Once the responsibility for notifications has been moved to one class or the other, it can be separated more easily into
a separate Notification class. Let’s work on moving it to Pages.

We’ll start by adding notification-related methods on IUsers to IPages (we won’t remove the methods from IUsers or Users yet):

The other methods are implemented similarly. We can now look for usages of those methods on IUsers and change them to reference the same methods on IPages instead. The only usages for the IUsers methods should now be by Pages and the IUsers methods can be
removed. You’ll have to temporarily cast the IUsers instances in the delegating methods to Users as the methods no longer exist on the IUsers interface:

Time to pack up the notification-related methods on Users and move them to their new home on Pages.

And That’s a Wrap

Simply by making the dependencies between classes explicit via dependency injection, we revealed a number of circular dependencies lurking in the ScrewTurn Wiki codebase. Circular dependencies between components effectively turn the individual components
into one large super-structure, which is difficult to modify. Changes ripple through these super-structures and resulting in unexpected breakages after seemingly innocuous modifications.

Applying the same techniques to Host’s other dependencies, we remove Host’s use of singletons altogether. (For the curious reader, the code is available for download from
MSDN Code Gallery for Extreme ASP.NET Makeover.) Host’s constructor signature now looks like this:

Its dependencies are obvious in a way that they were not before. Host has a fair number of dependencies, but it is acting as a facade between ScrewTurn Wiki and the plug-ins. So it is not overly worrying.

We can start asking ourselves meta questions about our software:

Do these dependencies make sense?

Should some of these dependencies be combined/split?

How do the dependencies relate to one another and can those relationships be improved?

We can reason about the overall structure of our software and improve it because that structure is more apparent. In the end, our software becomes more flexible, more testable, and more resilient in the face of change.

Acknowledgements

I would like to thank Dario Solera, creator of ScrewTurn Wiki, for being brave and open in allowing me to use ScrewTurn Wiki as the brownfield application throughout this series. He has already taken the constructive criticism provided in earlier articles
and used it to improve the latest builds of ScrewTurn Wiki. Kudos to Dario for permitting all of us to learn together out in the open.

Thank you to my two occasional co-authors, Kyle Baley and Donald Belcham, for their assistance on parts 6 and 7. Your insights were invaluable in pushing the series forward. Dario has agreed to allow ScrewTurn Wiki to be used as the sample brownfield application
for Kyle and Donald’s upcoming book, Brownfield Application Development in .NET, published by Manning. If you want more information about improving brownfield applications, their book is an excellent resource.

A big thanks to Howard Dierking for giving me the latitude and encouragement to take the series where I thought would be most useful and practical. Thanks also to Gary Clarke and the rest of the
MSDN Magazine staff for their helpful suggestions, patience, and quick turn-around while editing the series.

Finally, I would like to offer special thanks to my spouse, Risa Kawchuk, and my two sons, Daegan and Gareth, for their understanding in not having as much spouse/daddy time in the last few months as I’ve toiled away evenings and weekends on these articles
and screencasts.