Let us burn all those pesky Util & Common libraries
This is a post that is riling against things like Rhino Commons, MyCompany.Util, YourCompany.Shared.
The reason for that, and the reason that I am not longer making direct use of Rhino Commons in my new projects is quite simple.
In computer programming, cohesion is a measure of how strongly-related and focused the various responsibilities of a software module are. Cohesion is an ordinal type of measurementand is usually expressed as "high cohesion" or "low cohesion" when being discussed. Modules with high cohesion tend to be preferable because high cohesion is associated with several desirable traits of software including robustness, reliability, reusability, and understandability whereas low cohesion is associated with undesirable traits such as being difficult to maintain, difficult to test, difficult to reuse, and even difficult to understand.
I am going to rip into Rhino Commons for a while, let us look at how many things it can do:
- Create SQL CE databases dynamically
- Keep track of the performance of ASP.Net requests
- Log to a database in an async manner using bulk insert
- Log to a collection of strings
- Log to an embedded database – with strict size limits
- Same thing for SQLite
- Same thing for SqlCE
- Keep track of desirable properties of the http request for the log
- Add more configuration options to Windsor
- Provide a static gateway to the Windsor Container
- Plus some util methods
- Allow to execute Boo code as part of an msbuild script
- Allow the execute a set of SQL scripts as part of an msbuild script
- Provide cancelable thread pool
- Provide an implementation of a thread safe queue
- Provide an implementation of a countdown latch (threading primitive)
- Expose a SqlCommandSet that is internal in the BCL so we can use it
- Allow to easily record log messages executes in a given piece of code
- Allow to get the time a piece of code executed with high degree of accuracy
- Allow to bulk delete a lot of rows from the database efficiently
- Provide an easy way to read XML based on an XPath
- Provide a way to update XML based on an XPath
- Provide a configuration DSL for Windsor
- Provide local data store that works both in standard code and in ASP.Net scenarios
- Provide collection util methods
- Provide date time util methods
- Provide disposable actions semantics
- Provide generic event args class
- Allow 32 bit process to access 64 bit registry
- Give nice syntax for indexed properties
- Give a nice syntax for static reflection
- Provide guard methods for validating arguments
- Provide guard methods for validating arguments – No, that is not a mistake, there are actually two different and similar implementations of that there
- Provide a very simple data access layer based on IDbConnection.
- Provide a way to query NHibernate by for a many to one using its id with a nicer syntax
- Provide a named expression query for NHibernate (I am not sure what we are doing that for)
- Provide unit of work semantics for NHibernate
- Provide transaction semantics for auto transaction management using the previously mentioned unit of work
- Provide a way to map an interface to an entity and tie it to the Repository implementation
- Provide a fairly complex in memory test base class for testing Container and database code
- Provide a way to warn you when SELECT N+1 occur in your code via http module
- Provide nicer semantics for using MultiCriteria with NHibernate
- Provide Future queries support externally to NHibernate
- Provide an IsA expression for NHibernate
- Provide a way to execute an In statement using XML selection (efficient for _large_ number of queries)
- Provide a pretty comprehensive generic Repository implementation, including a static gateway
- Provide an easy way to correctly implement caching
- Provide a way to easily implement auto transaction management without proxies
- Do much the same for Active Record as well as NHibernate
Well, I think that you get the drift by now. Rhino Commons has been the garbage bin for anything that I came up with for a long time.
It is easy to get to that point, but just not paying attention. In fact, we are pretty much doctrined into doing just that, with “reuse, reuse, reuse” bang into our head so often.
The problem with that?
Well, most of this code is only applicable for just one problem, in one context, in one project. Bulk Deleter is a good example, I needed it for one project, 3 years ago, and never since. The repository & unit of work stuff has been used across many projects, but what the hell do they have to do with a configuration dsl? Or with static reflection?
As a matter of fact, that Rhino Commons has two (different) ways to do parameter validation is a pretty good indication of a problem. The mere fact that we tend to have things like Util, Shared or Common is an indication that we are basically throwing unrelated concerns together. It actually get worse if we have something in the common project that can be used for multiple projects. A good example of that would be the in memory database tests that Rhino Commons provide. I have used it in several projects, but you know what? It is freaking complex.
The post about rolling your own in memory test base class with NHibernate show you how simple it can be. The problem is that as timed went by, we wanted more & more functionality out of the rhino commons implementation, container integration, support for multiple databases, etc. And as we did, we piled more complexity on top of it. To the point where it is easier to roll your own than to use the ready made one. Too many requirements for one piece of code == complexity. And complexity is usually a bad thing.
The other side of the problem is that we are going to end up with a lot of much smaller projects, focused on doing just one thing. For example, a project for extending NHibernate’s querying capabilities, or a project to extend log4net.
Hm, low coupling & high cohesion, I heard that somewhere before…