NHibernate and NDepend – skimming the surface
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.
Another one:
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.
Comments
too much time waste... too much...
With NH3.0 we will see another analysis saying how much bad is the NH's internals when whose working in NH know how much NH is componentized.
In the previous post I saw something about dependency of the namespace NHibernate.Util. For NH the NHibernate.Util is like System and I'm pretty sure that all classes inside NHibernate.Util can be moved in a separated assembly, the same for all events, same for all dialects, same for all Types, same for queries translator, same for.... Who want see NH distributed as 50, or more, assemblies ?
The real NH core is composed by interfaces, of injectable components, and very few concrete implementations (as Environment, Configuration and few others).
One of our problems is collect the tremendous amount of AddIns, AddOns and extensions; if NH would be a real spaghetti code we shouldn't have so many AddIns, AddOns and extensions.
NH2.1.0GA ~1000 downloads in 6 days, NH2.0.1 +70000 downloads in 10 months... many professionals like our spaghetti.
Ok... Now going back to something more productive.
Cycle between types (meaning having types inter-dependent, meaning having types entangled....) is not a problem. Most of design pattern fosters inter-dependent types, outter/inner types can be inter-dependent... etc And here we go again (and for the last time for me, but time is not extensible at whim) the problems come when 2 types of 2 different components are inter-dependent.
Unfortunately in the NH screenshots you didn't use the 'indirect dependencies' mode and this is why the matrix presented are pretty sparses. In 'indirect dependencies' mode a cell is black if the 2 types are inter-dependent (like A -> B -> A or A -> B -> C -> D -> A)
Here is the global NH structure (1456 classes): the black surface shows at first glance that at least 40% of types are inter-dependent:
codebetter.com/.../TypesDSM.jpg
Here is the NDepend architecture (1399 classes): there are some black cells around small squares located on the diagonal. This shows high cohesion inside small groups of types (components). But the matrix is all in all pretty sparse and triangular also. This shows overall low-coupling.
codebetter.com/.../NDependTypesDSM.jpg
All these is based on academic and industrial work like this book:
www.amazon.com/.../0201745720
+the great work of John Lakos:
www.amazon.com/.../0201633620
But the best summary of all these principles has been written by Uncle Bob IMHO and here is the link (a MUST-READ):
www.objectmentor.com/.../granularity.pdf
Also I take a chance here to briefly answer to Jeremy D.Miller that insulted me on twitter because I am defending all these principles publicly.
http://twitter.com/jeremydmiller/status/2761385912
http://twitter.com/jeremydmiller/status/2761400982
Jeremy wrote a lot of good stuffs on high-cohesion/low-coupling, like this article...
msdn.microsoft.com/en-us/magazine/cc947917.aspx
...and when analyzing the work of Jeremy on StructureMap, we see that 75% of the classes are inter-dependent. Where is the low-coupling here?
codebetter.com/.../StructureMapTypesDSM.jpg
There is no debate around the benefits of these componentization principles and as said, I cannot dedicated more time into this debate. Everybody is free to not believe in 2 decades of academic and industrial research on componentization but I would strongly suggest to have a look at all these references.
Patrick,
I updated the post to look at a few of the indirect data as well
Ayende you are arguing that the classes that produce the acyclic dependancies are closely related so it is acceptable. But there is no reason why you can't use the DIP to break these references. Surely that can't be a bad thing? Either way I think the most important thing is that the contributors to the project find it easy to maintain the codebase. That is the litmus test.
Dan,
a) in many cases, it is not actually possible. See IType <->ISessionImplementor
b) what on earth would it give me except unneeded abstraction?
b) what on earth would it give me except unneeded abstraction?
It will give you Low-Coupling.
Such abstractions are needed. They are needed to achieve Low-Coupling between implementations. Because being coupled with an asbtraction is always better than being coupled with an implementation.
Again, Uncle Bob clearly explain all these:
www.objectmentor.com/.../granularity.pdf
Fabio
"NH2.1.0GA ~1000 downloads in 6 days, NH2.0.1 +70000 downloads in 10 months... many professionals like our spaghetti."
Yeah, right. Let's go along this path. How many people use strongly-typed datasets? Many professionals like strongly typed datasets. So they must be GOOD.
You seem to take issue personnaly each time someone dares to say something about NH (an outstanding framework, BTW) which is not pure ecstatic raving. So does Jeremy Miller. I can understand that, since some of the most vocal alt.net proponents are known for their well-balanced and meek comments on other people's work, and it's only fair you should be entitled to be treated the same gentle, reverent way. Way to go Jeremy, way to go Fabio. I can understand how outrageous it can be to have someone utter non-insulting comments about your framework. How dare they?
BTW, Oren's replies are well thought-out, even if it sounds like Patrick and him are somehow talking about different things.
a) in many cases, it is not actually possible. See IType <->ISessionImplementor
And again type inter-coupling is not a bad things when types belongs to the same components.
Having IType <->ISessionImplementor is just a good indication that these interfaces conceptually belong to the same component.
NDepend has gotten enough free advertising out of this now. Spending energy on this is taking away from the excitement of a big release that we all benefit from.
The level of extensibility of NHibernate speaks for itself. If the coupling were as bad as Patrick says that it is we would not be able to extend and write our own implementations for NHibernate interfaces as easily as we can.
I think you're wrong. I don't think spending 2 days or 3 days or even a week after such a major release to analyse and examine the fundamentals as bad, but very useful. I think you should do it as a team to gain insight for the next release and bring everybody in team to same page when it comes to architecture. And I think you should also thank Patrick for doing the analysis for you.
No, in my judgement would create artificial abstraction that would only make things harder to understand.
On this we fundamentally disagree then.
The Acyclic Dependency Principle has an awesome power. Indeed, this principle guides developers on where precisely abstractions must be created to reduce coupling between implementations.
For you such abstraction is artificial. For me it represents the corner-stone of low-coupling. And I can affirm without any doubt that reducing coupling between implementations doesn't make things harder to understand.
I am very disappointed by Jeremy D. Miller and his twitts.
He has been preaching a lot of good practises that can be enforced and verified by a tool like NDepend. There is no best way to make sure you are following these good practises.
The big problem with twitts is that you just have the space for a statement not for elaboration.
However Patrick work and NDepend are highly regarded and the metrics used are very relevant indeed.
There is no doubt in my mind that if your code, library or application does well in the tool, it will be low-coupled, testable and maintenable.
It does help make clear where architecture problems are.
So far, I don't see anything close from a tool like NDepend on the market.
The other option is human judgement and opinions, and this is never rational or a scientific approach. There is habits, difference of understanding, personal preferences...
It is also a good tool also to discover if "gurus" follow what they preach and the recent uproar is a testament to that.
In my experience a cyclic dependency between two components is often a sign that there is some other important concept at work that can be factored out orthogonally to both. Alternately one dependency can be inverted to eliminate the cycle and reduce coupling.
This is not true in all cases certainly but I do find the study of these cycles to be occasionally very enlightening (and occasionally not so much!)
For example, IType may not actually need everything that ISessionImplementor provides or vice-versa. There could be some more general abstraction lurking in the shadows waiting to be discovered here. Maybe all IType really needs is some kind of factory that ISessionImplementor can provide. I can't tell you whether it is worth pursuing but often when I find and adopt such an abstraction the tests become much simpler and require fewer mocks to arrange.
The last time I threw NDepend at Gallio (which is about the size of NHibernate, iirc) I discovered interesting things about the components and ended up rearranging the conceptual layers and pushing the abstraction boundaries around a bit. It took some time to figure out the issues that the tool was really hinting at but I feel that the refactoring that came out of the process has been extremely worthwhile.
You can see an analysis of information to give some conclusion about a situation.
What I'm not agree are that conclusion "spaghetti", "impossible to maintain" and so on...
Do you want see another arbitrary conclusion from the same guy ?
codebetter.com/.../...re-for-software-quality.aspx
IMO when Patrick analyse a software he should write something about how he would solve what he define a problem in that software. Instead Patrick write his arbitrary conclusion and nothing more.
I can respect the guy when he respect me and, over all, our work. I can accept constructive critics but absolutely not arbitrary conclusion as "NH is spaghetti code".
Btw my congratulation to Patrick for his commercial strategy... every time it is working very well.
@Fabio: why do you take offence of things which are simply digged up from the code which is structured according to something you have no control over? (hibernate)
It has already been discussed that nhibernate is structured the way it is because hibernate is structured the same thing. Whether hibernate thus has to be restructured is something we all can do little about.
IMHO you shouldn't take these things so personal. I mean, for every time someone cries out that POCO is the way to go and my own o/r mapper therefore sucks as it promotes anti-pattern XYZ etc., should I take it personal? Take my advice: don't take it personal, look into why these questions are asked, what valuable lesson can be learned and if so: if you want to fix it or not or live by it. You know why the code is structured the way it is and you think it's OK. Advice is given to change it, you then should look into that and take a conclusion: we don't change it because for reason ABC, or yes we should change it because of reason XYZ. That not only learns you to live with criticism better but also you might get valuable advice from it once in a while. It helped me to deal with 'code generation sucks' and 'not using poco is bad' kind of criticism as I know why I use code generation and not poco.
Fabio, when quoting my post it would have been appropriate to quote as well the caution I underlined in bold in the post:
"Notice that I don't claim that this indicator is resulting from a scientific approach (it is not the case). I just found the result interesting enough to be shared publicly. Just take these numbers as-is."
In this post I just share some interesting insights that all other ISV keep private. I wish more ISV would share such info, it would be very interesting. Btw, I wish the NH project could also share this info.
This is not arbitrary. What is the definition of spaghetti code if it is not: A significant portion of implementations are statically inter-dependent.
And in NH, the demonstration that a significant portion (around 40% of the 1456 classes) of implementations are statically inter-dependent is made obvious by this dependency matrix.
codebetter.com/.../TypesDSM.jpg
Realize that 40% of your classes depends on 40% of your code base. Something like 580 classes involved in a giant cyclic graph! From any of these 580 classes you can find a static path to the 579 others and vice-versa! The small cycles exhibited by Ayende is just an epsilon of the problem. Maybe you can justify things epsilon by epsilon. But at the end of the day hundreds of classes are still inter-dependent!
This is not my fault, this is not showing disrespect to shed light on this, it is tangible facts.
Why do you stay on your stance when facing such an obvious problem? Why being so defensive? Why not changing your mind and see the results presented in the analysis as something you can benefit from to reduce overall NH coupling?
@Patrick
You created a software that analizes software based on scientific principles. In practice business requirements drive resource allocation, and leaders have to consider ROI in every allocated man-hour.
You had the resources (developer hours) to stick to your principles while redesigning ndepend, because ndepend's redesign was justified by itself (the proof is the product). Notice the cyclic dependency? ;)
Can you justify the redesign of nh besides anything but your principles backed up in an academic level presented in pretty matrices?
You have to stop thinking binary when thinking about code inter-dependency. There are many shades.
Some of them are: not inter-dependent at all, acceptable inter-dependency, inter-dependent, very inter-dependent, entangled spaghetti code.
Ndepend knows only two colors (literally): not inter-dependent at all and spaghetti code. You only see code through the eyes of ndpend and say: stick to these principle fully, or be fking doomed with your spaghetti hell.
You have to realize that binary ndepend analysis results (black-square-no black square) can't indicate directly how hard it really is to understand, maintain or extend any code base, and how much business value it would give to redesign the code just to make black squares disappear.
Please stop bugging coders of different frameworks, saying they don't practice what they preach, because they write inter-dependent code. Please realize that there are levels of inter-dependence.
Finally, start putting practical, real-world facts on the table: hard facts that show a trend on how ndepend brought business value to companies. 9-10 projects which benefited from making black squares disappear in ndepend, and also how much they benefited approximately (not just an ego-stroking "we feel better about our code") will be a great start.
...scientific principles that I didn't invent. These scientific principles comes from 2 decades of research (academic+industrial). See the references above.
One more time academic is negatively presented :o/
Yes, I am enthusiast on working on a code base extremely low-coupled, completely componentized and layered, where every maintenance task is immediate. My big point is that the Acyclic Dependency Principles (ADP) is extremely efficient in the real-world and is easy to apply.
codebetter.com/.../NDependTypesDSM.jpg
Hopefully I defend (and apply) much more principles than just the ADP, immutability, high test coverage + DbC, small iterations, reversibility...
NH coders are big names. My unique concern comes when they justify 580 classes inter-dependent. Because they are big names, many developers can find here a justification to not care about their own hundreds of inter-dependent classes.
As said above, spaghetti are here when a 'significant' portion of the types indirect dependency matrix is black. The adjective 'Significant' is not binary. But certainly 40% or more of inter-dependent classes is IMHO more than significant.
Who on earth can have an understanding of 580 classes entangled?
Some developers are open to free advices. For example Craig Sutherland leading CruiseControl decided recently to allocate resources to achieve low-coupling in CC.NET.
codebetter.com/.../...e-control-net-code-base.aspx
Indeed there is a case of a big name where:
-he spend his time preaching for low-coupling
-he wrote a code where 75% of its classes are entangled
-he insulted me on twitter
What am I supposed to do in such case?
I usually avoid talking business in a purely technical discussion, especially a polemical discussion.
NDepend has thousands of pro users world-wide.
If they bought the product they certainly find a benefit in it but I refuse speaking in their names.
So here are some more tangible facts:
codebetter.com/.../...-code-in-the-real-world.aspx
+
http://www.ndepend.com/Testimonials.aspx
+
The last one in date: Quote from Jeff Brown above:
The last time I threw NDepend at Gallio (which is about the size of NHibernate, iirc) I discovered interesting things about the components and ended up rearranging the conceptual layers and pushing the abstraction boundaries around a bit. It took some time to figure out the issues that the tool was really hinting at but I feel that the refactoring that came out of the process has been extremely worthwhile.
PS: Guys, all these discussions are as interesting as exhausting. If some-one has something to add please make sure it hasn't been debated above, thanks!
You seem to be hell bent on the idea that it is almost impossible to maintain the NH code base. You seem to neglect the fact explained by Ayende that it's architecture was designed in a way where some inter-dependency is inherent to it, and it's still logical, and understandable, it still makes sense, and he can explain how each component functions and how it could be changed or extended any day.
The NH codebase has neither high nor low component coupling. It has the right amount of coupling.
You have to accept and learn to live with the fact that there is a margin of error to the level of inter-dependency, and IRL you can't measure it based on scientific principles invented for a perfect world, and so the measured 75% of inter-dependency translates to an indicator that may or may not give true information on how hard it is for a coder to maintain a codebase in his day-to-day work.
You warned Ayende about your concerns, he drew his conclusions and answered you in the above post. IMHO now it's your time to reconsider your seemingly unchangeable ideas and learn to accept the fact, that measuring by the academic ADP can not be considered a hard fact when it comes to determining the maintainability of a code base in real-world applications.
It is an indicator, yes, but it may have given false positives in these cases, as explained by the concerned developers themselves.
And to clarify my argument, the testimonies on your site are about all the features of NDepend, and I don't contradict that NDepend has very useful features. It's about you mainly basing your arguments on the ADP.
@Sandor,
So you are saying Low-Coupling is not important and require some kind of proofs for proving it's importance ?
I can't believe you guys are the same guys who keep on arguing about all the benefits of SOLID principles (which includes Low-Coupling as a main effect) and yet argue that those principles aren't needed in nHibernate ?
Proves more concretely that ALT.NET is just about hypocrisy. Everyone should follow(in particular Microsoft!) your idea of software development. But when it's convenient you can change or break the principles.
nHibernate is great product, but that doesn't mean it can't be improved. The fact that Ayende is doing posts on this means it's important and is being looked at. That's good enough to move the product forward.
You need to understand Highly coupled classes aren't "false positives". It needs to be looked at NOW.
This is an attitude that is echoed in a lot of the post around this subject and its sadly misguided. In a perfect world we would have infinite resources and be able to fix all problems (bugs, new features, code structure). However that is never true in the real world. In the real world resources are finite. So the real questions we face are things like: "given 4 hours to work on NHibernate today should I add feature A, fix bug B or refactor classes C and D to reduce cyclic dependencies". Its very very rare that you have such a wealth of resources that you have the luxury of making changes that drive nothing more than code structure. There is always a much greater presure for features and bug fixes.
The practical effect of those pressures is that great teams make structure changes as they touch code to work on new features or fix bugs. That deliver incremental code improvement along with tangible external improvements to the product. IMO the NHibernate team has done a superb job of maintaining that balance.
"It needs to be looked at NOW." is an entirely academic statement. Any development manager that went to their CEO and proposed no new releases or features for 6 months so they could focus on removing all cyclic dependencies would be looking for a new job pretty fast.
@Patrick
I agree with Jon.
This happens when principles are applied in practice. They become intelligently applied guides instead of unbreakable laws.
By your academic standards, yes, NH classes are highly coupled.
By practical real-world standards concerning day-to-day work, they are not spaghetti or brittle to change, their level of coupling is just right. It's not a problem that should take valuable time. Do you value scientific approach over NH down-to-earth developers' opinion?
(I feel I can't add any more to the conversation, so I'll probably just leave it at this.)
I have nothing to add that Dinesh already wrote except one comment on this:
In essence you are claiming that in the real world, 'technical debt' cannot be re-paid because there is always something more urgent to do. Here is what Martin Fowler wrote on technical debt:
"You have a piece of functionality that you need to add to your system. You see two ways to do it, one is quick to do but is messy - you are sure that it will make further changes harder in the future. The other results in a cleaner design, but will take longer to put in place."
(...)
"The Technical Debt metaphor explains why it may be sensible to do the quick and dirty approach. Just as a business incurs some debt to take advantage of a market opportunity developers may incur technical debt to hit an important deadline. The all too common problem is that development organizations let their debt get out of control and spend most of their future development effort paying crippling interest payments."
oh and I forgot:
And one more tack at academic. Did you guys really feel that the job of the academic world is focused on disturbing developers from getting their job done?
Aren't most of successful concepts that we use today invented by academic? (object, relational DB, functional, parametric polymorphism, compilers, DbC...)
How can you both use all the goodness coming from academic and permanently present academic as a world where people doesn't know what is it to code in the real-world?
Patrick, you continue to misread or misinterpret what people are saying in their comments. You said:
"In essence you are claiming that in the real world, 'technical debt' cannot be re-paid because there is always something more urgent to do."
but that is not the essence of my argument at all. Please read my comment more carefully and you'll see what I said was:
"The practical effect of those pressures is that great teams make structure changes as they touch code to work on new features or fix bugs"
So I'm in total agreement with the Fowler quote. The key part of Fowler's quote is "You have a piece of functionality to add" he is NOT talking about making changes for the sake of change he is talking about limiting or eliminating technical debt when you are in there already adding functionality. We are in total agreement that we should avoid incurring adding technical debt as we add of fix features.
However, we disagree on the value of focusing on any given metric in isolation or that simply attacking the problem described by that metric is in itself a practical approach to building.software.
See now your just being deliberately unfair. I never said anything of the sort about the role of academics in advancing software engineering. However, I will say that sticking to 'academic' or 'theoretical' arguments without practical real-world consideration is a mistake and potential damaging idea to up and coming software engineers. Great software engineers (and they are very different from great coders) and great development teams understand that building software involves a continuous set of trade offs. You have to trade off long term vs short term goals, I need it now vs I might need it later, abstract purity of design vs technical debt etc. etc. You have to understand technical debt and you must actively make the trade off. However, that doesn't always mean that fixing technical debt always wins the trade off. Arguing (and I paraphrase) that "Cyclic dependency is bad and must be fixed NOW" does nothing to educate engineers about how and why to make those trade offs in the real world practical situations that they face every day.
Indeed, I misunderstood. But still we disagree on what is the technical debt.
It would be nice that no-one around use the term academic then, because despite your explanations the way you are using it really sounds to me like:
"It needs to be looked at NOW." is an entirely {non-realistic, non-real-world, non-practical, non-pragmatic} statement.
'theoretical' is much suited then, and 'theoretical' is not 'academic'.
"•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. "
Wait you're saying a Factory having a cyclic relationship with the object it creates is not problematic? I guess the rules only apply when you're talking about other people's code not your own.
So the argument is that removing the cycles introduces "needless" abstractions. Heaven forbid someone would want to actually plug in their own SessionFactory without recompiling all of NH. Get real. It's okay to say "We only had so much time and effort" but to defend sloppy code as not problematic because we know how it works or doing so would only create unecessary abstractions that will "make it more difficult to understand"?
What's difficult to understand about a Session taking a dependency on SessionFactoryBase or ISessionFactory? I've seen BS before, but with all the preaching that you guys do about making code more maintainable and the importance of DIP, it's hilarious that you actually think that this doesn't go against every principle you tout.
It's like telling your kids don't do drugs but when they catch you smoking weed in the basement saying "it's okay I know what I'm doing".
Yes, heaven forbid.
Those are not parts that you are supposed to mess about with, not from outside.
Why do you use interfaces for ISession and ISessionFactory while they are not supposed to be implemented outside NH?
Another question is, you do have ISessionImplementor and ISessionFactoryImplementor. And I always thought that interface and implementation are opposites. So, why these names?
Just curious..
@Ulu:
An interface represents the contract (i.e. methods and properties) that is exposed, without saying anything about __how it is implemented. It's a fundamental (though often not taught, nor stressed enough if it is) principal that we should program to an interface, not an implementation ( <citeDesign Patterns, Erich Gamma et al.
Programming directly to a class couples your code to it, and reduces your ability to substitute implementations. If you had a Session object rather than an ISession you'd have no scope to provide a mock instance for unit testing, for instance.
ISession and ISessionFactory are being used outside of NHibernate. Use abstractions, not implementations.
As for the I***Implementor, those are mostly needed because a lot of people want to wrap a session, and that gives them an easy way of doing that.
@Dave
Yes I know that in theory I should use abstractions and program to interface etc etc. I was just wondering about this particular case. Because each "should" has to have valid reasons behind it, and I was wondering whether these reasons apply here.
"reduces your ability to substitute implementations" doesn't apply here, since we're not supposed to implement ISession yourself.
"no scope to provide a mock instance for unit testing" -- I could say that you can always provide a manual stub or use a partial mock. However, as Ayende pointed out, mocking ISession is usually quite painful, and you better use SQLite for testing.
"An interface represents the contract" true in general, but in this particular case the interface evolves over time, so the contract is.. violated?
@Ayende
"Use abstractions, not implementations" -- As I said, in general, I'm totally for abstractions. However, in all NH usage samples I've seen, If I replace ISession for Session, nothing seem to change.
Don't take me wrong, I'm not questioning the quality of code here, just trying to learn by example.
Thanks
Ulu,
It is actually quite common to have ISession decorated, see Active Record, Castle NHibernate Integration or Spring Integration.
We give you an ISession interface, and you wrap it in another ISession that does additional things
Thanks, now I see
Comment preview