Archive for January, 2009

Framework Configuration: A Different Approach

No Comments »Written on January 12th, 2009 by
Categories: Software Development

Last week i spent some time at work moving some common infrastructure classes which were used in multiple projects into its own little 'framework' assembly. This framework basically just provides everything we need to use the Request/Response Service Layer, the KnownTypeProvider, some stuff built on top of NHibernate (the QueryBatcher, Repository and UnitOfWork implementations), our own MVP implementation for WebForms and UserControls, the Dispatcher (for easy communication with the Request/Response service layer, see that post for more details), and some Silverlight equivalents of some of these classes that were written by a coworker of mine.

This little framework uses the Windsor IoC container quite heavily so naturally, everything needs to be registered properly. You also need to register your known Request/Response types with the KnownTypeProvider and you have to configure the NHibernate components to use the correct mapping files as well. The framework provides default implementations for pretty much all of the components, except for some that you need to provide implementations for yourself, although abstract base classes are available in the framework assembly which you can inherit from. So i needed something which would allow me to easily configure the framework in every project that uses it, making it possible to override the implementation of certain components or use the default implementations when these are sufficient. I really wanted to avoid the typical XM-Hell that this usually leads to, so i wanted to go for a code-only approach.

First of all, the business side behind the Request/Response WCF service. There's two ways to use this, with or without NHibernate support (in case we have to work for... umm... conservative clients). So we start off with the following class:

namespace Trinity.Business
{
    public class Registration
    {
        public Registration(Assembly commonAssembly, Assembly businessAssembly)
        {
            CommonAssembly = commonAssembly;
            BusinessAssembly = businessAssembly;
            SetDefaultImplementationTypes();
        }
 
        public Assembly BusinessAssembly { get; private set; }
        public Assembly CommonAssembly { get; private set; }
        public Type IRequestProcessorImplementation { get; set; }
 
        private void SetDefaultImplementationTypes()
        {
            IRequestProcessorImplementation = typeof(RequestProcessor);
        }
    }
}

Nothing spectacular... This Registration class can be instantiated with two assembly references. The first is a Common assembly, which contains the known Request/Response types that will be registered with the KnownTypeProvider. The second is the business assembly which contains all of the IRequestHandler implementations to handle each Request type so we can return a Response. Finally, you can set the implementation type of the IRequestProcessor interface that the framework should use at runtime. Notice how this is optional and that a default implementation type is set.

We also have another Registration class which contains some more configuration possibilities for NHibernate usage:

    public class RegistrationWithNHibernateSupport : Registration
    {
        public RegistrationWithNHibernateSupport(Assembly commonAssembly, Assembly businessAssembly,
            string mappingAssemblyName) : base(commonAssembly, businessAssembly)
        {
            MappingAssemblyName = mappingAssemblyName;
            SetDefaultImplementations();
        }
 
        public string MappingAssemblyName { get; private set; }
        public Type ISessionProviderImplementation { get; set; }
        public Type IActiveSessionManagerImplementation { get; set; }
        public Type IUnitOfWorkImplementation { get; set; }
 
        private void SetDefaultImplementations()
        {
            ISessionProviderImplementation = typeof(SessionProvider);
            IActiveSessionManagerImplementation = typeof(ActiveSessionManager);
            IUnitOfWorkImplementation = typeof(UnitOfWork);
        }
    }

Here we have an extra required constructor parameter to provide the name of the assembly which contains the embedded NHibernate mapping files. We also have 3 properties which enable you to provide implementation types for the ISessionProvider, IActiveSessionManager and IUnitOfWork interfaces. Again, the default implementation types are set automatically.

We can now configure the business side of the framework with the following two static methods in the Register class:

    public static class Register
    {
        public static void WithNHibernateSupport(RegistrationWithNHibernateSupport registration)
        {
            Normal(registration);
            RegisterNHibernateComponents(registration);
            RegisterAllRepositories(registration.BusinessAssembly);
        }
 
        public static void Normal(Registration registration)
        {
            RegisterRequestProcessor(registration);
            RegisterRequestAndResponseTypes(registration.CommonAssembly);
            RegisterRequestHandlers(registration.BusinessAssembly);
        }
    }

I left out the implementations of the private methods for brevity. Although i will show you what the implementation of the NHibernate components looks like:

        private static void RegisterNHibernateComponents(RegistrationWithNHibernateSupport registration)
        {
            IoC.Container.Register(Component.For<ISessionProvider>()
                .ImplementedBy(registration.ISessionProviderImplementation)
                .Parameters(Parameter.ForKey("mappingAssemblyName").Eq(registration.MappingAssemblyName))
                .LifeStyle.Singleton);
 
            IoC.Register(typeof(IActiveSessionManager), registration.IActiveSessionManagerImplementation, IoC.LifeStyle.Singleton);
            IoC.Register(typeof(IUnitOfWork), registration.IUnitOfWorkImplementation);
 
            // these 2 component implementations can not be overridden by consumers (why yes, that _is_ on purpose)
            IoC.Register<IQueryBatcherFactory, QueryBatcherFactory>(IoC.LifeStyle.Singleton);
            IoC.Register<IQueryBatcher, QueryBatcher>();
        }

As you can see, it always uses the implementation types that are set in the Registration instance, which refer to the default implementations if you didn't overwrite the property values.

So how do we configure this to be usable in one of our projects? It's pretty easy:

            Assembly businessAssembly = Assembly.GetExecutingAssembly();
            Assembly commonAssembly = typeof(EmsRequest).Assembly;
 
            var registration = new RegistrationWithNHibernateSupport(commonAssembly, businessAssembly, "EMS.Mappings")
                {
                    IRequestProcessorImplementation = typeof(EmsRequestProcessor),
                    ISessionProviderImplementation = typeof(Infrastructure.NHibernate.SessionProvider)
                };
 
            Trinity.Business.Register.WithNHibernateSupport(registration);

As you can see i am providing my assembly containing my common Request/Response types, and my business assembly. I also provide the name of the assembly containing my mapping files, and i overwrite the implementation of 2 components in the framework. And that's about it.

It works the same way in the Web layer... for that i have the following Registration class:

namespace Trinity.WebForms
{
    public class Registration
    {
        public Registration(Assembly commonAssembly, Assembly webAssembly,
            Type resourceManagerFactoryImplementation)
        {
            WebAssembly = webAssembly;
            CommonAssembly = commonAssembly;
            IResourceManagerFactoryImplementation = resourceManagerFactoryImplementation;
            SetDefaultImplementationTypes();
        }
 
        public Assembly WebAssembly { get; private set; }
        public Assembly CommonAssembly { get; private set; }
 
        public Type IResourceManagerFactoryImplementation { get; set; }
        public Type ITextRepositoryManagerImplementation { get; set; }
        public Type ISessionStateImplementation { get; set; }
        public Type IRequestProcessorImplementation { get; set; }
        public Type IDispatcherImplementation { get; set; }
 
        private void SetDefaultImplementationTypes()
        {
            ITextRepositoryManagerImplementation = typeof(TextRepositoryManager);
            ISessionStateImplementation = typeof(WebSessionState);
            IRequestProcessorImplementation = typeof(RequestProcessorProxy);
            IDispatcherImplementation = typeof(Dispatcher);
        }
    }
}

And well, i guess you can imagine what the rest looks like :)

Ethics In Software Development: Pragmatism Over Dogmatism

2 commentsWritten on January 11th, 2009 by
Categories: Opinions

My fellow Elegant Coder Jan Van Ryswyck wrote about Craftmanship Over Crap. I generally agree with his point of view. Writing good, clean code is tremendously important for the long term survival chances of any software project. But i also believe that we sometimes need to be a bit more pragmatic about how we solve a problem.

A software developer's primary goal should be to create value for the users of a system. Value can mean a lot of things here. First and foremost, it should be about things that users actually experience. Features, ease of use, performance, etc. You can get all of those with crappy code, but that leads to a situation where you won't be able to sustain that value in the long term. A system can be very useful to its users, but if the code is in such bad shape that it can't easily be maintained and extended with new features over time, the value of the system will slowly reduce. New features will introduce new bugs. Bug fixes will introduce new bugs. Eventually, the system starts to collapse under its own rot and the dreaded rewrite commences. Nobody really wants this, do they? If you write good, clean code from the beginning, you can usually avoid these problems.

A lot of opinionated developers claim that a true craftsman developer will never write a piece of bad code. In an ideal world, i would agree. These same developers also look down on people who implement a quick fix instead of looking for the proper solution. Again, in an ideal world i would agree with that. In the real world however, i'm not so sure if that's always the best thing to do.

Those of you who've been reading my posts for a while know how important clean code is to me. I generally hate crappy code and i generally hate quick fixes that don't fix the real problem. Then again, i do realize that we sometimes need to put our principles aside in order to be able to deliver value to our users.

Allow me to use an example to defend my position on this. I recently had to fix a nasty bug in NHibernate. Once i found the true reason for the bug's existence i had two options to fix it. The correct solution would have required me to modify some crucial parts in NHibernate. The easiest fix required me to modify one non-essential class in a manner that couldn't impact anything else.

Certainly, a true craftsman would go for the best solution, right? Well, let me tell you something about the NHibernate code base... it's pretty big, it's quite complex, and it's been worked on by a lot of people over the years. There are parts of the code where you really don't feel comfortable making drastic changes. Sure, we have our test-suite, but it unfortunately doesn't cover every possible thing that could go wrong.

I chose to implement the easier fix. The bug was fixed, which means that the fix created value for everyone who's using the trunk (which is more people than you'd think) and it means that this bug (which was a show-stopper IMO) won't delay our 2.1 release. The correct fix would've meant making a risky change at this point, which could've led to more bugs that we don't have tests for yet. The correct fix will be implemented right after the 2.1 release, when we have more room to make drastic changes to core parts of the code.

Was i wrong to implement the easier fix? I don't think so... although i'm still not happy about that fix. But we have a responsibility to release software. If we would always stick to our principles, that could sometimes lead to having to delay or postpone a release. While there are many valid reasons for delaying or postponing a release, i don't think merely sticking to your principles about a piece of code is always the best thing to do.

Of course, you do have to have the discipline to pay back the technical debt you've incurred when you do this, but sometimes the cost of that technical debt is less than that of having users losing faith in your product. And that, in general, is something we as software developers need to keep in mind as well. Writing good, clean code is great. We should all strive to do that. But we first and foremost need to create value for our users.

Great Links On Using Garbage Collection Efficiently

1 Comment »Written on January 11th, 2009 by
Categories: Memory Management

I usually try to avoid posts that merely link to other stuff, but these links are just too good:

Recommended Books: Behind Closed Doors, Secrets Of Great Management

2 commentsWritten on January 11th, 2009 by
Categories: Books

I don't really have any interest in management, but i read a great recommendation for this book recently (forgot the link) so i couldn't resist ordering it. It consists of two parts. The first 120 pages is a bit of a story about a manager who was just hired to lead one of the departments of a software development company. In between the story (which is an easy and interesting read), you'll find lots of great insight into what great management is all about. The last 40 pages are great descriptions of 13 management techniques.

This book is a must-read for anyone doing any kind of management (even if it's just project management), and i'd even recommend it to non-managers as well. It is just filled with great insight, tips and things that everyone should know about, not just managers.

And for those of you who're too lazy to read a book (and i know there's at least a few of you ;) ), it's only 160 pages so it's not like this will eat up a lot of your time.

NHibernate Profiler Review

8 commentsWritten on January 4th, 2009 by
Categories: NHibernate

A Profiler For NHibernate? What's The Point?

If you're not very experienced with NHibernate, it's not always clear what NHibernate is doing behind the scenes. What kind of queries is it generating? How many entities are we loading? How often does it go the database? Even experienced NHibernate users can make mistakes which may result in inefficient data access, high memory usage, slow response times, etc. When used properly however, you can get excellent performance out of NHibernate.

According to the website, NHibernate Profiler delivers the following advantages:

  • Cognitive application awareness
  • Visual insight into the interaction between your database and application code
  • Analysis and detection of common pitfalls when using NHibernate
  • Analysis is delivered via perfectly styled SQL and linkable code execution

Sounds pretty good, right? Let's take a closer look.

What is NHibernate Doing?

To get a good view on what NHibernate is doing, you should get answers to questions like:

  • How many statements are we sending to the database?
  • What statements are we sending to the database?
  • What data are we loading into memory?

NHibernate Profiler makes it easy to anser those questions. For an NHibernate session where we send a simple query to the database, the profiler already gives us some useful information:

nh01

In the Statements tab, you get an overview of all of the statements in this session. When you select one of the statements, you can view more details in the tabs on the bottom. In this screenshot, you see a properly formatted SQL query which is the query that was generated by NHibernate. The overview also shows how many rows were retrieved by the query.

So we know how many entities were loaded, but which ones were they? Again, the profiler gives us some useful information on that:

nh02

The Entities tab shows you the identifiers of each entity instance (grouped by type) that was retrieved in the session. There's also a useful general overview of your session usage:

nh03

Looks like the profiler is already alerting us of a possible problem. Let's go the Alerts tab:

nh04

You can see the alert right there, with a link to a help page on the profiler's website with a more detailed explanation. The help pages are very helpful and always suggest a way to avoid the problem. In this case, the problem is that our query returns the rows of a table without limiting the number of rows to be returned. In some cases, this can really be a problem but if you're really sure that the table will always have just a few records then it's not really a problem. A helpful extra feature here would be to mark the alert with some sort of "i know about this, and i don't consider it a problem" action so it is removed from the profiler's output. This specific alert can be disabled altogether as well, although i think it would be more useful to remove these alerts on a case-by-case basis.

Now, we know what NHibernate is doing which is pretty useful, but we also need an easy way to figure out which piece of code caused the SQL statements to be sent to the database. The profiler allows you to look at a stacktrace when you select a statement:

nh05

You can double click at each entry in the stacktrace and Visual Studio will show you that line of source code.

I think it's clear that the profiler does a good job of showing you what NHibernate is doing behind the scenes. The output that the profiler is showing you is very useful as well:

nh06

This is the output of a batch of queries. Notice how the queries are nicely separated, and that the parameter values are already filled in. You can easily copy these select statements to execute the queries in whatever querying tool you'd like to use so you can study the actual output of a query. Another nice extra feature would be the ability to select a statement and have the profiler execute it against the database and showing you the results in a separate window.

I hope to see more information regarding the usage of NHibernate's 2nd Level Cache in a future version of this profiler. It would be great to see which entity instances are stored in the cache, when they are stored and through which query, when they are retrieved from the cache instead of the database, when they expire from the cache, when they get refreshed, etc...

What are YOU doing?

Alright, we already covered how the profiler shows what NHibernate is doing. That's nice. But do you know what you're doing? Are you sure you're using NHibernate properly? The profiler has a couple of nice features to warn you from mistakes you might make. As you saw earlier in this review, the profiler alerts you when you do something that might be problematic.

The profiler currently has the ability to alert you of the following problems:

  • Select N + 1
  • Too many database calls in a session
  • Unbounded result set
  • Excessive number of rows
  • Usage of implicit transactions
  • Large number of writes

The profiler offers guidance for each type of alert, making it clear how you can avoid the problem by suggesting other approaches. This guidance is offered through the website of the profiler (the application provides links), but it might be a nice idea to show that guidance from within the tool as well.

Here's an example of the Select N + 1 problem:

nh07

As you can see here, the same query is executed 4 times with an ID parameter that differs each time. Naturally, it would be much better if this data was fetched in one query instead of 4. The profiler clearly alerts you to the problem, and through the stacktrace tab you can very easily navigate to the part of code that is causing the problem.

It's also worth pointing out that you can modify the settings which trigger these alerts:

nh08

Overview Features

Looking at what each individual session is doing is useful, but sometimes you kind of want an overview of the overall NHibernate usage of your application. NHibernate Profiler offers 4 extra views on what's going on in your application.

The first is an overview of all of the queries that were executed during the run:

nh09

This is useful, but i think it would be better if the grid included the average duration for each query. Also, a way to navigate from one of the queries to where it is triggered in code would be great here.

There's also an overview of the queries that were triggered by class and method:

nh10

In this view it would also be very useful to show more information about average durations of statements.

The third one is a general overview of your overall NHibernate usage:

nh11

This one is very nice... the aggregated alerts pane is great, but when you click on the links next to the alerts a browser window will open with relevant alert information from the profiler's website. I think it might be easier if you could just navigate from these aggregated alerts to the specific sessions which are causing these. For instance, if i have a SELECT N + 1 alert in there, i would like to have a way to go to the data from that specific session (or the sessions) with as little clicks and searching as possible.

The aggregated entities and the general statistics are also a very nice touch.

And finally, you can also keep track of the stats that NHibernate itself provides:

nh12

Conclusions

I've been playing with this profiler for a couple of weeks now, and i definitely like it a lot. It not only does a great job of quickly pinpointing problems, it also does a good job of teaching users how to properly use NHibernate. It not only saves you time when you need to fix a problem, it enables you to fix the problem in an informed manner. It's got some great features already, and there will probably be many more interesting additions to the profiler in the future. Is this profiler worth the cost of the license? I'd say it definitely is. Not just for the time you'll save because of it, but also for the stuff you'll learn from it.