-
Featured Posts
Wednesday, 26 February 2014
My Hardy Little Friend: Coding the Arduino in C++ - Choosing a development...
My Hardy Little Friend: Coding the Arduino in C++ - Choosing a development...: So now that we have decided what language to write the code in, we need to decide what development environment we want to use, and with th...
Monday, 9 December 2013
Dependency Inversion in Go - Introduction
Introduction
The fact that you have landed on this page is a strong indication that you are aware of the existence of the go language.
The language itself was originally created by three Google developers back in 2007 (though officially released to the world in 2009) in their spare time, but it has since gone on to be one of the hottest new languages on the market and is even used by Google to power some of their own services.
Although a relatively young language, there is a big community of developers using it, and some of these are approaching the language in very much a craftsman like manner, and these developers are looking for ways to use principles like SOLID with it.
This is not a post about the merits of SOLID in go, what I want to cover here is one aspect of SOLID, Dependency Inversion Principle, and how you can apply DIP to go code.
The language itself was originally created by three Google developers back in 2007 (though officially released to the world in 2009) in their spare time, but it has since gone on to be one of the hottest new languages on the market and is even used by Google to power some of their own services.
Although a relatively young language, there is a big community of developers using it, and some of these are approaching the language in very much a craftsman like manner, and these developers are looking for ways to use principles like SOLID with it.
This is not a post about the merits of SOLID in go, what I want to cover here is one aspect of SOLID, Dependency Inversion Principle, and how you can apply DIP to go code.
Requirements of Dependency Inversion
The principle of Dependency Inversion, is to remove hardwired dependencies from any code that you write, further more functions, structs, and even packages should only depend on abstractions of other modules, and not the module itself.
This can be achieved in many ways, and some of the standard methods are:
This can be achieved in many ways, and some of the standard methods are:
- Separated Interface Pattern
- Dependency Injection
- Inversion of Control
- Adapter Pattern
DI Options
So what are my options as far as Dependency Injection is concerned in the go language. Well this is not an exhaustive review of all of the libraries, and if you know of others that you think are worth exploring please feel free to let me know, but at the time of writing this post the three packages below stood out as promising.
Over the next couple of posts I will go through each option detailed above, give some background about each, as well as, with the use of a simple example discuss the good and bad points of each option.
Next: Simple IoC >>
- go-inject
- go.inject
- depinject
Over the next couple of posts I will go through each option detailed above, give some background about each, as well as, with the use of a simple example discuss the good and bad points of each option.
Next: Simple IoC >>
Links
Dependency Inversion in Go - IntroductionDependency Inversion in Go - Simple IoC
Dependency Inversion in Go - go-inject
Dependency Inversion in Go - go.inject
Dependency Inversion in Go - depinject
Dependency Inversion in Go - Summary
Dependency Inversion in Go - Simple IoC
There are many out there who seem stumped by Dependency Inversion Principle (DIP) in go, especially if they don't have experience of it in other languages it can seem a lot of work for little payoff. Those that do persevere often, like myself, immediately go off and look for a third party Dependency Injection (DI) package, but it turns out that it is relatively easy to implement DIP, via Inversion of Control (IoC), and can be achieved using the built in functions of go.
First things first, the functions required to implement IoC are in the language, but a simple description of how to do it is hard to find.
So what does this achieve? Well at the simplest level the functions are not directly coupled to an object, and so other objects, based on the same interface, can substitute in and used. This comes into it's own in two particular scenarios, unit testing and ability to plug different providers into the application.
In unit testing, we are able to create mocked/fake objects to ensure that the unit tests are only testing a unit of code, and not the infrastructure beneath it.
In the plug-in case, this enables us to change systems such as databases, and message queues, relatively easily, and in a way that means that the original providers can be switched back in without reverting too much code.
First things first, the functions required to implement IoC are in the language, but a simple description of how to do it is hard to find.
What is IoC?
At it's simplest level the basic concept of IoC is that any code that needs an object does not create it, rather the objects are already available and an implementation can be reused, and in go this can be implemented using factory functions defined on startup and stored in a map. Using this method the actual binding is not done by a function, function uses the factory to get the object, usually reference by it's interface.So what does this achieve? Well at the simplest level the functions are not directly coupled to an object, and so other objects, based on the same interface, can substitute in and used. This comes into it's own in two particular scenarios, unit testing and ability to plug different providers into the application.
In unit testing, we are able to create mocked/fake objects to ensure that the unit tests are only testing a unit of code, and not the infrastructure beneath it.
In the plug-in case, this enables us to change systems such as databases, and message queues, relatively easily, and in a way that means that the original providers can be switched back in without reverting too much code.
Example
The example below is based on a imaginary car sales system. The idea is that when ordering a car the request must go to a car factory that builds that particular model.
The code is broken down into it's four key areas, these being the interfaces, the concrete implementations, the 'class' factories (I know classes don't actually exist in go), and a method that defines the mapping of the objects and later uses those objects to get details of the car that has been 'built'.
If you are new to DIP you might struggle to understand how this benefits development, but if you study the code closely, and particular the main function, it should become obvious that if you wanted to substitute the make and model of car, you can register a new factory and use pass the key for this factory into the 'class' factory instead of the existing "Ford" key.
The code is broken down into it's four key areas, these being the interfaces, the concrete implementations, the 'class' factories (I know classes don't actually exist in go), and a method that defines the mapping of the objects and later uses those objects to get details of the car that has been 'built'.
If you are new to DIP you might struggle to understand how this benefits development, but if you study the code closely, and particular the main function, it should become obvious that if you wanted to substitute the make and model of car, you can register a new factory and use pass the key for this factory into the 'class' factory instead of the existing "Ford" key.
Loading ....
Summary
In summary, the simple IoC example above does provide a very straight forward option to DIP, but it isn't perfect. In the ideal world we want to setup object mappings at runtime and not build time, which is what we have here, is it possible? Very much so, and in future posts I will look to take the example and update it to be driven from a configuration file.
Would I recommend this as a path to implementing SOLID principles? I think if done properly using this approach would work well, especially on smaller projects.
Would I recommend this as a path to implementing SOLID principles? I think if done properly using this approach would work well, especially on smaller projects.
<< Previous: Introduction Next: go-inject >>
Links
Dependency Inversion in Go - IntroductionDependency Inversion in Go - Simple IoC
Dependency Inversion in Go - go-inject
Dependency Inversion in Go - go.inject
Dependency Inversion in Go - depinject
Dependency Inversion in Go - Summary
Dependency Inversion in Go - go-inject
| GoDoc | http://godoc.org/code.google.com/p/go-inject |
| Code | https://code.google.com/p/go-inject/ |
| License | Apache License, Version 2.0 |
This library has been created, and open sourced by Jason Kinner, who although he does work for Google, is not associated with the go project.
The style of dependency injection that go.inject uses is reflection.
The style of dependency injection that go.inject uses is reflection.
Example
The example below is based on the same imaginary car sales system as used in the previous post. The idea is that when ordering a car the request must go to a car factory that builds that particular model.
The code is broken down into it's four key areas, these being the interfaces, the concrete implementations, injector tags, and a method that defines the mapping of the objects and later uses those objects to get details of the car that has been 'built'.
As with the previous post a quick look at the code, and the main function, and it should be obvious that if you wanted to substitute the make and model of car, you can change the object returned by the GetCarFactory struct to a new factory instead of the FordFactory used.
The code is broken down into it's four key areas, these being the interfaces, the concrete implementations, injector tags, and a method that defines the mapping of the objects and later uses those objects to get details of the car that has been 'built'.
As with the previous post a quick look at the code, and the main function, and it should be obvious that if you wanted to substitute the make and model of car, you can change the object returned by the GetCarFactory struct to a new factory instead of the FordFactory used.
Loading ....
Summary
In summary, the go-inject example above does provide a relatively straight forward option to DIP, but like the IoC option previous, it isn't perfect, and beyond that is not as easy to extend and improve. As before we would ideally want to setup object mappings at runtime and not build time, unlike the IoC post it wouldn't be as simple to achieve, however time permitting I may look at branching the library and include a configuration driven approach.
Would I recommend this as a path to implementing SOLID principles? Although not as simple to do, it be achieved, though I may be tempted to use it on smaller projects only.
Would I recommend this as a path to implementing SOLID principles? Although not as simple to do, it be achieved, though I may be tempted to use it on smaller projects only.
Links
Dependency Inversion in Go - IntroductionDependency Inversion in Go - Simple IoC
Dependency Inversion in Go - go-inject
Dependency Inversion in Go - go.inject
Dependency Inversion in Go - depinject
Dependency Inversion in Go - Summary
Dependency Inversion in Go - go.inject
| GoDoc | http://godoc.org/github.com/ParsePlatform/go.inject |
| Code | https://github.com/ParsePlatform/go.inject |
| License | Apache License, Version 2.0 |
This library has been created, and open sourced by the guys over at Parse, a provider of a cloud based backend system designed for mobile development, and a major contributor to the open source community.
The style of dependency injection that go.inject uses is reflection
Example
The example below is based on the same imaginary car sales system as used in the previous posts. The idea is that when ordering a car the request must go to a car factory that builds that particular model.
The code is broken down into it's three key areas, these being the interfaces, the concrete implementations, and a method that defines the mapping of the objects and later uses those objects to get details of the car that has been 'built'.
As with the previous post a quick look at the code, and the main function, and it should be obvious that if you wanted to substitute the make and model of car, you can change the object mapped in the graph. One key downside to this package is that it's not as flexible as the two previous packages and to truely achieve the functionality of the other examples a larger level of refactoring would be required.
The code is broken down into it's three key areas, these being the interfaces, the concrete implementations, and a method that defines the mapping of the objects and later uses those objects to get details of the car that has been 'built'.
As with the previous post a quick look at the code, and the main function, and it should be obvious that if you wanted to substitute the make and model of car, you can change the object mapped in the graph. One key downside to this package is that it's not as flexible as the two previous packages and to truely achieve the functionality of the other examples a larger level of refactoring would be required.
Loading ....
Summary
In summary, the go.inject example above does provide an option for DIP, but it is neither straightforward, or perfect. As before we would ideally want to setup object mappings at runtime and not build time, in the case of go.inject, achieving this is a not inconsiderable task, and with other options out there I don't see a reason for extending this library to include a configurable approach.
As for a recommendation, my personal view is that there are better options out there.
<< Previous: go-inject Next: depinject >>
As for a recommendation, my personal view is that there are better options out there.
<< Previous: go-inject Next: depinject >>
Links
Dependency Inversion in Go - IntroductionDependency Inversion in Go - Simple IoC
Dependency Inversion in Go - go-inject
Dependency Inversion in Go - go.inject
Dependency Inversion in Go - depinject
Dependency Inversion in Go - Summary
Dependency Inversion in Go - depinject
| GoDoc | http://godoc.org/github.com/99designs/goodies/depinject |
| Code | https://github.com/99designs/goodies/tree/master/depinject |
| License | The MIT License (MIT) |
This library is part of a much larger library created, and open sourced by the guys over at 99designs, a provider of website design and hosting, as well as a major contributor to the open source community.
The style of dependency injection that depinject uses is reflection.
The style of dependency injection that depinject uses is reflection.
Example
The example below is based on the same imaginary car sales system as used in the previous posts. The idea is that when ordering a car the request must go to a car factory that builds that particular model.
The code is broken down into it's three key areas, these being the interfaces, the concrete implementations, and a method that defines the mapping of the objects and later uses those objects to get details of the car that has been 'built'.
As with the previous post a quick look at the code, and the main function, and it should be obvious that if you wanted to substitute the make and model of car, you can change the factory functions registered against the types. As with go.inject this package is that it's not as flexible as the first two packages and to truly achieve the functionality of the other examples a larger level of refactoring would be required.
The code is broken down into it's three key areas, these being the interfaces, the concrete implementations, and a method that defines the mapping of the objects and later uses those objects to get details of the car that has been 'built'.
As with the previous post a quick look at the code, and the main function, and it should be obvious that if you wanted to substitute the make and model of car, you can change the factory functions registered against the types. As with go.inject this package is that it's not as flexible as the first two packages and to truly achieve the functionality of the other examples a larger level of refactoring would be required.
Loading ....
Summary
In summary, as with go.inject, the example above does provide an option for DIP, but it is again neither straightforward, or perfect. As before we would ideally want to setup object mappings at runtime and not build time, in the case of depinject, achieving this is a not inconsiderable task, and with other options out there I don't see a reason for extending this library to include a configurable approach.
As for a recommendation, my personal view is that there are better options out there.
<< Previous: go.inject Next: Summary >>
As for a recommendation, my personal view is that there are better options out there.
<< Previous: go.inject Next: Summary >>
Links
Dependency Inversion in Go - IntroductionDependency Inversion in Go - Simple IoC
Dependency Inversion in Go - go-inject
Dependency Inversion in Go - go.inject
Dependency Inversion in Go - depinject
Dependency Inversion in Go - Summary
Dependency Inversion in Go - Summary
Summary
After looking at a number of the options out there for implementing Dependency Inversion Principle (DIP) in go, there seems to be two obvious options.
The first is using Inversion of Control (IoC), and as we have seem the basics are there in the base code. It can also be seen that extending this to include features such as configuration driven binding is very possible.
The other option is Dependency Injection (DI), however of the three packages we have looked at, it looks from my viewpoint that only one is straightforward enough to use, and is probably the one best positioned to be extended.
In future posts I will look into extending these two approaches, hopefully producing two complete processes for implementing DIP in go.
If you would like to download and try the samples used in these posts please check out the following git repo: commentsondev
<< Previous: depinject
The first is using Inversion of Control (IoC), and as we have seem the basics are there in the base code. It can also be seen that extending this to include features such as configuration driven binding is very possible.
The other option is Dependency Injection (DI), however of the three packages we have looked at, it looks from my viewpoint that only one is straightforward enough to use, and is probably the one best positioned to be extended.
In future posts I will look into extending these two approaches, hopefully producing two complete processes for implementing DIP in go.
If you would like to download and try the samples used in these posts please check out the following git repo: commentsondev
<< Previous: depinject
Links
Dependency Inversion in Go - IntroductionDependency Inversion in Go - Simple IoC
Dependency Inversion in Go - go-inject
Dependency Inversion in Go - go.inject
Dependency Inversion in Go - depinject
Dependency Inversion in Go - Summary
Subscribe to:
Posts (Atom)






ReadABlog.com