.

Matthew Rathbone's Blog

I was tagged in: vba ioc dependency injection csharp

Monday, November 10, 2008

Regardless of how much time Microsoft invests into developing Visual Studio Tools for Office there’s still going to be a market for VBA, but that doesn’t mean we have to compromise our methodologies or best practices.

Dependency injection in VBA is not only possible, but it’s not as much work to implement as you might think. Sure VB6’s system for Interface inheritance leaves a lot to be desired, and it’s a whole lot less flexible than modern languages, but you can still add a massive amount of flexibility and control to your code through a little thought and planning.

There are a few key things we need for a basic IoC implementation.

1. Interfaces for key dependencies that we want to ‘inject’ (for example a data-repository)
2. A centralized way to change what concrete object is mapped to that interface by default
3. A way to inject that concrete object upon creation of a dependant object (as VBA does not allow you to pass parameters on construction)

Let’s address how to do each of these things in turn:

Interfaces

Interfaces in VBA are created by making a class and populating it with stub methods and properties which don’t do anything, that’s it. You don’t have to declare it as an interface, but it would probably make sense to prefix the name with an ‘I’.
For example, here’s an interface for IDataSource:


Option Explicit
Public Function GetOrders(customerID As String) As collection
End Function
Public Function GetAllOrders() As collection
End Function

Easy!

And here’s a basic example implementation of that interface:

Option Explicit
Implements IDatasource
Public Function IDatasource_GetOrders(customerID As String) As collection
	Dim returnCollection As New collection

	returnCollection.Add ("Item1")
	'Collection logic here
	Set IDatasource_GetOrders = returnCollection
End Function

Public Function IDatasource_GetAllOrders() As collection
	Dim returnCollection As New collection

	returnCollection.Add ("Item1")
	returnCollection.Add ("Item2")
	'Collection logic here
	Set IDatasource_GetAllOrders = returnCollection

End Function


Object Mapping

Because we don’t have use of Unity, Spring.net, or any other IoC framework, the simplest thing to do is to completely dedicate a module to the job of being an ‘object provider’

Because VBA doesn’t need to be compiled, it’s almost as easy as using a configuration file as you can change it on the fly without having to recompile and redeploy.

Additionally, if you want to externalize the assignment of concrete objects to a configuration file, you can just extend this basic object.

Here is an example of a simple object provider:

Option Explicit
'set your bindings here
Private mDataSource As New SqlDataSource
Public Property Get DataSource() As IDatasource
Set DataSource = mDataSource
End Property

All you have to do is chage the type of the private members to switch the default concrete class.

Dependency Injection

VBA doesn’t allow us to have non-default class constructors, which means we cannot construct objects like below:

Dim dataService as new OrderService(SqlRepository)


Instead we simple have to be a little more creative with our objects, I tend to add a method called Initialize which takes a IDataRepository class. If you haven’t initialized the class, no methods that rely on this private member will work, which acts as a failsafe:

Dim repository as IOrderRepository
Dim dataService as new ObjectService
Set repository = ObjectProvider.OrderRepository
dataService.Initialize repository

 

Summary

Coding VBA can be frustrating and confusing when one is used to more elegant languages and frameworks, but that doesn’t mean it’s impossible to import modern programming strategies and methodologies.

Using inversion of control in any framework promotes code reuse, separates concerns, and makes for more manageable maintenance going forwards. Working with an outdated framework does not mean one has to write code like it’s 1995.
 

0 Comments

Page: 1 

Copyright Matthew Rathbone 2008 © : about me : contact