In-House Dev Anti-pattern: Environmental Certainty

In-house developers (software developers that work for an IT department and not a software development firm) openly condemn their plight of being tasked to design software quickly rather than correctly.

In-house developers rely on environmental certainty. We have a comfortable technical environment.  We have our data sources, our common web services, a monolith HR system, and these things never change

Right?  Never?  ...

Mergers, acquisitions, vendor changes, new technologies, staff changes, user requests, management fiat, budgetary constraints...

To overly rely on your environment is an anti-pattern for corporate developers.

My company was acquired in November by a huge mammoth company that isn't asking questions about why our data sources are useful. Our technical environment is about to radically change.

Fortunately it's not hard to reduce dependencies on certain external services in our applications.  Here is a real-world five-minute example with a scenario should be familiar to most in-house devs.

Interfaces define the implementation

There's a web application.  In it we like to do things with the currently logged in user.  Show data specific to that user, display the user's real name, etc.  We call a web service to get the full name from the login name. I'd wager that almost every moderate-sized company has a "directory" web service like this.

public class GetFullNameService
{
public string GetFullName(string username)
{
string fullname;
// call your web service and get the full name
return fullname;
}
}

Great, wonderful, okay.  But to prepare for an eventual change in environment, we should write an interface so that we can switch out the implementation using dependency injection.

public interface IGetFullNameService
{
string GetFullName(string username);
}

This is useful because my new implementation (the one that will work after the acquisition is complete) is totally different, in fact instead of a web service it uses ADO.NET against OHR.

public class OHRFullNameService : IGetFullNameService
{
public string GetFullName(string username)
{
// use ADO.NET to call OHR
return "full name";
}
}

Since I am programming against an interface and have written a new implementation I can just do a find and replace and change all the GetFullNameService calls to call OHRFullNameService, rebuild, redeploy and ... um, no.

Using dependency injection to swap out implementations

So now we have an interface and two implementations. In the application, we might see something like

public class BasePage : Page
{
private IGetFullNameService _nameService;

public BasePage()
{
_nameService = new GetFullNameService();
}
}

Instead of newing up a concrete type we can use dependency injection to create the instance for us:

public class BasePage : Page
{
private IGetFullNameService _nameService;

public BasePage()
{
_nameService = (IGetFullNameService)
ObjectFactory.GetInstance(typeof (IGetFullNameService));
}
}

Now our BasePage class doesn't care which implementation of IGetFullNameService we use!

Configuring the dependency injection container (StructureMap, in this example) is super easy.  You can set this up to use attributes instead of a configuration file.  But here is a simple, sample StructureMap.config:

<?xml version="1.0" encoding="utf-8" ?>
<
StructureMap>
<
PluginFamily
Type="MyProject.Web.Services.IGetFullNameService"
Assembly="MyProject.Web"
DefaultKey="Default">
<
Plugin Assembly="MyProject.Web"
Type="MyProject.Web.Services.GetFullNameService"
ConcreteKey="Default"/>
<
Plugin Assembly="MyProject.Web"
Type="MyProject.Web.Services.OHRFullNameService"
ConcreteKey="OHR"/>
</
PluginFamily>
</
StructureMap>

Changing the implementation fro GetFullNameService to OHRFullNameService is as easy as changing the DefaultKey attribute of the PluginFamily element to "OHR".

So we've successfully eliminated our dependency on one aspect of our technical environment and we are secure knowing that if our environment changes, we can handle it easily.

So this is just the start down a deep rabbit hole.  There are a few more considerations if you are developing an application using dependency injection that I have omitted from this post.  Fortunately there are resources out there.. a good starting place is Jeremy Miller's blog and my links to DI resources.

Published Tuesday, February 12, 2008 7:44 AM by mhinze

Comments

No Comments