I'm designing a re-usable class library that contains 2 assemblies (amongst others) named core.xml.dll and core.string.dll.
The xml assembly references the string assembly in order to use some string helper methods.
However now there is an string method that would be benefit from using a method contained in the xml assembly.
If I reference the xml assembly from the string assembly I will have created a circular dependency and will be unable to build both assemblies from source code. (ie chicken and the egg problem).
In order to follow the "Don't Repeat Yourself" principle I would like to avoid duplicating the functionality in both assemblies. If I find a bug in the implementation I only want to fix it in one place.
While I could merge the assemblies into one, this is not ideal as it reduces the cohesiveness of the assembly.
I would need to re-build and re-deploy the entire assembly just for a small change to a specific class. Also, eventually, with so many dependencies I would probably end up with one huge library assembly.
So in the context of a re-usable set of library assemblies what is the best approach to use here? Also, how does the .NET framework itself deal with this issue?
(In Reflector it appears that System.Configuration.dll references System.XML.DLL and vice versa. Is this actually correct, if so how is the circular dependency managed?)
In software engineering, a circular dependency is a relation between two or more modules which either directly or indirectly depend on each other to function properly. Such modules are also known as mutually recursive.
Circular dependencies also make code difficult to read and maintain over time, which opens the door to error-prone applications that are difficult to test. If circular dependencies proliferate an architecture, any changes to a single module will likely cause a large ripple effect of errors for others.
Avoiding circular dependencies by refactoring Circular dependencies create tight couplings between the classes or modules involved, which means both classes or modules have to be recompiled every time either of them is changed.
To resolve the circular dependency, you must break the loop by replacing the dynamic reference to the bucket resource.
Agree with Knives. Circular depedencies is a design smell. Refactor it Mercilessly!
This can be challenging in the case where business objects are tightly coupled. In most cases this can be solved through dependency injection.
Pseudo C++ Example:
class Employee {
Company company;
};
class Company {
vector<Employee> employees;
};
Tricky? Not neccesarily:
template<class CompanyT>
class Employee {
CompanyT company;
};
class Company {
vector<Employee<Company> > employees;
};
More primitive types, which must depend on a higher level, can be abstracted to work with any sort of other type, so long as it fulfills its contracts.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With