CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Patrick Smacchia [MVP C#]

NHibernate 2.0: Changes Overview

My post .NET Framework 3.5 SP1: Changes Overview on analysis evolution, structure and quality of the .NET framework code base with NDepend became popular. It shows the interest of the community for the under the hood of popular Fx. Thus came the idea of publishing a similar post for the new release of NHibernate 2.0. This post NHibernate 2.0 Gold Release analysis NHibernate 2.0 with NDepend and lists breaking functional changes, while I'll focus more on structural changes.

 

Changes Overview (compared to NHibernate v1.2.1)

# IL instructions    176 818 to 245 106      (+68 288   +38.6%)
# lines of code (LOC)    25 960 to 36 143      (+10 183   +39.2%)
# lines of comment    25 135 to 29 401      (+4 266   +17%)
Percentage Comment    49% to 44%      (-5%)
# Assemblies    1
# Namespaces    46 to 65      (+19   +41.3%)
# Types    806 to 1 262      (+456   +56.6%)
# Methods    8 190 to 12 016      (+3 826   +46.7%)
# Fields    2 166 to 3 842      (+1 676   +77.4%)


4.852 new public methods:  

SELECT METHODS WHERE IsPublic AND WasAdded

 

548 new public types:  

SELECT TYPES WHERE IsPublic AND WasAdded

 

21 new mamespaces:  

SELECT NAMESPACES WHERE WasAdded

 

2 namespaces removed:  

SELECT NAMESPACES WHERE WasRemoved

 

127 public types removed:  

SELECT TYPES WHERE IsPublic AND WasRemoved

 

5 non-public methods became public: 

SELECT METHODS WHERE IsPublic AND VisibilityWasChanged AND IsInNewerBuild

 

1.230 methods where code was changed

SELECT METHODS WHERE CodeWasChanged

 

380 types where code was changed

SELECT TYPES WHERE CodeWasChanged

 

The following treemap/metric view shows the impact of methods changes or added (in blue). It clearly looks like that the entire code base has been refactored:

 

 

Assembly dependencies

The assembly structure hasn't changed. The NHibernate code is still packaged within one assembly named NHibernate.dll, and this is IMHO the best possible choice since there is no reason to have several physical components for the NHibernate Fx.

 

NHibernate.dll is almost using the same set assemblies: Castle.Core.dll v1.0.3.0 has been added and also Castle.DynamicProxy2.dll v2.0.3.0 is used in lieu of Castle.DynamicProxy.dll v1.1.5.0. Here is the simple graph of assemblies dependencies (made with the version of NDepend v2.10 under development, so stay tuned for this future exciting release scheduled in a few weeks).

 

 

Internal namespaces dependencies

As noted by Jim Bolla a few months ago in his post Analyzing NHibernate with NDepend, the NHibernate code is quite entangled and unfortunately this problem hasn't been fixed for NHibernate v2.0. Basically, on 65 namespaces, 63 namespaces depend directly or indirectly on 62 other namespaces. This is what is shown by the big black square in the dependencies matrix below, taken with the indirect dependencies option of NDepend. A black cell means that the 2 corresponding namespaces are involved in a dependency cycle of minimal length the number displayed.

 

IMHO, the NHibernate team should fix this problem asap. This article Controlling Dependencies to get Clear Architecture explains how we get rid for good of spaghetti in the NDepend code base within in a few days, about 2 years ago. Retrospectively, I estimate that this is by far the best Return On Investment on quality we ever done, much better that any of the thousands automatic tests we wrote. As explained in the article, we now use some NDepend capabilities to prevent new cycle to appear.

 


 

The picture below shows direct dependencies between namespaces of NHibernate. The legend is:

  1. A blue cell means: {the X Namespace} is using {the Y Namespace}.
  2. Weight of a blue cell means: W members (methods and fields) of the {the X Namespace} are used by {the Y Namespace}.
  3. A green cell means: {the Y Namespace} is used by {the X Namespace}.
  4. Weight of a green cell means: W methods of the {the Y Namespace} are using {the X Namespace}.
  5. A black cell means: {the X Namespace} and {the Y Namespace} are using each others.
  6. A red tick on a cell means: the coupling has been changed.
  7. A red tick with a plus on a cell means: the dependency has been created.
  8. A red tick with a minus on a cell means: the dependency has been removed.
  9. A Namespace name underlined means that its code has been changed.
  10. A Namespace name in bold means that it has been added.

 

Code quality

According to the following CQL rules, 464 methods are good candidate to be refactored because they each violates one of the metric threshold.

// <Name>Quick summary of methods to refactor</Name>

WARN IF Count > 0 IN SELECT METHODS WHERE 
                                           
// Metrics' definitions
     (  NbLinesOfCode > 30 OR              // http://www.ndepend.com/Metrics.aspx#NbLinesOfCode
        NbILInstructions > 200 OR          // http://www.ndepend.com/Metrics.aspx#NbILInstructions
        CyclomaticComplexity > 20 OR       // http://www.ndepend.com/Metrics.aspx#CC
        ILCyclomaticComplexity > 50 OR     // http://www.ndepend.com/Metrics.aspx#ILCC
        ILNestingDepth > 4 OR              // http://www.ndepend.com/Metrics.aspx#ILNestingDepth
        NbParameters > 5 OR                // http://www.ndepend.com/Metrics.aspx#NbParameters
        NbVariables > 8 OR                 // http://www.ndepend.com/Metrics.aspx#NbVariables
        NbOverloads > 6 )                  // http://www.ndepend.com/Metrics.aspx#NbOverloads

 

This stance on metrics is a bit extremist and honestly, we have a bunch of methods in the NDepend code base that still don't abide by all these thresholds. While abiding by metric threshold helps a lot to have maintainable code, my opinion is that quality effort must be focused first on rationalizing componentization and dependencies, with non-cyclic dependencies between components, low level components and logical component (namespaces) instead of physical components (assemblies).

 

However, there is a fundamental metric not represented here: Test Coverage. I tried to gather Test Coverage metrics for NHibernate 2.0 to make this data analyzed by NDepend. Unfortunately just running the NHibernate.Test-2.0 project with the option Run Test(s) of TestDriven.NET lead to: 427 passed, 755 failed, 14 skipped, took 3738,55 seconds. I suspect I don't have all DB stuff installed (I am not really a DB guy) and am a bit lazy to go thought all the operation to make it work. (Btw, any code coverage file produced by NCover or VSTS Coverage on NHibernate 2.0 is welcome, just send it with http://www.transferbigfiles.com/ and let me know the url where I can download it. My email is psmacchia at google mail. This way I could complete this post with obtained results).

 

Conclusion

This awesome release of NHibernate is the result of a lot of work done by extremely talented guys. As said, I am not a DB guy, I cannot appreciate the real value of this framework. However, googling it a few seconds lets find dozens of thousands of enthusiast users.

 

This post focuses on structure, quality and evolution and thanks to NDepend capabilities, I find some good things but also some important room for improvement (IMHO) within a few minutes that I wanted to share.
 


 



Comments

Cuanto se ha cambiado NHibernate desde 1.2.1 hasta 2.0 GA? at Espacio de Dario Quintana said:

Pingback from  Cuanto se ha cambiado NHibernate desde 1.2.1 hasta 2.0 GA? at Espacio de Dario Quintana

# August 26, 2008 2:03 PM

Will Shaver said:

One of the difficulties in developing features for NHibernate and with performing code cleanups is the desire to keep it somewhat in sync with it's older brother Hibernate. There's a constant and necessary struggle between wanting to improve the core and wanting to keep it as true to Hibernate as possible. While I haven't tried to reduce related complexities I imagine it would cause a rather large deviation from Hibernate. Perhaps we can try and get Hibernate to refactor some and then can use those changes as well.

This information is quite interesting. Thanks for providing it.

-Will (Just barely a nhibernate developer.)

# August 26, 2008 2:05 PM

Patrick Smacchia said:

Will, I indeed just got this feedback from some others NHibernate developers.

I hope that your team and the Hibernate team will find a way to improve the overall architecture because with such entangling, it must not be fun everyday to develop it.

# August 26, 2008 2:11 PM

Firebird News » NHibernate 2.0 GA released said:

Pingback from  Firebird News &raquo; NHibernate 2.0 GA released

# August 26, 2008 3:12 PM

Torkel said:

This was really interesting, very useful to see detailed stats on changes in assembly versions.

I have studied the nhibernate source and find it very nicely structured and coded, there are of course many ways it could be improved. Stats like this is a really good starting point :)

# August 26, 2008 6:24 PM

How much has change NHibernate since 1.2.1 till 2.0 GA ? at Dario Quintana said:

Pingback from  How much has change NHibernate since 1.2.1 till 2.0 GA ? at Dario Quintana

# August 26, 2008 6:30 PM

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# August 26, 2008 8:12 PM

Damon Wilder Carr said:

As always fantastic. Indeed your SP1 post subconsciously 'gave us permission' to add the NDepend analysis.

It just happened, we didn't even think about it to be honest.

We had done this analysis from the earliest bits of the alpha and like most software we use/construct/care about, these artifacts are expected, not optional for us.

CANNOT WAIT for the new version of NDepend.

Actually I am sure you have thought of this, but any plans for 'Linq to CQL'? That would be utterly awesome....

# August 26, 2008 8:42 PM

Brian Johnston said:

This is good information.  Thank-you for doing this.

It does concern me that a framework traditionally used hand in hand with other frameworks to help reduce dependencies (Google 'NHibernate' and 'Dependency Injection' to see what I mean) has so many cross dependencies itself - not good advertisement in my mind.

I think this shows the problem we all face when writing software - when is it time to cut the cord to the past and do a true 'new' version?  By trying to encompass all things, we fall apart at the seams in many cases, so sometimes the best thing to do is limit what we try to do and not fall into the jack of all trades, master of none in the 'code' sense of the saying.

We all know NHibernate is powerful in the hands of the right developer who knows how to utilize it correctly, but perhaps a rewrite and decoupling of the past would result in a better framework.

Just my opinion.

# August 26, 2008 10:44 PM

Brian Johnston said:

Is that 3738.55 seconds to run unit tests (1 hour, 2 minutes) a typo or am I doing my math wrong?   That can't be right.

Seems extremely excessive for what appears to be only about 1200 tests if I did my addition right (427 passed, 755 failed, 14 skipped)

# August 26, 2008 11:08 PM

Patrick Smacchia said:

Brian, yes more than one hour, no typo problem, I think that tests tried and tried to create unsuccessfully some DB, but that is my own theory.

Damon, yes there are many (many) things in the pipe but cannot talk about it so far.

# August 27, 2008 2:58 AM

Dew Drop - August 27, 2008 | Alvin Ashcraft's Morning Dew said:

Pingback from  Dew Drop - August 27, 2008 | Alvin Ashcraft's Morning Dew

# August 27, 2008 8:47 AM

Tuna Toksoz said:

Patrick, you need to create a database named nhibernate. IThen rerun the test again. It took

3 mins 50 secs 58 msecs  to run all the tests in the trunk(and I assume it will take less for the release) and I had 1407 passed 5 failed 38 ignored. 5 failing tests were dialect issues complaining This fixture applies to Firebird, etc.

# August 27, 2008 5:05 PM

Jack said:

WTF???? Why is there a dependency on System.Data.OracleClient?????

# August 31, 2008 2:00 AM

Patrick Smacchia said:

Jack, after verification:

the method

NHibernate.Driver.OracleClientDriver.CreateConnection()

creates a

System.Data.OracleClient.OracleConnection..ctor()

and the method

NHibernate.Driver.OracleClientDriver.CreateCommand()

creates a

System.Data.OracleClient.OracleCommand..ctor()

hence the dependency on System.Data.OracleClient.

With your 'WTF' you point exactly why a tool such as NDepend is essential: the code base structure is often different than what we think it is.

# August 31, 2008 12:04 PM

NHibernate 2.0 « Beautiful code said:

Pingback from  NHibernate 2.0 &laquo; Beautiful code

# September 1, 2008 1:21 PM

NHibernate 2.0 « Beautiful code said:

Pingback from  NHibernate 2.0 &laquo; Beautiful code

# September 2, 2008 2:38 AM

Jay R. Wren - lazy dawg evarlast » Blog Archive » Lack of Value of Code Metrics said:

Pingback from  Jay R. Wren - lazy dawg evarlast  &raquo; Blog Archive   &raquo; Lack of Value of Code Metrics

# September 7, 2008 1:40 PM

Patrick Smacchia [MVP C#] said:

A part of my job as lead developer of the tool NDepend , is to make sure that the product fits real-world

# September 23, 2008 12:42 PM

Community Blogs said:

A part of my job as lead developer of the tool NDepend , is to make sure that the product fits real-world

# September 23, 2008 1:19 PM

Mirrored Blogs said:

A part of my job as lead developer of the tool NDepend , is to make sure that the product fits real-world

# September 23, 2008 1:27 PM

Fabio Maulo said:

@Patrick

Analyze dependency from classes included inside .NET FW is not necessary and less when you are talking about dialects because all dialects can be extracted from code-base without any problems.

Compare NH1.2 with NH2.0 is unnecessary if you know the history of NH. NH2.0 was a big work and many classes was completely rewritten.

Dependency from castle: 4 hours to remove it completely.

I don't understand if your effort is oriented to have a better NH or to publicize NDepend using NH. If you have a patch to remove some "dependency" remember that we are happy to analyze your proposals.

# November 22, 2008 4:23 PM

- adventurers said:

NHibernate in Zahlen

# November 23, 2008 1:59 PM

Ayende @ Rahien said:

On NHibernate Quality

# November 25, 2008 12:05 PM

NHibernate: A Hard-Work and Success Story « WS-KNOWLEDGE said:

Pingback from  NHibernate: A Hard-Work and Success Story &laquo; WS-KNOWLEDGE

# November 25, 2008 3:09 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Patrick Smacchia

Patrick Smacchia is a Visual C# MVP involved in software development for over 15 years. After graduating in mathematics and computer science, he has worked on software in a variety of fields including stock exchange, airline ticket reservation system as well as a satellite base station at Alcatel. He's currently a software consultant and trainer on .NET technologies as well as the lead developer of the tool NDepend which provides numerous metrics and caveats on any compiled .NET application. He is the author of Practical .NET2 and C#2, a .NET book conceived from real world experience with 647 compilable code listings. Check out Devlicio.us!

Our Sponsors

Proudly Partnered With