Archive for August, 2009

Could You Go Back To Coding Without Resharper?

37 commentsWritten on August 31st, 2009 by
Categories: Opinions

As most of you know by now, i'm a pretty big fan of Resharper. I've been using it for about 2 years now, and i really can't picture myself anymore writing code in Visual Studio without it. I'm definitely not the biggest Resharper keyboard-shortcut Jedi, but i make use of the shortcuts a lot. A hell of a lot actually. Having to go back to plain old Visual Studio without Resharper would seriously mess me up.... a lot.

At work, most of my coworkers started using Resharper as well since about a year ago. Now, almost every time i happen to sit by a coworker or just observe someone writing code, i can see them using shortcuts that i didn't even know about, or using a lot of live templates (which i really should start using as well) that they created. I know that some of them simply wouldn't want to go back to working without it either.

So what about you guys? Have you tried Resharper and if so, would you be able to go back to not using it? If you did go back to not using it, did you replace it with another tool (like Coderush or something else)? If you do still use it, which features do you like the most? Which ones make you the most productive?

Btw, i'm not getting paid by JetBrains for this, but i'm genuinely interested in hearing about this from you guys so speak up! :)

How Community Matters

No Comments »Written on August 31st, 2009 by
Categories: Opinions

Just wanted to share an interesting link from someone who's gotten some first-hand experience on a topic i talked about before: The incredible difference between what is considered normal in the Java community and the .NET community.

I'm not gonna get into that argument again, but it's nice to hear someone else say it ;)

There Is No Excuse For Failing Queries In Production

5 commentsWritten on August 30th, 2009 by
Categories: Opinions

Bertrand Le Roy left a few interesting comments on a previous post. Here's a 'transcript' of the comments (i'm only showing the parts that pertain to this particular topic):

Bertrand Le Roy: Would it make sense for the query to implement IDisposable so that you can put it in a using block? I would be a little concerned about the query failing and never getting disposed of. Me: well, if a query fails the underlying SqlCommand object will eventually be garbage collected so i wouldn’t really worry about that. Failed queries shouldn’t happen frequently anyway IMO because they typically are the result of incorrect code. Bertrand Le Roy:Incorrect code happens. When it happens, you may exhaust your connection pool before that stuff gets collected. Me:code that causes failing queries should never even make it to your source code repository… you do write tests for queries, no? If you deploy code which causes frequently failing queries, then you have some fundamental problems in the way you create, test and deliver software.

I wanted to expand on this since i think it's an important topic. Simply put, i believe that failing queries in a production environment are simply inexcusable.

First of all, every single query in your application should be tested properly with automated tests. Doing this consistently will avoid a lot of problems. In fact, i can only think of 3 reasons why queries could still fail in production, even if you do write tests for each and every one of them:

  • The query is composed dynamically, based on a set of conditions (for instance, a complex search screen with lots of filtering possibilities).
  • Queries that use a dynamic number of parameters (like with a WHERE yaddiyadda IN ({your parameters here}) clause) and the parameter list grows bigger than the maximum allowed by your database.
  • Some idiot modified parts of the database structure without redeploying an updated version of the application.

In case of dynamically composed queries, you obviously need some tests for each and every possible filter that can be added to the query. Parameter values shouldn't cause problems either, unless you're adding their values straight into the SQL statement (which is terrible for a host of reasons). Different filter combinations shouldn't cause issues either since you should have tests for those as well anyway. In any case, this can only fail due to not testing each possible combination.

The second option (dynamic list of parameters) is a bit more difficult. In most cases, you truly don't expect the number of parameters to exceed the limit (which is 2100 on SQL Server 2005) because you typically use this approach when you have a fixed set of data. I'd even go as far saying that using the IN clause with a parameter list that could very reasonably grow much larger over time (based on data in another table for instance) is negligent programming. Simply put, you should only use this approach when you know that the list of parameters won't grow too large. If the list of parameters can grow beyond the allowed limit, you simply need to come up with a different query.

And then there's the last situation... and it's an oh-so-typical one unfortunately. I've come across more than my fair share of people who think it's 'ok' to make changes directly into a production database without going through the proper deployment procedures. This is simply just asking for problems. Whenever a database change needs to be made, you should always make the change first in a development (and preferably an acceptance) environment, and at least run your entire test suite on the modified database. If there are failing tests, then you will at least have the option to fix the code and run the testsuite again until everything is alright. Only then should you upgrade both the application and the database in production.

Proper testing practices and proper deployment procedures can virtually eliminate the possibility of having failed queries in production. Having said all that, we all know that even the best of intentions and practices won't prevent all bugs from showing up in production. I'll once again quote from Bertrand's comment:

Incorrect code happens. When it happens, you may exhaust your connection pool before that stuff gets collected

He does have a point there. However, i personally don't think that you should keep this particular situation in mind whenever you need to execute a query in your code. Like i said, i consider failed queries in production inexcusable and therefore, i do not think it's worth the effort of protecting yourself against a situation that shouldn't occur in every possible place where it might occur.

For instance, in Bertrand's particular example of exhausting a connection pool, you could easily avoid this situation in one single part of the code by making use of a circuit breaker. As soon as you know that your application is having problems connecting to the database, why would you even bother to keep trying? It's much better to fail instantly when the database is known to be down instead of trying to connect over and over again. You could easily use a circuit breaker (either at the service level like in the example i linked to, or at the lowest possible level by using a custom DriverConnectionProvider in NHibernate with circuit breaker logic at that level) to prevent such a problem from getting out of hand.

Now, don't get me wrong... i don't want to advocate improper usage of the disposal pattern or incorrect resource utilization in general, but i don't agree that we should litter our code with checks and precautions for things that shouldn't occur frequently anyway. I do believe that protective countermeasures should be put in place, but only where they make sense. I think this is somewhat similar to proper exception handling practices: don't put a try/catch/finally block in every piece of code, use it where you can deal with it... etc.

Build Your Own Data Access Layer: Conclusions

15 commentsWritten on August 29th, 2009 by
Categories: Build Your Own DAL

Note: This post is part of a series. Be sure to read the introduction here.

Building your own DAL is almost never a cost-efficient solution. In this case, i wrote this DAL in 24 working hours, but it is limited in scope, power, flexibility and functionality. Having said that, i do think it's better than every single custom DAL i've come across so far. Taking it to the next step however would take a lot more effort, which truly is never worth it. As you try to provide more functionality, overall complexity of your custom DAL will increase heavily and the effort you'll eventually spend on it will more than outweigh any of the downsides that might come with using something that already exists. Building your own DAL is an undertaking that should always be questioned, and shouldn't be considered unless the alternative of doing so is even worse.

If however, you're in a situation where it does make sense, then i hope this series might have been helpful for you. I've shown that you can come up with something relatively decent without having to resort to code generation, without having to spend an insane amount of effort on it, and without having to write repetitive and error-prone code in your application code. Those were the goals i had in mind when i started working on this DAL, and i think i've succeeded at achieving those goals. The final result is an easy-to-use DAL which is far from as powerful as already existing solutions, but it is pretty good for the scenario's where we intend to use this.

The code itself is clear, easy to maintain and in some cases, very easy to extend as well. In total, this DAL is slightly less than 1100 lines of code, and i think the complexity of the code is relatively low so everyone should be able to understand what's going on, how it works, and where things could be modified in order to fix issues or to add new features.

Also, this series of blog posts helps in figuring out how it works since pretty much every aspect of it is now documented pretty extensively :)

All in all, i had a lot of fun in writing both the DAL and this series of posts (which took another 8 hours in total).

In the introduction of this series, i mentioned the following:

The purpose of this series is basically to:
* Show you that you really don’t need to resort to code generation to build your own custom DAL
* Show you what kind of complexity is involved with the implementation of a good DAL
* Convince you that you typically are better off with simply using something that is already available as a mature, powerful and proven solution

So tell me, did the series succeed in these listed goals? Would you still go for code generation if you had to create a custom DAL? Would you still prefer to use a custom DAL over something that already exists? How would you react to having to use this particular DAL? What would need to be added or modified before you would find it acceptable? What are your thoughts on this in general?

I'd be very interested in hearing about it, so please do post your opinions in the comments :)

Build Your Own Data Access Layer: Bringing It All Together

2 commentsWritten on August 29th, 2009 by
Categories: Build Your Own DAL

Note: This post is part of a series. Be sure to read the introduction here.

By now we've already covered everything that this DAL has to offer, which admittedly isn't all that much. All of the classes you've seen so far are pretty good at whey they should do, but nobody in their right mind would want to use any of these things directly in application code. Any easy-to-use DAL should offer a simple facade which sits on top of the underlying system and makes it very easy to perform the most typical tasks that you need it to perform for you. You shouldn't need to know about specific classes to be able to use it (that goes for most good frameworks and libraries btw).

So once again, i based my approach on what NHibernate does, and with that the ISession interface was born:

    public interface ISession : IDisposable
    {
        void Commit();
        void Rollback();
 
        IQuery CreateQuery(string sql);
        IQuery CreateQuery<TEntity>(string whereClause);
 
        TEntity Get<TEntity>(object id);
        IEnumerable<TEntity> FindAll<TEntity>();
 
        TEntity Insert<TEntity>(TEntity entity);
        TEntity Update<TEntity>(TEntity entity);
        void Delete<TEntity>(TEntity entity);
 
        TableInfo GetTableInfoFor<TEntity>();
 
        void ClearCache();
        void RemoveFromCache(object entity);
        void RemoveAllInstancesFromCache<TEntity>();
 
        SqlConnection GetConnection();
        SqlTransaction GetTransaction();
    }

Everything that you need to be able to do with this DAL is provided by this single interface. And the implementation of the Session class is very easy as well, since we can simply delegate pretty much everything to each of the classes we've covered in the other posts in the series:

    public class Session : ISession
    {
        private readonly string connectionString;
        private SqlConnection connection;
        private SqlTransaction transaction;
        private readonly MetaDataStore metaDataStore;
        private readonly EntityHydrater hydrater;
        private readonly SessionLevelCache sessionLevelCache;
 
        public Session(string connectionString, MetaDataStore metaDataStore)
        {
            this.connectionString = connectionString;
            this.metaDataStore = metaDataStore;
            sessionLevelCache = new SessionLevelCache();
            hydrater = new EntityHydrater(metaDataStore, this, sessionLevelCache);
        }
 
        private void InitializeConnection()
        {
            connection = new SqlConnection(connectionString);
            connection.Open();
            transaction = connection.BeginTransaction();
        }
 
        public SqlConnection GetConnection()
        {
            if (connection == null)
            {
                InitializeConnection();
            }
 
            return connection;
        }
 
        public SqlTransaction GetTransaction()
        {
            if (transaction == null)
            {
                InitializeConnection();
            }
 
            return transaction;
        }
 
        public IQuery CreateQuery(string sql)
        {
            var command = GetConnection().CreateCommand();
            command.Transaction = GetTransaction();
            command.CommandText = sql;
            return new Query(command, metaDataStore, hydrater);
        }
 
        public IQuery CreateQuery<TEntity>(string whereClause)
        {
            return CreateQuery(metaDataStore.GetTableInfoFor<TEntity>().GetSelectStatementForAllFields() + " " + whereClause);
        }
 
        public TableInfo GetTableInfoFor<TEntity>()
        {
            return metaDataStore.GetTableInfoFor<TEntity>();
        }
 
        public void Commit()
        {
            transaction.Commit();
        }
 
        public void Rollback()
        {
            transaction.Rollback();
        }
 
        public void Dispose()
        {
            if (transaction != null) transaction.Dispose();
            if (connection != null) connection.Dispose();
        }
 
        private TAction CreateAction<TAction>()
            where TAction : DatabaseAction
        {
            return (TAction)Activator.CreateInstance(typeof(TAction), GetConnection(), GetTransaction(),
                metaDataStore, hydrater, sessionLevelCache);
        }
 
        public TEntity Get<TEntity>(object id)
        {
            return CreateAction<GetByIdAction>().Get<TEntity>(id);
        }
 
        public IEnumerable<TEntity> FindAll<TEntity>()
        {
            return CreateAction<FindAllAction>().FindAll<TEntity>();
        }
 
        public TEntity Insert<TEntity>(TEntity entity)
        {
            return CreateAction<InsertAction>().Insert(entity);
        }
 
        public TEntity Update<TEntity>(TEntity entity)
        {
            return CreateAction<UpdateAction>().Update(entity);
        }
 
        public void Delete<TEntity>(TEntity entity)
        {
            CreateAction<DeleteAction>().Delete(entity);
        }
 
        public void InitializeProxy(object proxy, Type targetType)
        {
            CreateAction<InitializeProxyAction>().InitializeProxy(proxy, targetType);
        }
 
        public void ClearCache()
        {
            sessionLevelCache.ClearAll();
        }
 
        public void RemoveFromCache(object entity)
        {
            sessionLevelCache.Remove(entity);
        }
 
        public void RemoveAllInstancesFromCache<TEntity>()
        {
            sessionLevelCache.RemoveAllInstancesOf(typeof(TEntity));
        }
    }

As you can see, there's nothing special here and it's all very straightforward. Application code can now perform database operations pretty easily once it has a reference to an ISession instance. And obtaining a reference to an ISession instance can be done through the ISessionFactory interface:

    public interface ISessionFactory
    {
        ISession CreateSession();
    }

And its implementation:

    public class SessionFactory : ISessionFactory
    {
        private string connectionString;
        private MetaDataStore metaDataStore;
 
        public static ISessionFactory Create(Assembly assembly, string connectionString)
        {
            var sessionFactory = new SessionFactory {connectionString = connectionString, metaDataStore = new MetaDataStore()};
            sessionFactory.metaDataStore.BuildMetaDataFor(assembly);
            return sessionFactory;
        }
 
        private SessionFactory() {}
 
        public ISession CreateSession()
        {
            return new Session(connectionString, metaDataStore);
        }
    }

The static Create method takes an assembly and a connection string. The assembly (containing your entity types) will be used to to build up the metadata model as covered in the Mapping Classes To Tables post. You would typically call the Create method in your application's startup code, and then you'd have to store a reference to the ISessionFactory somewhere. Your application code can then simply call the ISessionFactory's CreateSession method and that's all there is to it.