Monday, March 28, 2016

Circular Dependencies

I’ve been working with relatively green developers the past few months. I’ve been trying to find an efficient way of letting them learn from their mistakes and be creative without damaging the integrity of the product. A lot of times, questions are asked of me that I explain as best as I can on the spot. Sometimes I do a quick search on Google and find a few articles that have been better thought out than my on-the-spot explanation. The other day, a developer asked me why circular dependencies weren’t acceptable. I explained it partway, but I couldn’t find a well thought out writing piece that explained it.

How this occurs

Suppose you have a Data Access Layer (DAL) and your own logging layer for auditing purposes. Inside your DAL, you’ve got a method that is supposed to insert a record into the database. In the event that you add a record to the database, you need to log it by calling your audit logging layer. The logging layer will accept the request, and try and log it to the database using the DAL.
Now you’ve got a problem. What if the method that was initially called in the DAL is now the one that my logging layer is calling? You’re going to go around and around in a circle.

What I saw

The project I inherited has been worked on for many years by over 100 developers of different strengths in their skill set. One area that I come across frequently is how projects are referenced. Rather than adding a reference to the project itself, developers add a reference to the DLL in the Bin. Sometimes this works, other times I would have to hit Build multiple times to get a complete build. The developer was getting around the circular dependencies problem.

This can “work” based on the build order. Visual Studio helps out as best as it can, but it cannot help out with references to DLLs directly. Projects references need to be added correctly for Visual Studio to help you.

How do you solve this problem?

The example above will never end. It violates the Single Responsibility Principle. The Single Responsibility Principle states that each object will be responsible for only one purpose. There should be only one reason to change the class. While I try not to go overboard with SOLID design, this is an example where you have two different layers that need to be called by a middleman.
Create a layer that calls the DAL directly. In this newly created layer, also call the logging. This prevents you from creating a circular dependency.

Each object now will follow the Single Responsibility Principle. The DAL only puts things into the database. The DAL does not care about logging, who is calling it, or what happens next. The Logging Layer will allow for other middlemen to call it, and it will behave the same way. It can log using the DAL if it wants, or it can call a web service, or log to the file system. Finally, the middle man is responsible for making sure that both the DAL and the logging are called. The middle man is responsible for the order of execution, but it does not care how either the DAL or logging occurs, just that it occurs. Each layer only has one reason to change.

No comments:

Post a Comment