Vendor Lock-In Vs. Best Of Breed Tools
I posted the bulk of this on the Albacore group as a reason for my wanting to take Albacore down to it’s “core” as a suite of build related tasks (which I talked about in the Preview1 post). However, I thought the information was enough to warrant it’s own post on my blog… so here it is: why I think best-of-breed tools that you tie together yourself tend to be better than the all-in-one vendor lock-in approach.
As a .net developer, I’m used to seeing the "all in one" solutions being handed to us by various vendors. Microsoft gives us Visual Studio, they give of Office, they give us Team Foundation Server. Telerik gives us UI controls for WinForms, Web, WPF, and even an ORM and test framework. Oracle provides a database engine, business rules / erp system and much much more. It's the nature of software-as-a-business model, to a certain extent – at least in the .NET world. Vendors want you to use their tools because they need to make money. So it makes sense for every vendor to offer complete solutions that work well with their own items. You see a lot of integration and interop between the products that one particular company produces.
Unfortunately, this has a ripple-effect into the open source efforts in .NET as well. There tend to be a lot of the same things being done by many different people because everyone expects to see a one-stop-shop for the things that go hand-in-hand.
In the ruby world (and in the *nix world in general), you don't see this very often, if at all. You see many individual pieces being put together to create something that is larger than the sum of the individual parts. Many of the small pieces that one large system uses will be pulled from many different vendors, and each of them will do their one specific thing really really well. Look at Rails3 for example. There’s the core of Rails, but there’s also the direct use of Thor, the SQLite integration, the Test::Unit and RSpec integration, the Rake integration, etc. There are so many parts of what Rails is that most people outside of the ruby world tend to think that Rails is the only thing that ruby does (yes, I have heard people say things close to this).
Looking back at my development experience, I’ve been exposed to both worlds – the vendor lock-in world and the best-of-breed world. At this point in my career, I prefer the many-tools, best-of-breed approach. I've done the whole vendor-lockin thing with one stop shops and it has burned me more times than i can count. There are inevitably issues that I have with the toolset and/or things I want to do that the toolset just can’t do, and I’m stuck. I am using the tools that don’t do what I need and often can’t do anything about that. Having taken the other approach in the tools and vendors that i choose over the last 4 years or so, I find it to be overall better. Instead of locking me into VS+TFS and the "one microsoft way", for example, I found subversion + trac + apache. Later, trac no longer served my needs so i switched to redmine. When that no longer served, I dropped trac and apache and went to VersionOne (letting them host it). Now that subversion is no longer fitting my needs, I am in progress of dropping it for git.
The best-of-breed mentality and capabilities of many small pieces gives me flexibility and control in situations like this.
Now this doesn’t mean that I won’t choose a vendor simply because they are an all-in-one package. There are times when that package is going to be the right tool for the job at hand, and those tools should be consider and used when appropriate. The point I’m making is that when you do select a tool – any tool – be sure that you are selecting the tool that fits your needs for what they are, and be sure to find tools that allow you to change according to how you need to change. Chances are, the big all-in-one tool (like TFS) is not going to be sufficient for every one of your needs unless you are willing to bend your needs to what the tool can do. And that, quite frankly, is the wrong thing to do. A good selection of the best-of-breed tools may take a little more time to set up and learn, but it will likely pay for itself in the long run when you are able to replace one or more pieces to keep up with your team’s needs.
How To Build Custom Rake Tasks; The Right Way
A long time ago (last year) I wrote a few blog posts that talked about how I was going about creating some custom rake tasks. This turned out to be the beginning of my albacore project and I’ve been working on that project for nearly a year now. It’s been a lot of fun and I’ve learned a lot in the process of creating and maintaining it. One of the things I learned recently is that the way I am currently handling task creation – the way that I talked about in those posts – is not the best way to do it. There is, in fact, a much easier way to create a custom rake task: the Rake::Task.define_task method.
A Simple Rake Task
The following code creates a rake task called “foo”, then defines a task named :bar and sets it up to run as the default task.
1: def foo(*args, &block)
2: Rake::Task.define_task(*args, &block)
3: end
4:
5: foo :bar do
6: puts "this is coming from the task called :bar, which is a foo task"
7: end
8:
9: task :default => [:bar]
Lines 1 through 3 show how simple it actually is to define a rake task. Obviously I haven’t done anything useful with this task, but it illustrates the point. The call to Rake::Task.define_task on line 2 is where the real magic happens. Well, ok… there’s nothing magical about this… at all. I’ve defined a method on line 1 and I’ve called that method on line 5. the name :bar is passed into the *args parameter and the do … end block is passed into the &block parameter. Both of those are then passed into the define_task method. Running rake on this rakefile produces the simple message that you see in the puts statements on line 6.
A Useful Rake Task
At this point, any valid ruby code you want can be used to define a rake task. You only need to provide a minimum of a name to the define_task method and you’re good to go. The code block to define the method body is optional and can be provided by any code that you want. You can also take different parameters than the define_task needs, as long as you provide what define_task needs when it needs it.
For example, you could easily create a very simple task to copy files, like this:
1: def copy(*args, src, dest)
2: body = proc {
3: FileList[src].each do |f|
4: puts "copying #{f} to #{dest}"
5: FileUtils.cp f, dest
6: end
7: }
8: Rake::Task.define_task(*args, body)
9: end
10:
11: copy :copysomefiles, "*.rb", "/temp/"
Line 11 will copy all of the .rb files from the current folder into the temp folder on the root of your drive… more importantly, though, it is a first class citizen in the rake task list, giving you all the capabilities of task depdenencies, parameterized tasks, etc.
1: copy :copyoutput => [:initialize, :build, :test], "**/*.rb", "/myproject/"
2:
3: task :default => :copyoutput
This simple snippet sets up a :copyoutput task with 3 dependencies and then sets up the default task to run it.
Cleaning Up
I’m glad I found this… it is going to greatly simplify the things I have been doing to create rake tasks – especially when it comes to Albacore. The code that I have in Albacore’s create_task method is pretty ugly, involves inheritance and a few other hacks that I’m not so fond of. The worst of it, though, is that it’s very difficult to change because it’s hard to see what’s really happening. Simplifying things down into small methods that call Rake::Task.define_task should greatly improve the infrastructure of Albacore, though.
I hope this information is useful for others, as well. If even one person has that “aha!” moment and realizes how easy it is to create your own rake tasks, than this blog post has done it’s job. :)
Why Is Git Trying To Delete My Project Folder?!
NO! I do NOT want you do delete my project… what’s going on here? why is git trying to delete my project folder?
Albacore v0.2.0 Preview 1 Is Available
A few days ago I pushed a preview version of Albacore up to RubyGems. The intention of doing a preview release was to show everyone the new direction that Albacore is heading and to get feedback from the community on that direction. Things are far from complete in this preview… there is a lot of work that I still want to pack in before the final release of v0.2.0… but there’s already enough change that has occurred, that I think it is time to start getting feedback and making improvements based on that.
Installing The Preview
This is all you need to install the preview version:
1: gem install albacore --pre
The inclusion of ‘--pre’ on the command line will tell the gem system that you want to install the latest preview version of albacore. You will then need to modify your rake file to use the preview version (v0.2.0.preview1):
1: require 'rubygems'
2: gem 'albacore', '=v0.2.0.preview1'
3: require 'albacore'The second line tells the gem system to use the specific version of Albacore that you want, when the Albacore gem is required.
With all that being said, here’s what you can expect from the preview…
Reduced Syntax For Several Attributes
Many of the tasks that Albacore includes are what we call ‘command line tasks’ – these are tasks that call out to a command line tool. In previous releases, all of these tasks had their command line executable (or script or whatever) set through an attribute called ‘.path_to_command’. This lengthy name is hard to type and hard to remember if you don’t use it on a regular basis. With that in mind, we reduced the attribute to ‘.command’. For example:
1: nunit :test do |nunit|
2: nunit.command = "tools/nunit/nunit-console.exe"
3: # other settings here
4: end
A few other tasks have had similar overhauls to specific attributes. the Unzip task, for example, has attributes renamed to ‘.file’ and ‘.destination’ to represent the zip file you want to unzip and where you want the contents sent. These changes should simplify your tasks a little and make them easier to read.
A Few New Tasks
In addition to the CSC task that I’ve already mentioned on this blog, there is also a new SpecflowReport task that let’s you run reports from specflow.
1: specflowreport :specflow do |sfr|
2: sfr.command = "path/to/specflow.exe"
3: sfr.projects "path/to/something.csproj"
4: sfr.reports "nunitexecutionreport"
5: sfr.options "/out:specs.html"
6: end
Default To .NET 4 For MSBuild And CSC
FINALLY!!!!
I do have to apologize to the community of Albacore users for taking so long to get this done. I should have done it in a previous release, but I kept tell myself “no no… I’ll get v0.2.0 out the door soon…” … sorry about that. At long last, though, you no longer have to do any hard coded paths to make it work with .NET 4.
Not using .NET 4? Don’t worry! v0.2.0 will make your life easier, still! You can easily change framework versions with one simple statement in your task definition:
1: msbuild :build do |msb|
2: msb.use :net35
3: # other configuration here
4: end
The .use(version) method is now available on the MSBuild and CSC tasks and let’s you specify which version of .NET you want to use when calling out to the command line. Here’s the current list of supported versions:
- :net2 or :net20 for v2.0.50727
- :net35 for v3.5
- :net4 or :net40 for v4.0.30319
Need another version? Drop us a line or submit a patch and we’ll get it added. (I know that this isn’t anywhere near the complete list. This is what I have on my machine, right now.)
A New Configuration System
This is one of the things I’m most excited about and hopefully something that will make your life even easier, with Albacore. There is a new configuration system that let’s you configure defaults for any attribute of any task in one simple place. Always using .Net 3.5 with MSBuild and don’t want to specify it in every msbuild task? no problem… Always want to use the same .command or .options with nunit? No problem… want to set the .log_level for every task? no problem…
1: Albacore.configure do |config|
2: config.log_level = :verbose
3: config.msbuild.use :net35
4: config.nunit do |nunit|
5: nunit.command = "path/to/nunit-console.exe"
6: nunit.options "/noshadow"
7: end
8: # additional task configuration here
9: end
This Albacore.configure method can be called at the top of your rakefile and it will set the specified attributes for the specified tasks, on every instance of that task, to this default. Of course, you can still override any individual setting within any individual task definition.
In addition to the .configure method, this release of Albacore also makes it easy to configure any specific task through code, using a hash.
1: msbuild_settings = {
2: :properties => {:configuration => :release},
3: :targets => [:clean, :build]
4: }
5:
6: msbuild do |msb|
7: msb.update_attributes msbuild_settings
8: endNow you can set virtually any attribute of any task through code, outside of the task definition. You only need to provide a hash to the .update_attributes method on the task object.
A Better Internal Structure
I don’t want to bore everyone with a lot of detail here, but it is worth mentioning. Many of the individual modules that have previously been used in Albcore task objects have been consolidated into a single ‘AlbacoreModel’ module. In addition, many other changes have gone into the other modules to help clean them up, significantly. This is important not just for the current developers of Albacore, but also for the future developers and contributors. It will make life easier and allow others to extend Albacore with less trouble.
A Few Tasks Have Been Killed
This is probably going to be the most controversial thing that I’ve done in Albacore…
After a lot of thought and consideration about the focus of Albacore should be, I came to the conclusion that I want to help build the best set of build related tools for the .NET workd, running in Ruby / Rake. What this means is that I don’t think Albacore should be in the business of deployment. There are some tremendous deploy related gems already available and I want to encourage the use of those instead of having half-baked, 2nd class deployment capabilities built into Albacore.
In addition to this, I also realized that there are a few tasks that just don’t add any value. They are either duplicating functionality from somewhere else, or muddying the functionality that was intended.
With all that being said, here are the tasks that have been killed, and why:
- rename: provides no value. just use ‘FileUtils.mv’ in a regular task. you get more options and better support from the ruby community with the FileUtils module
- ssh: deploy related, which is not albacore's "core". albacore is a build related framework, not deployment. suggest users switch to capistrano and webistrano if the want ssh stuff.
- sftp: same as ssh
- expandtemplates: while this is (mostly) functional and does provide some value, it's a hack that i put together because i wasn't aware of the existing templating solutions out there. ERB is built into to ruby and there are so many more available if people want them. I would suggest a switch to ERB or one of the other template systems if you need a templating solution.
- plink: I was on the fence about deleting this one, since it is a command line tool for a specific tool (PuTTY). However, I decided to kill it because it is ultimate a deploy related tool – an SSH client.
Now, just because these have been officially removed from Albacore, doesn’t mean you are out of luck if you are using them… at least, not long-term. Check out the “what to expect in the future” to see how you’ll be able to revive these tasks (if you so desire) in the near future.
And Much Much More
There’s a lot more that has happened than this list can show – many miniscule details to give Albacore a much more solid feel to it. For a complete list of what has changed, check out the “v0.2.0” label on the Github Issues page – specifically look at the “Closed” tags to see what has been done (though the list of closed issues will continue to grow, while the preview 1 release will not change. I may release another preview as progress is made).
What To Expect In The Future
One of the things I want to do for the final release (probably really soon, cause I need this…) is create a very simple plug-in architecture to allow end-users of Albacore to add functionality. I want to create a system that is easy to extend and easy to change. I want to allow the system to grow and change with your needs, not just the needs of those who are speaking up on the mailing list or StackOverflow or whatever. If you want to re-add the ExpandTemplates task, if you want to re-add the SSH or SFTP task, or if you want to re-create them or create something new in a meaningful manner that suits your environment’s needs better, I want to make it easy for you.
The work that has gone into, and is still going on in, the refactoring of the internal structure in Albacore is going to facilitate a lot of this. In addition to that, there will be a simple drag-n-drop folder that you can add to any project anywhere on your system, and Albacore will pick up and automatically call ‘require’ on all ruby files in that folder. This code isn’t available, yet… you’ll have to wait for another preview (or maybe the final release if that happens sooner than expected) but it will be there. I need this functionality for myself and I’m sure others will take advantage of it, too.
In addition to the plug-in system, there will be other changes and details on a smaller scale: some additional work will be done on the CSC task; a few more bugs will be fixed; a few other tasks will have more options; and we’ll continue restructuring and fixing up the internal structure of Albacore, too.
As always, if you’re interested in contributing to Albacore in any way, head on over to http://albacorebuild.net and you can find links to the discussion group, source code, wiki, and much more.
I Bought An iPad… And I’m Returning It.
A while back I posted that I would buy an iPad when I found a very specific type of app for it. Well I found that app thanks to the comments on the blog post and I’ve had my iPad for about 24 hours now. I’ve downloaded apps, and played games. I’ve watched movies from my Netflix account. I’ve checked email, I’ve used IRC and Twitter to communicate with my team while my laptop was going through 20 hours of CheckDisk (no joke on the 20 hours)… and I’m going to return the iPad. It’s not worth $600.
The Good:
The apps are the undeniable killer part of an iPod Touch / iPhone / iPad. Without the apps, it’s hard to say the device is worth anything. Apple has certainly created a culture around the apps and it shows. There are some amazing apps out there and they can do some great things. You can’t deny the quality and quantity of apps that are available.
If your wondering what app I bought to solve my problem previously stated: Air Sketch by Qrayon. It really is a great app and it does provide a solution for the needs I stated. If you are looking for a way to solve your distributed team collaboration needs by replacing a whiteboard with a virtual whiteboard, then an iPad and Air Sketch should be on your short of things to try. It really does work.
The hardware is also really nice. It’s solid. It’s easy to handle. It’s intuitive to use the controls on the device. It’s really well made and anyone who owned any Apple device (prior to iPhone 4) can tell you that this is what you expect. I have a Macbook Pro and an older iPod video. Both of these are well made, and I expected nothing less with the iPad. I was not dissapointed. The screen is also nice. Good resolution, great brightness and contrast. It makes the apps look great. The overall performance of the device is really good as well. Overall, it’s just a good piece of hardware.
Netflix streaming is awesome!
The Kindle App is great! … I’ve got a Kindle DX already. The benefit of the iPad is that you get a backlit screen and it’s color.
The Bad:
Everything else… well, ok… what’s left? Not a whole lot, honestly…
No multi-tasking. This one really drives me nuts with the iPad. I know a lot of you don’t care about this and don’t notice it. I believe that’s because you’re used to it with the iPhone (prior to iOS4). There is no iOS4 for iPad… at least not until later this year, which will likely see the announcement of new iPad hardware anyways. Coming from the world of Android, though, I do notice this. I can’t stand the single-task nature of the iPad. I had my IRC set up for work while my laptop was on the fritz, but I had to constantly re-open the app every time i wanted to know what was going on with my team. Forget that… I paid $5 for Android IRC on my Droid and turned on background notifications so I could receive messages even while running Skype Mobile. Yes, I do use multi-tasking on my Droid… just about every day. Why can’t I get IRC notices, twitter updates, play Pandora radio in the background and track my movement via GPS all at once? Oh wait, I can. My Droid does this for me every time I go out jogging or bike riding. :)
Yes, Netflix streaming is awesome… but i’m not going to spend $ every month on a 3G connection for this… i didn’t even buy the 3G iPad. I bought the wifi version. Sure, I could tether the iPad to my phone when I’m on the go, but what’s the point of that? I’ll bring my laptop, tether that, and have so much more. If i’m at home, I’m going to watch netflix on my PS3 (in much higher resolution than the iPad) or on my Laptop (again, much higher resolution)… so yeah… netflix is awesome if you’re on the go and have 3G or a tether… no thanks. not worth the $.
Yes, the kindle app is great! it really is… but I don’t care about backlight or color that much. I don’t read in dark places, and I have yet to need color on the device when I can open my PC and read / see the color version of what I’m reading. I’ll keep my Kindle. I love that device.
The Verdict: Not For me.
I have a Motorola Droid for my phone, and quite honestly it fits my life and my needs better than the iPad does. The things that I love about the iPad i also love about the Droid. Sure, the apps are not as numerous and it’s hard to find the same quality at times… but I don’t use that many apps… I’m not a casual gaming addict… I have a handful of games and I play them on occasion, but it’s not that big of a deal to have slightly lesser games. The ones I have are great.
I am a social media addict – twitter, facebook, etc. That being the case, I want a device that will keep me up to date when I’m on the go without me having to manually check in on things. My Droid gives me that. The background checking and multi-tasking capabilities of Android are what I need… and if I already have that fix being filled, why would I need another device that can’t fit in my pocket or give me that fix?
The iPad is a multi-media and entertainment powerhouse, and this device does not fit into my life. It is not worth the $ I spent and I want my $ back. I’d much rather have a new road bicycle to help me continue getting back into shape – something I’ll use for years to come – than a first generation multi-media buzz-worthy hunk of technology that will be outdated in 6 months or less.
The iPad solved the problem that I originally stated. No really… it did… but at a price that isn’t worth it, in my opinion. I expected to be wow’d on many fronts and I was wow’s on some of them. I expected a lot from the iPad, and I was given a little. I expected it to replace my netbook that the wife carries around the house … it probably could, except she uses it to play facebook games… *ahem* Flash, anyone? I expected the iPad to fill a void in my digital life and ultimately, it only reminded me why I bought a Droid and a Kindle – both of which fit my digital life perfectly.
Bye bye iPad. I wish I hadn’t spent the $ on you and I hope I can get a full refund from Apple.
Easy To Read != Easy To Understand
I ran into this code a while back:
1: public abstract class ScanPrefixSpecification : IScanSpecification
2: {
3: public abstract IEnumerable<string> BarcodePrefixesFilter { get; }
4:
5: public bool IsSatisfiedBy(string item)
6: {
7: return BarcodePrefixesFilter.Where(item.StartsWith).Any();
8: }
9:
10: public string GetScanFrom(string scanString)
11: {
12: foreach (var prefixFilter in BarcodePrefixesFilter.Where(scanString.StartsWith))
13: {
14: return scanString.Substring(prefixFilter.Length);
15: }
16: return "";
17: }
18: }
There isn’t anything wrong with this code from a technical standpoint. It does exactly what it needs to do and it provides a specific point of functionality in our system. By reading the code and by reading the tests around this code, I can see what this class does:
- it’s a basic specification pattern where the scanned item satisfies the specification when the “item” starts with any of the strings found in the BarcodePrefixesFilter list
- and it removes the first match found in the BarcodePrefixesFilter list from the beginning of the “scanString”; or returns an empty string if no matches were found
Ok, that’s great… now, why does it do that? Where does this code express the needs of the business; the understanding of why those characters need to be removed from the front of the scanned string? How much additional code am I going to have to read to understand the context of this code? How long will it take me to understand what functionality this code facilitates, from a functional view of the system?
… easy to read is not the same as easy to understand. Be sure your code is understandable, not just readable; and the only way to do that is for someone else to look at your code and work with it.
I’ll Buy An iPad When …
no, really… I’m actually interested in buying an iPad… but under very specific circumstances. Here’s the app that I want, that would make me shell out $500 for an iPad: a remote whiteboard app that transmits my drawing on the iPad over to my computer so that I can have a virtual whiteboard shared with my coworkers across the internet. It’s entirely a collaboration problem that I’m trying to solve. I want to grab my coworkers and walk over to a whiteboard… except we’re all thousands of miles from each other so that doesn’t really work.
Give me an iPad app that turns the iPad into a whiteboard and sends the drawing over to a whiteboard app on my PC (Windows 7, by the way… though I also run OSX on occasion).
I don’t want to use a shared whiteboard via a website… I’ve already got a Wacom art tablet… these are not good enough solutions because there is a disconnect between what I see on the screen and where my hand is drawing. I need to look at what I am drawing as I am drawing it and the iPad seems like it should be the perfect solution to this. It’s either that or a really expensive touch screen monitor, which I don’t have room for on my desk.
I don’t think a remote desktop client solves the problem, either. When I remote desktop into my box, it locks me out of the physical box so that the remote client is in control. I need a whiteboard app that keeps me up and running and just does whiteboard stuff from the ipad to the pc.
Does this app exist? If not, who wants to write it for me? :)
Work In Process (WIP) Limits, Policies, Etc.
I had a great discussion a few of my team members this morning. We were discussion work in process (WIP) limits, policies, and other items that are related to both of those. By the end of the discussion we had some great policies outlined for how we wanted to handle WIP limits, moving forward. The following represents the notes on the various policies that I wrote up based on the conversions. Before I get into the detail of what we are starting with for our policies, though, I wanted to talk about policies briefly
A Few Notes On Policies
Policies give us a basic framework for deciding what we are going to do, when. They give us guidance on how we should approach our work, from various perspectives. They are not, however, prescriptive "you must do this or you will face the wrath of Larry" rules and they do not give us all answers for all scenarios and circumstances. Software development is a human process, first and foremost. It requires interaction, communication, and judgment calls between humans for the benefit of humans, with the goal of getting things done quickly and effectively. you will run into scenarios that are not covered under the current policies. use your best judgment in those scenarios and seek the advice of others if you are not sure what to do.
Not every repeated scenario needs a policy. There are times when the repeated presence of a scenario should be an indication that our policies need to change to account for this, and there are times when that repeated occurrence should be a signal that we have a problem in our processes and we need to fix our processes.
The purpose of WIP limits is not to be a hard and fast rule or mechanical thing that prevents us from getting work done. The purpose is to facilitate getting things completed and out the door. A WIP limit is a policy, and like all policies there are exceptions and there is always the possibility of the WIP limit changing based on empirical evidence that suggests a need for change. A WIP limit is also not a comfort zone that we live within, but should be viewed as a goal that will expose problems in our process and help us to improve. Setting a WIP limit for any given column does not mean that you absolutely cannot put another ticket into that column. Rather, it means that when the WIP limit is exceeded, we as a whole team have to take on the responsibility of understanding why the WIP limit has been exceeded so that we can work to correct that situation now and prevent it from happening again.
When a given step is running up against it's WIP limit, it is our responsibility as a team to help move things forward. This means looking at the downstream steps to see if we need to get other work downstream completed so that we can make room for work that needs to be moved forward. However, don't look at WIP limits as a "you must not exceed this". Look at them as "what percentage of time are we staying under these limits? how can we improve that %?". When we start seeing WIP limits that are being met 80% or more, it may be time for us to consider reducing the WIP limit to expose the next set of problems in our process, facilitating further improvement.
I don’t expect our WIP limits to stay what we have currently defined them as for very long. After all, if our WIP limits are static, then we’re doing something wrong.
Policy: Protecting WIP
We should strive to complete work that has been started, before starting new work. this means a developer that is finished with their current work should seek to help others finish work in process before starting new work. if no other team member needs assistance, or if the time for the person needing work to come up to speed is more than the team can spend right now, then the person needing work should look for the next highest priority work to start. this also means that you should be looking downstream at steps in the process where WIP limits are being run into, to see if you can help alleviate any potential bottlenecks. If QA is getting backed up, take the time to see if you can help get some tickets tested and pushed through before starting a new ticket.
Policy: Emergency Fixes
We use VersionOne as our project management took, currently. Since we can’t model a horizontal swim-lane in V1, we will create an "Emergency Fixes" priority. This priority would be reserved for exactly what it sounds like: things that are truly emergencies. Emergency fixes mean that the developer who is working on them will drop whatever they are doing and get it fixed, now. All other work, for as many resources as are needed to complete the emergency fix, is put on hold until this thing is fixed. this includes developers, QA, product owners, etc. Emergency fixes are a primary exception to WIP limits and these fixes should be pushed through the system as quickly as possible, regardless of any WIP limits being exceeded.
Emergency fixes should also be a sign that we as a team need to step back and understand why the problem was allowed to be pushed into production in the first place. We should use this time and effort to find the root cause of the problem and see what we can do to not only prevent the problem from recurring, but also prevent similar problems from slipping through our fingers in the future.
We had a good example of an emergency fix from an IRC chat today:
Boss: hey [dev], [product owner] logged a backlog, problems with [feature] not working in IE7
Dev: oooh fun
Dev: so should issues like this trump the WIP limits we're trying to do ?
Boss: In this case, yeah. We released it, told them about it, and they just told us they can't use it.
I get the feeling that we will eventually be using many different of Classes of Service… but this is a great place for us to start.
Policy: Failed Acceptance Tests (ATs)
When an acceptance test is failed, the person doing the testing should move the ticket back to In Progress and notify the developer(s) that worked on it. both the person that worked on the ticket originally and the person that tested the ticket are responsible for ensuring the ticket is fixed and moved forward again. if a failed AT is going to prevent a release from happening on time, this needs to be brought up with the product owners immediately.
a failed AT may cause WIP limits to be exceeded. this is intentional, but not something to be ignored. a WIP limit being exceeded by a ticket with a failed AT should kick the team into problem solving mode. we should use this opportunity to find the problems in our processes and improve.
Policy: Create ATs Column
Our QA lead brought up the subject of tickets being in-progress vs. waiting for acceptance tests to be created. Based on her input and discussion with the others in the call, we think it would be good to have a column called "Creating ATs". The purpose of this column is not to say that we should wait until the work is done to create the ATs. Rather, it is there to facilitate the needs of our QA person considering our limited QA personnel. We often run into situations where a developer picks up work and completes it before she is aware of the work being started. this column will give us a place to recognize that situation and gives use better insight into the real status of a ticket.
Ideally, we should be working with QA to define the ATs before work is started. Given the number of developers compared to only 1 QA person, though, this is not always going to happen. The presence of tickets in the Creating ATs column should be another sign that our team uses to help us improve. It may be evidence for the need to hire more QA people, or the need for the developers to communicate with QA more frequently, etc.
Policy: Long Running Tasks
there are times when we are working on tasks that must be extended over long periods while waiting for input or data from external resources. for example, one of our developers is working on a data migration process for one of our customers. this process takes an extensive amount of time and cannot be run during normal business hours. He works through this process on the weekends and completes a little more of it every weekend. this type of activity will be put into VersionOne as an Epic and have individual stories split out to represent the work that is going to be done for the given increment, whether that increment is time based (on the weekends in this example) or feedback based (waiting for feedback from a customer on a given change). this will let us get the individual increments of work done and moved through the system, while letting us plan for the additional work by creating another ticket in the Epic / backlog.
One Final Note On Policies
All of this is open for discussion, clarification and modification by the team. These are policies designed to help us recognize the next set of problems in our current development process. As we continue to move forward, our needs as a team will change. When this happens, our policies will also change. We are not trying to define “the way” we develop and release software. We are trying to define what our current needs and goals are, with the intention of improving our processes as we move forward.
Git: Oops. I Forgot To Add Those New Files Before Committing
I do this pretty regularly… working away, adding files, finish something up and commit. Only after I commit do I realize that I forgot to add the new files to git.
This always frustrated me with subversion because it meant I would have to make yet another commit and put in some silly commit message like “forgot to add these files to the previous commit” and I would often repeat the same commit message as the previous commit along with the note about forgotten files. Anyone that needed to merge my changes anywhere would have to some how know that they need to read the commit messages and figure out that this second commit was supposed to be part of the first commit, so they have to bring it along for the merge.
Git Commit --amend To The Rescue!
With git, you can solve this problem easily without having to create another commit in the repository and without having to re-type any of your commit messages. Stage the file that you forgot then when you do your commit, provide the “--amend” and “-C” options.
1: git commit --amend –C HEAD
The --amend option tells git that you want to add these changes to the previous commit… that you want to amend the previous commit with these changes.
The –C option (or –c option… slightly different semantics, but generally the same) requires you to specify what previous commit’s message you want to reuse. If you don’t provide the –C or –c option, your commit message editor will come up and will contain the commit message from the HEAD commit allowing you to modify the message if you want. Alternatively, you can still provide a –m “message” and this new message will be used.
and you can see in gitk that there is only one commit with that message, but the menu.html file that I previously forgot is there
Note that --amend will change the SHA1 ID of the commit… you can see in the original screen shot at the top that the commit was ID 8bbad12 and in the second screenshot and the gitk screen shot, the ID is now 35af25e. If you need to preserve the SHA ID of the previous commit, this is probably not the best option for you. But if you don’t need to preserve it, this can save your coworkers the headache of having to look through a bunch of “forgot to add the files” commits.
Git: D’oh! I Meant To Create A New Branch First!
Yesterday I ran into a situation with git where I was working away on some code, finished what I was doing and committed the changes. Immediately after making the commit, I realized that I was still sitting in my master branch instead and had made the commits there instead of on a topic branch like I meant to.
If I were using subversion, at this point I would create a branch from the head of where I committed and then revert the original commits. The subversion history would show that I made the mistake and anyone that pulled changes from the original location would get the commits applied and then rolled back.
Git makes this situation trivial, and no one will ever have to know that you accidentally made a commit to the wrong branch, first. :)
Git Reset To The Rescue!
The first thing you want to do is snap off a new branch, just like you would in subversion. I normally like to use the ‘checkout’ shortcut to create the branch and switch to the branch at the same time:
1: git checkout -b mytopicbranch
but in this case, I don’t actually want to checkout the branch yet, so I’m just going to create a branch without switching to it:
1: git branch mytopicbranch
At this point, both mytopicbranch and master are pointing to the same location.
What we really want, though, is for master to still be back at “initial commit” and mytopicbranch to contain the two commits that were made after that. To do this, we need to know the sha fingerprint of the commit we want (which we can see in the above image) and we need to use the ‘git reset’ command. The great thing about reset is that is doesn’t do anything to the contents of the repository like a revert would do. Rather, the reset command just moves the branch pointer (the HEAD of the branch) to the commit that you specify.
Run this command:
1: git reset 2f7efb32 --hard
and you will see git move the HEAD of the master branch to that commit:
Now when we look at the repository again, we see master where we want it and we see mytopicbranch where it should be, as well!
No changes were made to the content of the repository. We only moved the HEAD pointer for the master branch around and made it look like we actually created our branch before making those other two commits. :)
Albacore Feature Preview: Building C# Code With CSC.exe
I’ve been meaning to do this for a very long time… it’s been asked for multiple times and it’s been on my list of things to do for a very long time… but it’s finally happening! I’m finally putting a ‘csc’ task into albacore so that you can build your c# code directly from the c-sharp compiler (csc.exe).
A Simple Example
Here’s a small sample of what a rakefile might look like, using the csc task:
1: csc :build do |csc|
2: csc.command = "csc.exe"
3: csc.compile FileList["src/**/*.cs"].exclude("src/**/*Specs.cs")
4: csc.output = "myproject.dll"
5: csc.target = :library
6: end
7:
8: csc :build_tests => [:build] do |csc|
9: csc.command = "csc.exe"
10: csc.compile FileList["src/**/*Specs.cs"]
11: csc.output = "myproject.specs.dll"
12: csc.target = :library
13: csc.references "myproject.dll", "nunit.framework.dll"
14: end
15:
16: nunit :test => [:build_tests] do |nunit|
17: nunit.command = "nunit-console.exe"
18: nunit.assemblies "myproject.specs.dll"
19: end
there are three tasks here: build, build_tests, and test.
- the build task will build all .cs files that do not end with “Specs.cs” and will produce a dll called “myproject.dll”
- the build_tests task will build all of the unit tests by compiling al files that end with “Specs.cs”, referencing the “myproject.dll” as well as “nunit.framework.dll” and producing a file called “myproject.specs.dll”
- and the test task will run the tests that are found in “myproject.specs.dll”
It’s a fairly simple script but that’s the point. By using a FileList to specify what files should be included / excluded from compilation, you can use naming conventions to determine what will or won’t be built into any given assembly. This means there is no need to have separate “tests” folder or project. You can have your tests living in files right next to the things that are being tested. With proper naming conventions being followed (whatever conventions your team wants to use), you don’t have to worry about your tests being built into your production code.
A Work In Progress
This is still a work in progress and not an official announcement of the csc task’s availability. The example above shows almost everything that the csc task is currently capable of… and as you can see, it doesn’t have a lot of the csc command line features built into it, yet. If you’d like to help add features and functionality, the task is currently being built in the dev branch of the albacore repository.
If you’d like to follow the progress of the csc task without wading through all the other work going on in the dev branch, I’ve started a small project over on github, called vimbacore. This is my personal playground for trying out two things: c# coding in vim (not just using vim from visual studio… but, only using vim), and the csc task in albacore. If you would like to see the evolution of the csc task in albacore, you can watch this project. I’m going to try and keep it up to date with new features and functionality related to the csc task and use this example project as a means of determining what features and functionality the csc task needs.
Health, Accountability and Technology
Anyone that’s been following me on twitter (or for the few of you left, facebook) for the last month has probably seen my status updates talking about jogging so many miles, etc etc. Some of you are probably annoyed by it, but others seem to be interested and are offering advice and motivation. I really do appreciate the motivation and advice, so keep it coming. :) I’m only going to bore you a little with my declining health over the last few years, but I promise that it all comes down to how I am managing to get through this with technology. :)
Community and Accountability
I consider exercise for the sake of health to be a drudgery and horrendous chore, completely lacking any intrinsic motivation. I would much rather be an active person in my day to day life and not need the additional exercise. However, having kids has set that part of my life back significantly, so I find myself needing to be proactive, pushing through my lack of motivation. This isn’t the first time in my life I’ve done this… but the last time I did it, I had a group of close friends / coworkers that were doing it with me. I found the company of friends to be highly motivating and I wound up in the best shape of my life… just before having kids and ending up in the worst shape of my life right now.
Since I work at home now, it is far more difficult for me to find a group of friends and coworkers that are available for me to exercise with, when I have time to do so. I’m essentially limited to work day hours when my kids are at daycare. This makes it difficult because my friends are all at their day jobs and no one works close enough to make a lunch exercise possible… not if they want to get a shower in before heading back to the office, anyways. But I still need the sense of community and the accountability that it brings. Even if I don’t have the people out there with me, pushing me every day, I still want to know that I have some accountability with a group of friends who will help keep me motivated to get out and exercise again, tomorrow.
A few weeks ago, I saw Corey Haines tweeting about the Couch 2 5K program… an exercise program designed to get just about anyone off the couch and running a 5K race in 9 weeks. After some additional conversation, I decided to start up on the program and try out some apps to track my progress and keep up to date with other people’s progress… my current list of tech includes my Android phone, the Couch2 5K app, RunKeeper, and DailyMile.
Android and GPS Systems
The Android platform is great. With the Droid line from Verizon, the Nexus One and the other great devices from manufacturers like HTC it’s hard not to notice and not to admire the sudden growth and capabilities of this phone OS (there are even e-book readers and televisions that run on the platform… but that’s another discussion). I’m a happy Motorola Droid owner… picked it up the day it was released and haven’t questioned the decision once. It’s a great phone all around.
In the context of exercise, I’m especially fond of the phone’s GPS capabilities. The Moto Droid specifically has an enhanced GPS system, as well. Rather than just use the actual GPS, it also uses cell towers to triangulate your position and help to create a more accurate location awareness. Now I’m not saying it’s perfect… but it does a great job most of the time. Since the Android platform allows pretty much any software to access any features and functionality of the host hardware and operating system, it’s no surprise that there are some great apps that take advantage of the GPS system – including some great exercise and training applications that will track your GPS data and time, speed and other information to help you understand your workout and whether you are improving or not.
Exercising The Android
I’ve used 3 different exercise apps for my Droid so far: CardioTrainer, BuddyRunner, and RunKeeper. All three of these applications allow you to export .gpx (GPS Data) files that tell you your route. None of them, that I know of, allow you to export the speed, time, or other information collected and calculated, though.
CardioTrainer: This app is by far the most functional of the three I’ve used. The free version does the basic tracking of GPS data, speed and time, etc. It has a lot of configuration settings, though, allowing you to adjust things like the required GPS strength. The paid for add-ons are pretty nice, and where CardioTrainer shines. There is an add on to do specific things like weight loss, and an add on to “race against yourself” and create a somewhat competitive environment where it tells you how you are doing compared to your best times on a given route. Overall, I like CardioTrainer… the big complaint I have about it is the ugly UI. they try to use a lot of image and iconography… but they wind up creating a cluttered and incongruous UI that just gets in the way sometimes. Even worse is the website. It’s just ugly and sparse… but it’s functional and has never failed me. The website has a strange key-id system. You get the key from your phone and log in with that to see your data. I’m not sure why they did it that way. It would be more common to use an email and password to login.
BuddyRunner: Sparse. Bland. Boring. Does nothing but tracking GPS data and speed / time. If that’s all you want, it might work for you. Just expect to be disappointed by the stupid UI design, leaving a lot of empty space where they should have scaled the design. The website isn’t quite as bad, but lacks any significance from what I saw.
RunKeeper: By far my favorite of the three apps I’ve tried. The first version that I tried had significant bugs, actually. It really jacked up my data and it had problems closing and exiting. However, a recent update has fixed all of that and it’s a stable, reliable app at this point. The UI for the runkeeper app is very simple, but not in a sparse or bland way like BuddyRunner. RunKeeper is simple in an elegant, don’t get in my way and just let me get things done, way. The app doesn’t do much more than track GPS and speed / time… but it doesn’t seem to need anything more than that, with it’s simple history to track your workouts. From that standpoint, it’s not much different than BuddyRunner. However, the elegant UI and great user experience design give it a much more polished feel and one that I’m comfortable with. The website for RunKeeper is also a world above the other two in simplicity and design. The designers of the website haven’t quite captured the app’s elegance and style, but they get pretty close. It’s an easy to use, easy to understand website that has a lot of capabilities – if you’re willing to pay for the extras. For me, the free version of the website does everything I need. It even does twitter and facebook integration… but I actually don’t want RunKeeper to do that for me. It’s very basic – post it to twitter / facebook, and that’s it. I prefer to leave the community aspect of my setup to a player that knows how to do it right. … RunKeeper is available for Android and iPhone.
Couch To 5K: This is the app that automates the timing of the program that I’m doing. It’s great because it prevents me from having to do any kind of work like using a stopwatch and remembering what I’m supposed to be doing, when. I just choose the Week and Day that I’m on, and it does the rest. It tells me in text what the day’s exercise will be and has all the timings built into it. Once I hit the start button, the app plays various chimes through my headphones to tell me when I should start walking or jogging. I just review the text on the day’s exercise before starting so that I know what to expect. The app also keeps track of your progress on that day, telling you how many jogging sessions you have completed and how many are left. Honestly, though, I don’t pay attention to the UI after I hit the start button. I always switch over to my media player because I know the C25K app will run in the background and stop when the day’s exercise is done. … the Couch25K app is also available for Android and iPhone.
Pandora Radio: This is my media player. I don’t store any mp3’s on my phone, but I still want to listen to music. Pandora is great for this. Select a station to listen to and it runs in the background so I can check up on the status of my run via RunKeeper. I don’t have much to say about Pandora other than it rocks. I use it all day, every day on my computer in my home office and in my car via my Droid. It’s great having it for my jogs, too.
I typically start up Pandora and get walking to warm up. Then I start up RunKeeper and wait for the GPS signal to go green (high quality signal). Once that happens, I start recording my workout and then load up the Couch25K app and start it. The great thing about all three of these apps is that they all run in the background on my Droid so I can switch back and forth between them without any of them losing any information. Most of the exercise for the day is spent on the Pandora app so that I can mark songs and liked or not liked, and easily turn the volume up and down when I need to. Another great thing about the Droid is that there are volume controls on the side of the phone and they work even when the phone is off, for media. Pandora plays through the “media” portion of Android, so I can turn a song up or down without having to pull my phone out of the hip case.
DailyMile.com: The Social Side Of Exercise
DailyMile.com is what brings this all together for me – connecting the technology in my phone to the technology of the social web. Now I know there are several websites out there that help to create community and social aspects of exercise across the web. However, in looking at a few of them, I did not find one that was as elegant or easy to use as DailyMile. The user experience of DailyMile will be immediately familiar to anyone that has ever used Facebook – and actually has Facebook Connect authentication built into it. I chose to use Facebook Connect to login because I didn’t want to bother with yet another username and password on yet another website… I really appreciated the ability to use an existing login.
The one thing I don’t like about DailyMile is that it doesn’t have direct integration with any of the app that I’ve used. It does have integration with Nike+ and Garmin systems, though. If you are a user of one of those systems, you can import data directly into DailyMile. If you’re using an app like I am, though, you have to manually upload the .gpx data file into the website, through the Add Route feature. This is super simple to do, though. So easy, that I upload a new route for every single workout I do and name it based on the date of the workout. That way, I get accurate distance information and accurate calculations when I put in my time.
Your homepage on DailyMile will look like a Facebook wall, with the ability add new workouts or notes, videos and photos via an input box at the very top, and a running list of all those things from yourself and your DailyMile friends going down the center of the page. Beyond the Facebook like UI, though, this site offers a real social networking experience, centered around exercise. You can find people all around the world based on a number of criteria – your location, your surrounding area, things you are interested in, friends of friends, etc. I’ve posted questions and concerns in some of my workouts and met some great people through the advice that they have provided in response.
When entering a workout, notes, or anything else, I always have the option of sending that information to twitter and/or facebook. I keep these options on by default so that every time I enter something into DailyMile, it hits both of those sites. This allows me to keep my social circles up to date and get input and advice from places other than DailyMile’s website.
Community And Challenges
Beyond the simple social networking, though, there is really is a great sense of community on DailyMile. There are features like the “challenges” area where you can set up your own challenges with your own friends, or join challenges that other people have created. There are plenty of options for this, including distance and time challenges. One of the challenges I joined was a charitable event to help those who were affected by the recent floods in Tennessee. I think I’m on track to finish the challenge in time… but it’s going to be close. I may have to squeeze in a few extra miles to make it, but it’s a great challenge and a great cause.
There’s another challenge advertises at the bottom of the Training page, that is advocating people use bicycles as a means of transportation to and from places that are only 2 miles from home. It’s a great challenge with an environmentally sound goal – to reduce the amount of pollution that we spew into the atmosphere by driving less than 2 miles at a time.
Metrics I Can Love
In addition to the challenges and other great aspects of the community, the website has a distinct sense of ‘fun’ and playtime about it. The design and UI elements are bold, round and easy to understand, and they have a great sense of humor about the kinds of data that they report. For example, look at the bottom of your Training page and you’ll see some great stats like “Donuts Burned” and “TVs Powered”. There are some great widgets that you can get for your website and blog, as well. My personal favorite is the Cheez Burgers. :)
Join Me! Keep Up The Accountability!
I’m not being paid to review these products or websites. I’m not getting any free services or apps for doing this. I’m talking about this in such great detail because I really do enjoy these products and technologies. But beyond that, I’m hoping to inspire some of you to get off your butt and get healthy. I’m currently 270 pounds – that’s nearly 70 pounds overweight… but I’m trying to do something about it. Join me in my effort to get back into shape. Friend me on DailyMile and help create the accountability that us technology geeks need to get things like this done.
Violations Of The “Tell, Don’t Ask” and “Don’t Repeat Yourself” Principles?
In the last few years, I’ve written a lot of code that looks like this:
1: public class IsThisATellDontAskViolation
2: {
3: public void DoBadThings()
4: {
5: if (something.CanHandle(anotherThing))
6: {
7: var response = something.GetThatFromIt(anotherThing);
8: DoSomethingWithTheResponse(response);
9: }
10: else
11: {
12: DoSomethingElse();
13: }
14: }
15: }
Look at lines 5 and 7, specifically. In this code, I’ve got a call being made to a dependency to check whether or not the dependency can handle whatever it is I want to send to it. If the dependency can handle it, I call another method on the same object, passing in the same parameter and expecting to be given a result of the processing.
This code bothers me, honestly, but I find myself constantly writing it. It appears to me, to be a violation of both the Tell, Don’t Ask and Don’t Repeat Yourself (DRY) principles. I don’t like how the class questions the dependency and then has it do something based on the response. This seems like a violation of Tell, Don’t Ask and is clearly falling back to simple procedural programming techniques. Then, having the same “anotherThing” variable passed into another method on the same dependency object seems like its violating DRY. Why should I have to pass the same thing to the same object twice?
Another example of this type of code can be found in my SOLID Principles presentation and sample code. In the Open Closed Principle, I create the following code:
1: public string GetMessageBody(string fileContents)
2: {
3: string messageBody = string.Empty;
4: foreach(IFileFormatReader formatReader in _formatReaders)
5: {
6: if (formatReader.CanHandle(fileContents))
7: {
8: messageBody = formatReader.GetMessageBody(fileContents);
9: }
10: }
11: return messageBody;
12: }
You can clearly see the same pattern with the CanHandle method on like 6 and the GetMessageBody method on line 8. For the same reasons, this code bothers me. It always has, but I’ve never done anything to correct it.
Is This A Violation Of Tell, Don’t Ask And/Or DRY?
Ultimately, that’s what I’m asking… are these code samples violating those principles? … and Why or Why Not? I would love to hear your opinion in the comments here or as your own blog post.
One Possible Solution
Assuming that this is a violation of those principles (and I’m all ears, listening for reasons why it is or is not), I have one solution that I’ve used a number of times for a similar scenario. Rather than having a method to check if the dependency can handle the data sent to it, just have one method that either processes the data or doesn’t, but tells you whether or not it did through the returned object.
1: public class Response<T>
2: {
3: public bool RequestWasHandled { get; private set; }
4: public T Data {get; private set;}
5: public Response(bool requestWasHandled, T data)
6: {
7: RequestWasHandled = requestWasHandled;
8: Data = data;
9: }
10: }
11:
12: public class TellDontAskCorrection
13: {
14: public void DoGoodThings()
15: {
16: var response = something.GetThatFromIt(anotherThing);
17: if (response.RequestWasHandled)
18: DoSomethingWithTheResponse(response.Data);
19: else
20: DoSomethingElse();
21: }
22: }
This works. I’ve used it a number of times in a number of different scenarios and it has helped clean up some ugly code in some places. There is still an if-then statement in the DoGoodThings method but that may not be avoidable and may not be an issue since the method calls in the two if-then parts are very different. I don’t think this is the solution to the problems, though. It’s only one possible solution that works in a few specific contexts.
Looking For Other Solutions
What are some of the patterns, practices and modeling techniques that you are using to prevent Tell, Don’t Ask and DRY violations? Not just for the scenario that I’ve shown here, but for any given scenario where you find yourself wanting to introduce procedural logic that should be encapsulated into the object being called. I would love to see examples of the code you are dealing with and the solutions to that scenario. Please share – here in the comments (please use Pastie or Github Gist or something else that formats the code nicely if you have more than a couple lines of code, though) or in your own blog, etc.
The Dangers Of AutoMocking Containers
Louis Salin commented on my original post about the Ninject.RhinoMocks automocking container, and brought up a very good point. Here is his comment, reproduced in full:
I've heard (or read...) that automocking is equivalent to taking weight loss pills while still eating cheesburgers for breakfast. Okay, I just made that up!
My point is, and I'm in no way in a position to opine on the matter, that the pain of mocking might be due to design issues. Hiding the pain with a tool won't make the cause go away.
So maybe in this case it's a very benign use of an automocker, but as the code base grows, the automocker will hide pain points that would otherwise become immediately obvious, no?
Louis has a good point and it is one that I have argued in the past to justify why I have not used an auto mocking container. However, I stand by my response in the comments of that post:
yeah, that's the "big problem" that people complain about when they say auto mocking containers are bad. honestly, that's a pretty weak excuse for not teaching developers how to spot too many dependencies as a part of bad design. trust your team. if they get it wrong, teach them right.
The “pain of mocking” that Louis is referring to is most often the need to mock a significant number of things in order to get a class spun up for testing. It may be painful or tedious or however you want to describe it, to get all of the things you need setup in order to get a class under test. But just because you can ignore that pain with an automocking container, doesn’t mean you will.
Before I expand on my response, though, let’s look at an example of what the problem really is.
A Simple Specification
This is the same sample specification that I ended yesterday’s blog post with. It’s small, easy to read and easy to understand. There is nothing really wrong with this code, in my opinion.
1: public class when_doing_something_with_that_thing : ContextSpecification<MyPresenter>
2: {
3: protected override void When()
4: {
5: SUT.DoSomething();
6: }
7:
8: [Test]
9: public void it_should_do_that_thing()
10: {
11: AssertWasCalled<IMyView>(v => v.ThatThing());
12: }
13:
14: [Test]
15: public void it_should_do_the_other_thing_twice()
16: {
17: AssertWasCalled<IMyView>(v => v.TheOtherThing(), mo => mo.Repeat.Twice());
18: }
19: }
The problem that an automocking container hides is not this code, but what this code potentially hides in the implementation.
A Complex Implementation
Now take a look at one possibility for the implementation of the MyPresenter class used in the above specification:
1: public class MyPresenter
2: {
3: private IMyView view;
4: private ISomeService someService;
5: private IAnotherService anotherService;
6: private IMoreService moreService;
7: private ISomeRepository someRepository;
8: private IAnotherRepository anotherRepository;
9: private IMoreRepository moreRepository;
10: private IValidator<SomeData> someDataValidator;
11: private IValidator<MoreData> moreDataValidator;
12: private IValidator<AnotherData> anotherDataValidator;
13: private SomeData someData;
14: private AnotherData anotherData;
15: private MoreData moreData;
16:
17: public MyPresenter(
18: IMyView view,
19: ISomeService someService,
20: IAnotherService anotherService,
21: IMoreService moreService,
22: ISomeRepository someRepository,
23: IAnotherRepository anotherRepository,
24: IMoreRepository moreRepository,
25: IValidator<SomeData> someDataValidator,
26: IValidator<MoreData> moreDataValidator,
27: IValidator<AnotherData> anotherDataValidator
28: )
29: {
30: this.view = view;
31: this.someService = someService;
32: this.anotherService = anotherService;
33: this.moreService = moreService;
34: this.someRepository = someRepository;
35: this.anotherRepository = anotherRepository;
36: this.moreRepository = moreRepository;
37: this.someDataValidator = someDataValidator;
38: this.moreDataValidator = moreDataValidator;
39: this.anotherDataValidator = anotherDataValidator;
40: }
41:
42: // ... methods and implementation details go here
43: }
That’s 40 lines of code just to get the object constructed! ARGH! that’s AWFUL! There are so many things wrong with just the member variables listed in the constructor of this class… and I haven’t even begun to imagine what the implementation of any methods on this class may look like. Quite honestly, I don’t want to think about what they may look like.
Now imagine that this code uses a couple of abstract base classes instead of all interfaces for the dependencies. Replace the three validators, for example, with abstract base classes. What happens when each of these base classes requires 2 constructor arguments for their own dependencies? The auto mocking container will go ahead and wire them up as well, and pass them into the abstract base classes so that the objects can be mocked. Now, instead of having 10 objects being mocked, we have 16. If any of those dependencies are objects with their own dependencies… well, I think you get the picture. The object graph being automocked in this scenario is horrendous and wreaks of bad design left and right.
But because we have an automocking container, we don’t care about that bad design, right? We’ll just let it slip and go on about our business because the pain of that horrendous mess is hidden away at test time. Our tooling of choice makes it easy to get away with poor design… or so the argument goes.
The Truth About Auto Mocking Containers
There is nothing inherently evil in auto mocking containers. They are not “bad” and using them is not “wrong”. Sure, they can be abused and you can do damage with them. The same thing is true of baseball bats, eggs, automatic rifles, and thousands upon thousands of other tools. Scott Bellware has quoted Ani DeFranco on the subject of tools, more than a few times: “every tool is a weapon if you hold it right”.
Now… let me restate my opinion on the problem that Louis is referring to, keeping in mind that I used to cite this exact reason for my not wanting to use an auto mocking container.
Auto mocking containers do not facilitate poor design or horrendous implementation. Poor design and horrendous implementation skill, in the person designing and implementing the code, does.
That’s it, right there. The notion that an automocking container will let someone design and implement that pile of garbage, while not using one won’t let them or will expose the problem, is ridiculous.
Speaking as a person who used to write garbage like this (and still does, occasionally, I’ll admit), I know that not using an automocking container will not prevent you from doing this. It will not make the problems more obvious if you don’t use an automocking container, and you will not inherently write better code without one. A software developer who writes code like this is not going to know the problems they are causing just because they have to declare and instantiate the 10 mock objects that this code needs to be tested. Developers write code like this because that’s the kind of code they right… no other reason. Now, there might be a lot of reasons why they write code like this… but that’s a completely different set of subjects.
“a poor craftsman blames his tools” … “with great power comes great responsibility” … “(insert other overused and abused quotes here)”
One Last Note
I wanted to note, specifically, that this post is not directed at Louis or anyone in particular. Louis is only the guy that prompted the discussion and not a person that I would single out for writing bad code.
Simplify Your Unit Tests With Automocking: Part 2 - Establishing Context
Following my helper methods in the base context specification class that we use, I decided to simplify the entire process of setting the context in which the tests are running. Specifically, I wanted to get rid of the constant declaration and instantiation of the System Under Test (SUT) field – the class that is having it’s method called to ensure it behaves correctly.
A Base Context With SUT Setup
Instead of having to manually call out to the MockingKernel directly, to retrieve the system under test (SUT), like this:
1: public class when_doing_something_with_that_thing : ContextSpecification
2: {
3: protected MyPresenter SUT;
4:
5: protected override void EstablishContext()
6: {
7: SUT = Get<MyPresenter>();
8: }
9:
10: protected override void When()
11: {
12: SUT.DoSomething();
13: }
14:
15: [Test]
16: public void it_should_do_that_thing()
17: {
18: AssertWasCalled<IMyView>(v => v.ThatThing());
19: }
20: }
I added a generics version of the ContextSpecification class to our set of spec helpers. I took the EstablishContext method out of the above code and dropped it into a ContextSpecification<T>:
1: public class ContextSpecification<T>: ContextSpecification
2: {
3: protected T SUT;
4:
5: override void EstablishContext()
6: {
7: SUT = MicroKernel.Get<T>();
8: }
9: }
Now I can declare a spec without having to setup an EstablishContext method, if I don’t need one, and I don’t need to declare a protected SUT field:
1: public class when_doing_something_with_that_thing : ContextSpecification<MyPresenter>
2: {
3: protected override void When()
4: {
5: SUT.DoSomething();
6: }
7:
8: [Test]
9: public void it_should_do_that_thing()
10: {
11: AssertWasCalled<IMyView>(v => v.ThatThing());
12: }
13: }
If I do need to set up additional code – stub methods, for example, I can still override the EstablishContext method. I just need to make sure I call to the base.EstablishContext so that I still get my SUT setup.
1: protected override EstablishContext()
2: {
3: base.EstablishContext();
4: Get<ISomeService>().Stub(v => v.ThisThingIsCalled()).Return("some value);
5: }
A Complete Example
The complete example that yesterday’s post ended with is even easier to read, now. I’ve eliminated another chunk of code and the test gets straight to the heart of what is happening – the behavior of the system.
1: public class when_doing_something_with_that_thing : ContextSpecification<MyPresenter>
2: {
3: protected override void When()
4: {
5: SUT.DoSomething();
6: }
7:
8: [Test]
9: public void it_should_do_that_thing()
10: {
11: AssertWasCalled<IMyView>(v => v.ThatThing());
12: }
13:
14: [Test]
15: public void it_should_do_the_other_thing_twice()
16: {
17: AssertWasCalled<IMyView>(v => v.TheOtherThing(), mo => mo.Repeat.Twice());
18: }
19: }
Other Considerations
I’m obviously very happy with what I’ve been able to do with the Ninject.RhinoMocks automocking container. However, there is a potential danger in using an auto mocking container. Stay tuned for tomorrow’s post to find out more about that danger and how you can help your team avoid it.
Simplify Your Unit Tests With Auto Mocking: Part 1 – Helper Methods
After working on the Ninject.RhinoMocks automocking container, I started using it in my current project right away and it wasn’t long before I started simplifying the usage of it with helper methods in my base test class.
From “MockingKernel.Get<T>()” To “Get<T>()”
I got tired of calling MockingKernel.Get<MyClass>() all over the place, so I created a helper method in my base ContextSpecification class called Get<T>(). This method does nothing more than forward calls to the MockingKernel.Get method, but it could easily be enhanced to do something more – like caching the object retrieved, so that the IoC container is not always resolving (even though it resolves to a singleton).
1: protected T Get<T>()
2: {
3: return MockingKernel.Get<T>();
4: }
This is a small change, but it makes a lot of code easier to ready. Compare this:
1: [Test]
2: public void it_should_do_that_thing()
3: {
4: MockingKernel.Get<IMyView>().AssertWasCalled(v => v.ThatThing());
5: }
To this:
1: [Test]
2: public void it_should_do_that_thing()
3: {
4: Get<IMyView>().AssertWasCalled(v => v.ThatThing());
5: }
A small amount of code reduction and a little easier to read.
From “Get<IMyView>().AssertWasCalled(…)” to “AssertWasCalled<IMyView>(…)”
After adding the Get<T> code, I realized that I could simplify the assertion even further by creating a helper method that would call Get<T> for me. RhinoMocks has two methods for AssertWasCalled. The first just takes the method and sets some defaults, like only expecting 1 call. The second allows you to specify method options for more advanced needs. I created to AssertWasCalled<T> methods to mimic the RhinoMocks methods and call Get<T> for me:
1: protected void AssertWasCalled<T>(Action<T> action)
2: {
3: T mock = Get<T>();
4: mock.AssertWasCalled(action);
5: }
6:
7: protected void AssertWasCalled<T>(Action<T> action, Action<IMethodOptions<object>> methodOptions)
8: {
9: T mock = Get<T>();
10: mock.AssertWasCalled(action, methodOptions);
11: }
This allowed me to simplify my specs down even further:
1: [Test]
2: public void it_should_do_that_thing()
3: {
4: AssertWasCalled<IMyView>(v => v.ThatThing());
5: }
6:
7: [Test]
8: public void it_should_do_the_other_thing_twice()
9: {
10: AssertWasCalled<IMyView>(v => v.TheOtherThing(), mo => mo.Repeat.Twice());
11: }
This is less code to read and easier to understand.
A Full Spec Example
With these helper methods in place, a full specification is much easier to read, now:
1: public class when_doing_something_with_that_thing : ContextSpecification
2: {
3: protected MyPresenter SUT;
4:
5: protected override void EstablishContext()
6: {
7: SUT = Get<MyPresenter>();
8: }
9:
10: protected override void When()
11: {
12: SUT.DoSomething();
13: }
14:
15: [Test]
16: public void it_should_do_that_thing()
17: {
18: AssertWasCalled<IMyView>(v => v.ThatThing());
19: }
20:
21: [Test]
22: public void it_should_do_the_other_thing_twice()
23: {
24: AssertWasCalled<IMyView>(v => v.TheOtherThing(), mo => mo.Repeat.Twice());
25: }
26: }
But Wait! There’s More!
It gets even better! In tomorrow’s blog post – part 2 of simplifying unit tests with automocking – I’ll reduce the full specification code even further by eliminating the need to declare and setup the System Under Test (SUT).
Albacore: Should We Continue To Support Ruby v1.8.6?
Ruby 1.8.6 seems to be an outdated version at this point… but I can’t find any official information on the life cycle and support plans for this version. I’d like to drop support for Ruby 1.8.6 from albacore, but I’m not sure if that’s a good idea. Here’s why I want to drop it:
I'm working on a new block configuration syntax that will make albacore much easier to deal with. It will let you set up a global and/or task level configuration in one place and have all instances of that configured task or everything that uses that global config option, behave the same way. There’s been a lot of conversation about this over on the google group, so if you want to know more, you should go read up at the group.
At this point, I've got some pretty nice syntax working that allows any task to add a new configuration method (better than originally shown in the above linked discussion). It let's the calling code determine whether the config method will have a code block or not. Here's the test that i have running and passing:
1: describe "when providing a configuration method to the configuration api" do
2: before :all do
3: class Test
4: attr_accessor :test
5: end
6:
7: Albacore.configure do |config|
8: config.add_configuration :testfoo do |&block|
9: block.call(Test.new) unless block.nil?
10: end
11: end
12:
13: Albacore.configure do |config|
14: config.testfoo do |testdata|
15: testdata.test = "this is config data"
16: @configdata = testdata
17: end
18: end
19: end
20:
21: it "should accept a parameter for configuration data" do
22: @configdata.test.should == "this is config data"
23: end
24: end
I like this syntax and i like the functionality it provides... however, it doesn't work in ruby 1.8.6. That version of ruby does not support the |&block| parameter syntax on line 8. So, I'm wondering... should albacore drop ruby 1.8.6 support in order to get this feature syntax in place? or should i try to find another way to make it work? ... I've been unable to get "yield if block_given?" syntax to work in this scenario... for some reason, block_given? always returns false when placed on line 9, which is why I switched to the |&block| syntax in the first place.
This new syntax works fine in ruby 1.8.7 and ruby 1.9.1… just not 1.8.6
I don't know if that's a good reason to drop ruby 1.8.6 support or not... is there a good reason to drop it? is it really necessary to support that version? ??? thoughts? suggestions? feel free to respond in comments here, or join the google group and respond to the discussion there.
Ninject.RhinoMocks: Auto Mocking Container For .NET 3.5 and Compact Framework 3.5
Earlier today, I decided I was tired of calling RhinoMocks directly. I love RhinoMocks. It’s a great tool and I don’t want to write tests without it (or another mocking framework like Moq or whatever…). But I’m tired of all the boring “declare a variable here, mock the object there, pass the object to the constructor here” junk that I have to do to get a mock object into my class under test.
Here’s an example of what I’m talking about:
1: public class when_doing_something: basecontext
2: {
3: private ISomeView View;
4: private SomePresenter Presenter;
5:
6: public override void EstablishContext()
7: {
8: View = MockRepository.GenerateMock<IView>();
9: Presenter = new Presenter(View);
10: }
11:
12: public override void When()
13: {
14: Presenter.DoSomething();
15: }
16:
17: [Test]
18: public void it_should_show_something()
19: {
20: View.AssertWasCalled(v => v.ShowThatThing());
21: }
22: }
Line 3: declare a variable here
Line 8: mock the object here
Line 9: pass it to the class under test
Line 20: assert against it
It’s even more annoying when I have to mock things that I don’t care about, or when I have 5 or 6 or more things to mock (and yes, I know that having that many dependencies is a design smell. I’m not working on a pure greenfield app, so I don’t have the luxury of designing everything ‘correctly’).
… what can I say… I’m lazy. I’d rather ignore the ceremony of declaring the variable, mocking it and passing it to my class. Let me get my class and ask for the mock if I need it. I’m not trying to do anything crazy or bad, or let myself get away with poor design problems. I’m just trying to reduce the amount of code that I have to write in my tests. Maybe it’s the ruby developer in me, lashing out against the ceremony of C# again… whatever it is, I want an auto-mocking container for ninject and rhino mocks.
Now I know there is a general sense of “NO!!!!!” in the alt.net crowd these days… but I don’t understand that. Just because you can abuse a tool, doesn’t mean you should or will. I like wielding triple-edged swords with poison-tip spikes on the handle. It give me power and flexibility to get things done… and yes, the occasional debilitating injury… but hey, a little pain just means I’m learning what not to do, right? :)
Automocking With Ninject And RhinoMocks
After doing a bit of googling, I found a stack overflow question with the basic code to get this running. I had a hard time getting that to work, though, so I scrapped it and started fresh from a copy of ninject.moq. A little while later, I have a basic working auto-mocking container for ninject and rhino mocks.
Now I can create a MockingKernel in my basecontext class and change my test code to run like this:
1: public class when_doing_something: basecontext
2: {
3: private SomePresenter Presenter;
4:
5: public override void EstablishContext()
6: {
7: Presenter = mockingKernel.Get<SomePresenter>();
8: }
9:
10: public override void When()
11: {
12: Presenter.DoSomething();
13: }
14:
15: [Test]
16: public void it_should_show_something()
17: {
18: mockingKernel.Get<IView>().AssertWasCalled(v => v.ShowThatThing());
19: }
20: }
Line 18: get the view and assert against it
There’s only a few lines of code difference in this simple example, so it seems like a wash. When you are dealing with multiple dependencies, though, it makes the code much easier to write.
As a real-world example, after implementing this, I was able to reduce my test code by about 12 lines because I only needed 2 of the mocked objects for assertions. The rest of them were there for ‘support’ and other behaviors, but needed to be there to prevent null reference exceptions. With the auto mocking container in place, I didn’t need to declare a variable, mock, or pass the other dependencies into the class under test. I let the auto-mocking container do that for me.
Ninject.RhinoMocks And Ninject.RhinoMocks.CF
If you’d like to use this functionality, you can grab the source code from github. There are two different version available – one for full .net 3.5 and another for .net 3.5 compact framework.
Please note, though, that I wrote this code for me and built in the behavior that I wanted. All mocked objects are essentially singleton instances so every time you request one from the kernel, it returns the same one. Be sure to call kernel.Reset(); in your teardown, so you don’t get mock objects bleeding over between test fixtures.
Also note that this code is a bit of a hack, as I am not entirely sure about the implementation needs of ninject. I’ve asked for Ian Davis’ input on the code and he’s said he’ll review it… but until that happens, and until I get a chance to “clean up” the code, there’s no promises about the quality of this work.
Ninject.RhinoMocks:
- .NET: v3.5, Full Framework
- URL: http://github.com/derickbailey/ninject.rhinomocks
- Ninject: v2.0.1
- RhinoMocks: v3.6
Ninject.RhinoMocks.CF:
- .NET: v3.5, Compact Framework
- URL: http://github.com/derickbailey/ninject.rhinomocks.cf
- Ninject: v2.0.1, compiled for Compact Framework
- RhinoMocks: v3.5 compiled for Compact Framework, with Castle.Core and Castle.DynamicProxy2 as separate dlls
Temporarily Turned Off Comments
I had to turn off comments on the my entire blog just now. The spam bots are unusually active today… I’ve received more than 150 spam comments today alone… that’s much more than the usual 2 or 3 per week. I’ll enable comments again at some point… maybe tomorrow.
Book Review: Web Design For Developers
I recently finished reading Web Design For Developers: A Programmer’s Guide to Design Tools and Techniques and while I would like to have seen a few more specific details in a few places, the book overall does a great job of breaking down the mystic art of web design in a manner that allows almost any left-brained analytical developer to grasp the concepts and produce work of sufficient quality. If you are a software developer that is interested in web design, this is the book for you. It is full of great parallels between the two worlds and will help you understand how to create a design that works, while conforming to standards and be accessible to all types of browsers and devices.
The book starts out by describing a fairly common set of scenarios where a customer is involved in some discussion about what their current website looks like and does, vs what they want it to do. It’s an accurate portrayal of what really goes on in these types of meetings, leaving the reader with a sense of “ugh. not another nebulous, undefined set of ‘requirements’.”
After that brief introduction into the world of dealing with customers, the book jumps into the basics of design and talks about some of the key elements of laying out a site, including the need to do pencil sketches as wire frames. One mild issue that I have with this section of the book is that the author uses a lot of standard notations for various elements in the sketches but fails to define those notations or provide any links to information on what those notations are. While most of it is rather obvious, I was able to understand the intent of some of the sketches only because I have experience with wire framing tools that use the same notations.
There is a large section devoted to dealing with color, choosing color schemes and understanding the basics of how color blind people will see your site. This was one of my favorite sections of the book – both toward the front and later on when discussing accessibility. The author does a great job of explaining how to select color schemes and themes, even with a complete absence of creativity and eye for design. He points to some great tools on the web and other resources that will help almost anyone pick a set of colors that work well together. He also talks about the difference between light that reflects off surfaces like in the real world, vs. light that is projected from a monitor. This is a subject that I have wondered about for more than 15 years – why is a monitor RGB and real world light RYB? – and I have never found such a clear and concise description of the difference.
The next few sections of the book dive into creating graphics for the site, including the use of typography in those graphics. In these sections, the author introduces the notion of using a grid to layout your designs in the graphics editors and also in the actual website. In my 15+ years of working on the web, I have never heard of this before and I have to say that it was an eye opening experience to see how effective this technique is. You can take a site from “blech” with difficulty getting things lined up and spaced out correctly, to “wow” pretty quickly if you stick with the grid system that he outlines.
Most of the book is then devoted to constructing the homepage of the site… that’s right – one page and one page only. The in-depth analysis of every step in the process is quite amazing, though. I never once felt like the author was repeating any information or providing dull, dreary content that could have been better summarized (though I will admit that I skimmed over most of the html content. Since I was not actively building a website while reading this, I wanted to catch the high points of what he was saying without getting mired down in the angle bracket and attribute mechanics).
Toward the end of the book, the author does spend what I felt like was an in inordinate amount of time discussing accessibility for disabled persons. He does do a good job of explaining why, though – he is a somewhat disabled person and uses assistive technologies to access websites on a daily basis. Having done accessibility work on the web in recent years, I can assure you that every point he makes is correct. If you need to create a site that conforms to “section 509” for example, this part of the book is a great place to start. Beyond the in-depth look at accessibility for disabled persons, though, the author does a great job of explaining how accessibility is more than just that. He discusses making website accessible by anyone, anywhere, on any device – not just a PC with a full web browser, but a mobile phone and other devices that provide limited web capabilities.
Pro’s For The Book:
Approaches web development as developer not as a designer and makes the web feel comfortable for a back end software developer. In depth look at HTML and other web standards for getting a site done, not just for the sake of talking about web standards. Great discussion on CSS and how to effectively use it. Excellent information on color theory, graphics layout, and other seemingly “mystical” design areas. Provides a ton of information on great tools and how to use them to make your job easier.
Con’s For The Book:
Covers HTML 4, with only a few minor notes about HTML 5. Uses Photoshop and Illustrator throughout the book – very expensive tools – though he does offer alternate suggestions but says that you’ll have to figure them out yourself. Lacks a few resources for things like standard wireframe notation (“what does that big X in the middle of the sketch mean, anyways?!” … well, it’s an image place holder… but he never explained that).
Final Score:
In the end, I felt that this book was a great read and provided a lot of valuable information. Even with my extensive background in web design and development, I found multiple gems of knowledge that will have a direct impact on how I approach web design. I give the book a 4 out of 5. There were a few things I would have liked to see, but the book is an all around great resource for developers doing web design.
On a technical note: if you buy the e-book version, make sure you get a color copy as a PDF or another format. You will lose out on all of the benefit of the images and differences that the author illustrates if you don’t have a color copy. For me, I read the book on my kindle which is black & white. This made it hard for me to see what he was talking about – especially in the color theory section. However, I do have a print copy of the book as well, which made up for this.

