Well, you are probably are already aware of the long discussion that I had about it. Patrick was kind enough to help me get to the actual information that I was interested at, and now I can try to talk with concrete data.
The post is based on skimming the following matrix:
But the reason that I am skimming is that the matrix size is just too big to really go over by hand. The matrix is showing dependencies between different types.
Here is an area that seems to be rich in cycles:
Let me list them out for you:
- FutureCriteriaBatch and FutureQueryBatch have a cyclic relationship with SessionImpl. There isn’t a problem here, since they are considered to be friend classes, they would probably have been defined as inner classes of SessionImpl, if that class wasn’t already big enough. So we consider them to be part and parcel of the same thing, since they are tied together very tightly.
- SessionFactoryImpl have cyclic relationship with SessionImpl and StatelessSessionImpl. Again, we don’t consider this a problem, those classes are tied together by the nature of their existence. SessionFactoryImpl have to be able to create the sessions, and they need to access it to be able to touch everything that isn’t session scoped.
- MultiCriteriaImpl has a cyclic relation with SessionImpl for much the same reason, SessionImpl is its creator, after which it is using SessionImpl to do a lot of its work.
- CritertiaImpl and its inner class, CriteriaImpl.Subcrtieria are also listed as a cycle. In this case, again, I don’t have an issue. Especially since inner class relationship already have the concept of a cycle in it.
Here are a few other snapshots:
On the face of it, it looks like a lot of cycles in NHibernate.Type. But again, digging a bit deeper, we can see that there is actually a good reason for those. Customer types needs to be able to create additional types, and it is no great surprise that they use the TypeFactory to do so, or that the TypeFactory can also create them.
Another matrix that looks bad at first glace is this:
Except that every single one of those cyclic dependencies are between a parent class and an inner class.
Now, I don’t want to say that there aren’t cyclic dependencies in NHibernate that shouldn’t be there and need to be removed. But on a(n admittedly short) study, I wasn’t able to find a such a case. And the cases that I found had pretty good reasons for behaving the way they do.
Another observation worth noting is that NHibernate is structured using a recursive spoke and wheel approach.
What I mean by that is that we have different types of components all doing their own specific task, and then we have what, for lack of a better word, I’ll call orchestrators, which manager a bunch of those components and how they work together.
This continues on recursively, we have orchestrators for orchestrators, until we end up at the pinnacle, with ISession and ISessionFactory.
This design make it pretty easy to add new functionality along existing lines, and adding entirely new functionality is just a matter of deciding where to put things.
One of the things that I most like with NHibernate is that so many features can be implemented using very high level concepts. For example, Futures were extremely easy to implement, because we could take advantage of all the underlying infrastructure.
An implication of this is that when I need to expose something from SessionImpl, for example, which was built mostly using SessionImpl, I am going to have a cycle.
I suggest taking a look at FutureCriteriaBatch and its association to SessionImpl to look at why we have those cycles. I don’t believe that you will find them to be a problem after you look at the actual code.
Now, let see how big an ants’ nest I kicked this time.
Update: Patrick mentioned in the comments that I should also pay attention to direct & indirect usage. The problem is that I don’t find it very useful, from the aforementioned reasons. For that matter, when I looked at a few of the “trouble spots” with direct & indirect usage, I was still not able to point at something that I would consider a problem.
The graph certainly looks scary, isn’t it?
But the problem is that I can’t find much new information when I dig in. Here are a few examples:
We already talked about SessionImpl and FutureCriteriaBatch, and it doesn’t surprise me that IType and ISessionImplementor are tied together. ISessionImplementor needs types to do its work, and IType needs ISessionImplementor to access the services that NHibernate offers internally.
Again, nothing that I didn’t know already.
In fact, I’ll go a bit further and say that even for indirect only cycles in NHibernate’s codebase, the things I said above about direct cycles still hold.