Do you need circular links?

I inherited a Visual Studio solution that contains numerous circular references between projects.

Is there ever a situation where this is remotely acceptable?

Just trying to confirm my suspicion that this application was created horribly. Thanks in advance.

+6
visual-studio circular-reference circular-dependency
source share
4 answers

I once read a column where they compared 3 types of models: the spaghetti model, the Lasagna model and the Ravioli model.

In the Spaghetti model , all the code is interconnected, there is no clear structure. This is terrible, and we can probably all agree to it.

In the Lasagna model, the code is divided into different levels, and only a level of a higher level can refer to a level of a lower level, and not vice versa.

In the Ravioli model, code is grouped into smaller modules. Each module provides only what needs to be disclosed, but each module can access all other modules.

About 10 years ago it seemed to me that the Ravioli model is better than the Lasagna model. After all, in Java you also have Java modules that can easily call each other (and I got the impression that there is no real structure between all the different Java modules). For me, the Lasagna model seemed to be the result of a non-object oriented old code, while the Ravioli model seemed more modern, more object oriented.

Currently, I usually return to the Lasagna model, but with a built-in Ravioli model. It:

  • The application is built using different layers, for example, in the Lasagna model
  • But inside the layers, the code is still split between different modules that can access each other, for example, in the Ravioli model.

Some circular links may be difficult or impossible to delete. An example is the following: Suppose your application has a FileWriter class and a Debug class. The Debug class will need the FileWriter class, since it needs to write files with debugging information. On the other hand, the FileWriter class can also use the Debug class.

Note that the circular reference in this example may already lead to problems (the FileWriter class can call the Debug class when writing a string, but the Debug class uses the FileWriter class to write debugging information, the result is a stack overflow).

In this case, the problem can be easily solved without using the FileWriter class in the Debug class, but using the native iostreams (if you are developing in C ++). In other cases, the problem can be solved much more complicated.

+8
source share

Good software is developed in layers with clearly delineated boundaries between them. i.e.: if you have a layer, you must clearly understand what it does, why it is, and what it depends on. Circulars make it difficult to achieve this goal and, as a rule, must be removed. (Microsoft spent a lot of effort in Windows 7 to improve Windows partitioning by removing Circularities.)

Just trying to confirm my suspicion that this application was created horribly.

This would certainly support this theory, but IMO, you will need more than just a few circular links to make this conclusion.

To answer your initial question: yes, circular links may be helpful from time to time. Mutual recursive functions are a good example of this kind of thing. However ... that the circular link is safely hidden in the module. For intermodular dependencies, a cyclic dependency usually means that your code is improperly distributed modulo, and this may require some significant refactoring. (Including new types of abstractions to bridge the gap, etc.)

+2
source share

Specifically, I would recommend using NDepend to detect and avoid dependency cycles .

alt text

Excerpt from article (I wrote): Dependency of component components to get clean architecture

Dependency cycles between components lead to what is commonly referred to as spaghetti code or confusing code. If component A depends on B, which depends on C, which depends on A, component A cannot be developed and tested independently of B and C. A, B and C form an indivisible unit, a kind of supercomponent. This supercomponent has a higher cost than the sum of costs compared to A, B and C due to the inefficiency of the large-scale phenomenon (well documented in Software Estimation: Demystifying the Black Art by Steve McConnell). Basically, this means that the cost of developing the indivisible part of the code increases exponentially.

This suggests that developing and maintaining 1000 LOCs (Lines Of Code) is likely to cost three to four times more than developing and maintaining 500 LOCs, unless it can be divided into two independent pieces of 500 LOCs . Hence, a comparison with spaghetti, which describes confusing code that is not supported. To streamline the architecture, you need to make sure that there are no dependency cycles between components, but also make sure that the size of each component is acceptable (from 500 to 1000 LOC).

+2
source share

Circular references to projects are a sign of poor design and should be removed, if at all possible.

The only excuse I can come up with for maintaining a circular link will be a backward compatibility issue. Even then it seems that it can be fixed using type forwarders and another assembly

+1
source share

All Articles