Entries
RSS 2.0

Comments
RSS 2.0

Convenience Kills, or the Case Against RAD Tools

A rather heated discussion erupted last week on Twitter and IRC concerning so-called “drag-and-drop demos” — point-and-click demonstrations of “software development” that just involve dragging controls around on a graphical designer without a lot of actual coding involved. Being entirely unable to resist joining in on debates, I had to chime in and give my two cents.

At root, drag-and-drop (D&D) demos are really nothing more than a marketing tool, and they do little to illustrate the actual way software is written. It’s kind of like the scene in Swordfish where the main character is “programming,” but all the audience actually sees is a spinning cube with nodes flying on and off. Why? Because real software development isn’t interesting in the least to a layperson. Real software development means hammering away on a keyboard for hours, drawing squiggly boxes on a whiteboard, and debating design with your team. People with passion for software relish this process, but if you don’t understand what you’re looking at, I imagine watching it would be pretty mind-numbing.

This is also why programming, sadly, will never be an Olympic sport, nor will we tune in on Sundays to National Software League competitions. :)

D&D demos, on the other hand, provide visual indicators and guides which allow people with any level of technical skill to understand the basic process. However, any software developer will tell you that drag-and-drop tools fall very far on the 80% side of the 80/20 rule — the second you try to do something more complex (read: useful), you have to write code.

This is why D&D demonstrations are actually extremely dangerous. They only serve to blow smoke up the asses of non-technical people, and convince them that software development is easier than it actually is. For example, let’s say a non-technical manager sees a demonstration of ASP.NET WebForms, with a data-bound grid control. It can become very difficult to convince them that, in order to support our actual requirements, we need to create a real domain model, and write the HTML directly so we can get better support for CSS, and write some tests so we can make sure it actually does what we claim. None of that was in the product demonstration, so it’s not surprising that non-technical people balk at estimates that include more of the nitty-gritty tasks.

I’ll take this argument a step further, also, and say that all tools geared around RAD (rapid application development) are harmful when considered out of context. Microsoft in particular has had a long-standing obsession with RAD, and you can see it in many of the graphical features of Visual Studio. Since the vast majority of the work on software is maintenance and extensibility, rapid development is the antithesis of good software design. If tool vendors were really interested in making software developers’ lives easier, they would focus more on providing features to maintain software rather than develop it quickly and shove it out the door. That’s why refactoring tools like ReSharper have become so popular — their entire focus is on making it easy to mold your code into a useful application.

However, vendors are in business to make money, and RAD tools are much easier to sell than tools for refactoring. You can only sell a refactoring tool to someone that understands code, but you can sell a RAD tool to anyone — “look how fast we wrote this useful application!” I’m not faulting Microsoft or other vendors for wanting to make money, and I’m not saying that drag-and-drop tools are never useful. If you’re writing disposable code, that you’re certain you’re going to throw away, there’s nothing wrong with slamming something quick and dirty out. If you’re writing something for keeps, though, you better spend at least a few cycles thinking about how to make it maintainable.

Writing software is all about managing change. You start by building a core, and then you start building layers on top of it. With each added feature, you are applying changes to the application as a whole. This is why most of the tenets of good software design focus on limiting the impact of change on your system as a whole — or maximizing orthogonality, if you prefer. This is true throughout the software’s life, both before and after the initial release (the only real difference being the risk associated with adding each change).

Real software design cannot be drag-and-drop, because it’s an organic process, where your code is molded, sculpted, and cultivated over time. I commonly refer to malleable software, which evokes the right idea — flexible software that can be molded into something that solves your business problem. I would argue that there will never be a visual design tool that is more effective long-term than writing code manually, or at least not in the foreseeable future.

The bottom line is that the more you can limit the impact of change, the more easily you can mold and sculpt your software. The idea of RAD and drag-and-drop tools are only smoke and mirrors that mask the real difficulties that go into creating good software.

Defensive Design

Joey Beninghove makes an excellent point in his most recent article. He describes creating an additional service layer (which he refers to as the anti-corruption layer) for shielding your application from services with bad APIs. I use this technique constantly, although I generally call it a defensive design layer. It particularly comes in handy when I have to work with WSDL-generated web service proxies. I don’t want that junk leaking through my application, so I generally create my own facade that works the way I expect it to, and translate to the underlying web service as necessary. (This also means I can mock up the web services more easily during development and testing.)

In fact, one of the projects I’m working on right now has a defensive design layer to shield against the API of Microsoft Reporting Services. Kudos to Microsoft for exposing the functionality via a web service, but I really wish they would have spent some more time making the interface logical. Take the “device info” junk that you have to pass to the ReportExecutionService in order to render a report. Extensibility is great, but you’re telling me they couldn’t come up with a better solution than passing an XML string as one of the parameters of the method call? Sheesh.

Relying on a defensive design layer in your application can also protect your application from changes in the underlying service itself. In extreme cases, it can even help you to replace a third-party component with your own custom-rolled one.

Functional Programming and Database Access

Something clicked in my head a few weeks ago, and ever since, I’ve found myself using more and more functional programming techniques. Even with C# 2.0, there are a lot of things you can do to make your code cleaner and easier to read. I recently came up with an interesting pattern for database access using ADO.NET, so I thought I’d share it. Essentially, it’s a way to create a quick-and-dirty object/relational mapper via a simple pattern rather than by using a framework.

First, a disclaimer: I highly recommend that, instead of using this pattern, you look into a real ORM framework like NHibernate. The only reason I’m using this at all is because I developed it for the .NET compact framework, and as such, I don’t have the luxury of real ORM. If you prefer doing data access by hand, this pattern can help structuralize it, though!

Also, if you looked at the length of this post and your tl;dr alarm went off, don’t worry, the bulk is mostly code, and the payoff is worth it. :)

First, let’s consider a simple database table:

   1: create table Users (
   2:   UserName varchar(20) primary key,
   3:   FirstName varchar(50) not null,
   4:   LastName varchar(50) not null,
   5:   Email varchar(100) null
   6: );

We could easily represent this as an entity in our code using the following simple type (property get/set methods are omitted for brevity):

   1: class User {
   2:   private string _userName;
   3:   private string _firstName;
   4:   private string _lastName;
   5:   private string _email;
   6:
   7:   public string UserName { ... }
   8:   public string FirstName { ... }
   9:   public string LastName { ... }
  10:   public string Email { ... }
  11: }

This is a common pattern that’s been around for a long time. When you want to load a user from the database, you run a SELECT statement, and use an IDataReader to load the information from the query result, and populate the User object:

   1: public User GetUser(string userName)
   2: {
   3:   string sql = "select UserName, FirstName, LastName, Email "
   4:              + "from Users where UserName = @UserName";
   5:
   6:   using (SqlConnection connection = new SqlConnection(...))
   7:   using (SqlCommand command = new SqlCommand(sql, connection))
   8:   {
   9:     command.Parameters.Add("@UserName", SqlDbType.VarChar).Value = userName;
  10:     using (SqlDataReader reader = command.ExecuteReader())
  11:     {
  12:       if (!reader.Read())
  13:         return null;
  14:
  15:       User user = new User();
  16:       user.UserName = reader.GetString(0);
  17:       user.FirstName = reader.GetString(1);
  18:       user.LastName = reader.GetString(2);
  19:       user.Email = reader.GetString(3);
  20:
  21:       return user;
  22:     }
  23:   }
  24: }

This works just fine, but there are a couple of problems. First, our data retrieval code is coupled to the code that populates the object (the “ORM” code). This means that if we wanted to add a method that returned a list of all users with a given last name, we would have to duplicate the ORM code in the other method. Second, there’s a hidden bug in the ORM code… the Email column is nullable, but we’re not checking it with IsDBNull before we call GetString. This is easily fixed, but if you’ve duplicated the code in your search method, you have to be sure to update all copies of it.

This is an example of a violation of the Single Responsibility Principle (as it pertains to methods). A simple way to fix this is to pull the ORM code out into a separate method and call it. This would let us re-use it in our search method:

   1: public User GetUser(string userName)
   2: {
   3:   string sql = "select UserName, FirstName, LastName, Email "
   4:              + "from Users where UserName = @UserName";
   5:
   6:   using (SqlConnection connection = new SqlConnection(...))
   7:   using (SqlCommand command = new SqlCommand(sql, connection))
   8:   {
   9:     command.Parameters.Add("@UserName", SqlDbType.VarChar).Value = userName;
  10:     using (SqlDataReader reader = command.ExecuteReader())
  11:     {
  12:       if (!reader.Read())
  13:         return null;
  14:       else
  15:         return ReadUser(reader);
  16:     }
  17:   }
  18: }
  19:
  20: public List<User> GetAllUsersByLastName(string lastName)
  21: {
  22:   List<User> results = new List<User>();
  23:
  24:   string sql = "select UserName, FirstName, LastName, Email "
  25:              + "from Users where LastName = @LastName";
  26:
  27:   using (SqlConnection connection = new SqlConnection(...))
  28:   using (SqlCommand command = new SqlCommand(sql, connection))
  29:   {
  30:     command.Parameters.Add("@LastName", SqlDbType.VarChar).Value = lastName;
  31:     using (SqlDataReader reader = command.ExecuteReader())
  32:     {
  33:       while (reader.Read())
  34:         results.Add(ReadUser(reader));
  35:     }
  36:   }
  37:
  38:   return results;
  39: }
  40:
  41: private User ReadUser(IDataRecord record)
  42: {
  43:   User user = new User();
  44:
  45:   user.UserName = record.GetString(0);
  46:   user.FirstName = record.GetString(1);
  47:   user.LastName = record.GetString(2);
  48:   user.Email = record.GetString(3);
  49:
  50:   return user;
  51: }

This is getting better, but we’ve still got a bunch of boilerplate code. How do we get rid of it?

First, a quick introduction to the functional programming capabilities in C# 2.0. There are a few basic delegate definitions built into the System namespace. If you haven’t used them before, here they are:

   1: delegate void Action<T>(T obj);
   2: delegate bool Predicate<T>(T obj);
   3: delegate TOutput Converter<TInput, TOutput>(TInput input);

These drive the functional capabilities that are seeping into the .NET base class library. For example, List<T> has a ForEach method, which accepts an Action<T> and executes it for each item in the list.

What might not be immediately apparent is that many existing methods already match the signatures of these delegates. In our case, our ReadUser method is actually a Converter<IDataRecord, User>, which just means that it’s a method that takes an IDataRecord as input, and returns a User. Combined with the automatic delegate creation feature of C# 2.0, this means that anywhere a Converter<IDataRecord, User> is expected, we can pass in ReadUser.

Let’s try to flex these newfound functional programming muscles to solve our boilerplate code problem. Let’s create a “helper” class that can abstract out what we want to do:

   1: static class DbHelper
   2: {
   3:   public static T ExecuteAndReadOne<T>(DbCommand command, Converter<IDataRecord, T> readMethod)
   4:   {
   5:     using (DbDataReader reader = command.ExecuteReader())
   6:     {
   7:       if (!reader.Read())
   8:         return default(T);
   9:       else
  10:         return readMethod(reader);
  11:     }
  12:   }
  13:
  14:   public static List<T> ExecuteAndReadAll<T>(DbCommand command, Converter<IDataRecord, T> readMethod)
  15:   {
  16:     List<T> results = new List<T>();
  17:
  18:     using (DbDataReader reader = command.ExecuteReader())
  19:     {
  20:       while (reader.Read())
  21:         results.Add(readMethod(reader));
  22:     }
  23:
  24:     return results;
  25:   }
  26: }

Consider for a moment what the readMethod parameter actually represents in ExecuteAndReadOne and ExecuteAndReadAll. We’ll be passing in a method, which will be called to do the actual object creation. Using DbHelper means that our original code is simplified significantly:

   1: public User GetUser(string userName)
   2: {
   3:   string sql = "select UserName, FirstName, LastName, Email "
   4:              + "from Users where UserName = @UserName";
   5:
   6:   using (SqlConnection connection = new SqlConnection(...))
   7:   using (SqlCommand command = new SqlCommand(sql, connection))
   8:   {
   9:     command.Parameters.Add("@UserName", SqlDbType.VarChar).Value = userName;
  10:     return DbHelper.ExecuteAndReadOne<User>(command, ReadUser);
  11:   }
  12: }
  13:
  14: public List<User> GetAllUsersByLastName(string lastName)
  15: {
  16:   string sql = "select UserName, FirstName, LastName, Email "
  17:              + "from Users where LastName = @LastName";
  18:
  19:   using (SqlConnection connection = new SqlConnection(...))
  20:   using (SqlCommand command = new SqlCommand(sql, connection))
  21:   {
  22:     command.Parameters.Add("@LastName", SqlDbType.VarChar).Value = lastName;
  23:     return DbHelper.ExecuteAndReadAll<User>(command, ReadUser);
  24:   }
  25: }
  26:
  27: private User ReadUser(IDataRecord record)
  28: {
  29:   User user = new User();
  30:
  31:   user.UserName = record.GetString(0);
  32:   user.FirstName = record.GetString(1);
  33:   user.LastName = record.GetString(2);
  34:   user.Email = record.GetString(3);
  35:
  36:   return user;
  37: }

See how we’re passing in the ReadUser method to the Execute calls? When you build this code, the compiler actually creates a Converter<IDataRecord, User> delegate for ReadUser and passes that into the Execute methods of the DbHelper type.

This is great so far, but we can do better still. Remember the problem with the Email column being nullable? Adding IsDBNull() calls to our reader methods gets old fast, and makes the code look pretty ugly:

   1: private User ReadUser(IDataRecord record)
   2: {
   3:   User user = new User();
   4:
   5:   user.UserName = record.GetString(0);
   6:   user.FirstName = record.GetString(1);
   7:   user.LastName = record.GetString(2);
   8:   user.Email = (record.IsDBNull(3) ? null : record.GetString(3));
   9:
  10:   return user;
  11: }

Doesn’t look too bad now, but in a realistic database table with 50 columns, 25 of which are nullable, it’ll get irritating. Also, if we change the nullability of a field, we have to always remember to add the check to our ReadUser method. (What? A database that changes? Never! :)

However, consider the GetString method of the IDataRecord interface (which our SqlDataReader implements). It takes an integer (the index of the column) and returns a string. That means it qualifies as a Converter<int, string>!

We can use this knowledge to add a couple methods to DbHelper to abstract out the DBNull checks:

   1: static class DbHelper
   2: {
   3:   // ...
   4:
   5:   public static T SafeRead<T>(IDataRecord record, int index, Converter<int, T> readMethod)
   6:   {
   7:     return SafeRead<T>(record, index, readMethod, default(T));
   8:   }
   9:
  10:   public static T SafeRead<T>(IDataRecord record, int index, Converter<int, T> readMethod, T defaultValue)
  11:   {
  12:     if (record.IsDBNull(index))
  13:       return defaultValue;
  14:     else
  15:       return readMethod(index);
  16:   }
  17: }

The first SafeRead overload will return the default value for the specified type if the field is null. The second overload lets you specify your own value to return on null instead. This is useful in cases when you want to return a special flag value for null entries — for example, if it’s an integer column, but zero is a valid value.

Now, we don’t need to worry about nulls in our ReadUser method:

   1: private User ReadUser(IDataRecord record)
   2: {
   3:   User user = new User();
   4:
   5:   user.UserName = DBHelper.SafeRead<string>(record, 0, record.GetString);
   6:   user.FirstName = DBHelper.SafeRead<string>(record, 1, record.GetString);
   7:   user.LastName = DBHelper.SafeRead<string>(record, 2, record.GetString);
   8:   user.Email = DBHelper.SafeRead<string>(record, 3, record.GetString);
   9:
  10:   return user;
  11: }

We’re actually passing the GetString method of our record object to the SafeRead method. The SafeRead method will do the null check, and if the field is not null, it will call the GetString method to get its value. If the field contains a null value, GetString will not be called.

There’s one final thing to implement, and in my opinion, is pretty friggin’ cool. There’s a static type in the System namespace called Convert, which contains a bunch of static methods that do conversion. For example, there’s a method called Convert.ToDateTime takes an object and returns a DateTime. Get it? It’s a Converter<object, DateTime>!

Here’s a couple additional methods to add to DbHelper:

   1: static class DbHelper
   2: {
   3:   //...
   4:
   5:   public static T ExecuteScalar<T>(DbCommand command, Converter<object, T> converter)
   6:   {
   7:     return ExecuteScalar<T>(command, converter, default(T));
   8:   }
   9:
  10:   public static T ExecuteScalar<T>(DbCommand command, Converter<object, T> converter, T defaultValue)
  11:   {
  12:     object result = command.ExecuteScalar();
  13:     return (result == DBNull.Value) ? defaultValue : converter(result);
  14:   }
  15: }

These methods work essentially like the SafeRead methods, only calling the provided conversion method if the scalar value returned by the query is not null. Now, if you want to run a query that returns a single value (say a string), which may be null, it’s easy:

   1: public string GetEmail(string userName)
   2: {
   3:   string sql = "select Email "
   4:              + "from Users where UserName = @UserName";
   5:
   6:   using (SqlConnection connection = new SqlConnection(...))
   7:   using (SqlCommand command = new SqlCommand(sql, connection))
   8:   {
   9:     command.Parameters.Add("@UserName", SqlDbType.VarChar).Value = userName;
  10:     return DbHelper.ExecuteScalar<string>(command, Convert.ToString);
  11:   }
  12: }

If you’re used to a static language, it takes some time to get used to treating methods more like variables. However, as you can see, it can make your code cleaner and more elegant — not to mention smarter and less prone to bugs!

If you’d like to download the DbHelper class used in this project, it’s available here.

Defending Dependency Injection

A few days ago, I read an article on Jacob Proffitt’s blog (Scruffy-Looking Cat Herder) about dependency injection. In the article, Jacob questions whether there are real benefits of dependency injection (DI) above and beyond additional testability. I challenged his stance in a comment, and he replied. I highly suggest that you read the article and the comments, because he’s posing a very good question.

First, a couple of definitions, in case you’re not familiar:

  1. Cohesion is the measure of semantic similarity between the code in a given logical segment. Highly-cohesive code is better code. (See also the Single Responsibility Principle, the optimal level of cohesion in object-oriented software.)
  2. Coupling is the measure of how much a given logical segment of code relies on other segments. Loosely-coupled code is better code.

Essentially, Jacob asserts that dependency injection raises the coupling in your code by pushing the need to understand dependencies of a given type outside of the type itself. As he says:

How can you say that dependency injection…creates loosely coupled units that can be reused easily when the whole point of DI is to require the caller to provide the callee’s needs? That’s an increase in coupling by any reasonable assessment.

This was precisely my first thought when I was originally exposed to the idea of dependency injection, because it goes directly against what we’ve been taught about object-oriented programming. The principle of encapsulation, one of the pillars of object-oriented design, states that if information doesn’t need to be exposed publicly from a class, it should be hidden from any code that consumes it. Encapsulation of data and logic is great, because it reduces the surface area of your classes, making it easier to understand how they work, and more difficult to break them.

Here’s the secret that makes dependency injection worthwhile: when it comes to dependencies, encapsulation is bad.

Consider the following code:

   1: public abstract class Engine
   2: { ... }
   3:  
   4: public class V6Engine : Engine
   5: { ... }
   6:  
   7: public class Car
   8: {
   9:   private readonly Engine _engine;
  10:   public Car()
  11:   {
  12:     _engine = new V6Engine();
  13:   }
  14: }
  15:  
  16: public class Program
  17: {
  18:   public static void Main()
  19:   {
  20:     // Car will always have a V6 engine.
  21:     Car car = new Car();
  22:   }
  23: }

There’s nothing “wrong” with this code. It works fine, and shows good use of polymorphism. But your Car type, by definition, will always have a V6 engine. But what happens if you need to create a car with a four-cylinder engine? You have to modify the implementation of the Car type. What if it was implemented by a third party and you don’t have the source?

Contrast the previous snippet with this one:

   1: public abstract class Engine
   2: { ... }
   3:  
   4: public class V6Engine : Engine
   5: { ... }
   6:  
   7: public class VTECEngine : Engine
   8: { ... }
   9:  
  10: public class Car
  11: {
  12:   private readonly Engine _engine;
  13:   public Car(Engine engine)
  14:   {
  15:     _engine = engine;
  16:   }
  17: }
  18:  
  19: public class Program
  20: {
  21:   public static void Main()
  22:   {
  23:     Car v6car = new Car(new V6Engine());
  24:     Car acuraTsx = new Car(new VTECEngine());
  25:   }
  26: }

Now we can create all sorts of cars with all sorts of engines. If you’re a GoF fan, this is actually the Strategy pattern. Dependency injection (in my perspective) is basically the Strategy pattern used en masse.

However, as Jacob has pointed out, all we’ve done is pushed the requirement for creating an Engine out into the code that consumes our Car class. Jacob is 100% correct in saying that this increases your coupling. Now, instead of Car being the only type coupled to Engine, both Car and Program are essentially coupled to Engine, because to create a Car, you must first create an Engine.

This is why dependency injection frameworks like Ninject, Castle Windsor, and StructureMap exist: they fix this coupling problem by washing your code clean of the dependency resolution logic. In addition, they provide a deterministic point, in code or a mapping file, that describes how the types in your code are wired together.

This leads me to my assertion that dependency injection leads to creating loosely-coupled and highly-cohesive code. Once you start writing code that relies on a DI framework, the cost required to wire objects together falls to next to zero. As a consequence, hitting the goal of Single Responsibility becomes exponentially simpler. Put another way, you are less likely to leave cross-cutting logic in a type where it doesn’t belong. Your MessagingService needs configuration? No problem, write a ConfigurationService and add a dependency to it. Better yet, make your MessagingService dependent on an IConfigurationService interface, and then later when you’re reading configuration from a database rather than an XML file, you won’t have to go through each of your services and rewrite their configuration logic.

Jacob also asks why we don’t just use a Factory pattern (much like the provider model in ADO.NET, which he uses as an example in his article). Factory patterns are great for small implementations, but like dependency-injection-by-hand it can get extremely cumbersome in larger projects. Abstract Factories are unwieldy at best, and relying on a bunch of static Factory Methods (to steal a phrase from Bob Lee) gives your code “static cling” — static methods are the ultimate in concreteness, and make it vastly more difficult to alter your code.

I mentioned in the comment on his article that I saw the “light” when it came to dependency injection, and Jacob asked me to share the light with him. Here it is: simply put, dependency injection makes your code easier to change. That’s why it’s so popular in Agile crowds, whose whole software development practice is geared around quick alterations in path.

Is it a silver bullet? No. Is it the only way to make code easy to change? No. Is it the best way? Maybe not. But it’s the best I’ve seen so far.