I once read a column where they compared 3 kinds of models: the Spaghetti model, the Lasagna model and the Ravioli model.
In the Spaghetti model, all the code is interlinked with each other, there is no clear structure. It's horrible, and we probably can all agree on that.
In the Lasagna model, the code is divided in different layers, and only a higher-level layer can access a lower-level layer, never the other way around.
In the Ravioli model, code is grouped in smaller modules. Every module only exposes what needs to be exposed, but every module can still access every other module.
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 which can easily call each other (and I had the impression that there was no real structure between all the different Java modules). To me, the Lasagna model seemed the result of non-object-oriented old code, while the Ravioli model seemed more modern, more object-oriented.
Nowadays, I tend to go back to the Lasagna model, but with a Ravioli model built-in. This is:
- The application is built using different layers, like in the Lasagna model
- But within the layers, the code is still split up in between different modules that can access each other, like in a Ravioli model.
Certain circular references may be difficult or impossible to remove. An example is the following:
Suppose you have a FileWriter class in your application and a Debug class. The Debug class will need the FileWriter class since it needs to write files with debug information.
On the other hand, the FileWriter class may also want to use the Debug class.
Notice that the circular reference in this example may already lead to problems (the FileWriter class could call the Debug class while writing a line, but the Debug class uses the FileWriter class to write the debug information, result: stack overflow).
In this case, the problem could be easily solve by not using the FileWriter class in the Debug class, but to use the native iostreams (if you're developing in C++). In other cases, the problem might be much harder to solve.