Friday, 23 May 2008

It's ladies night

More on women in IT there's a great article on the Guardian about the Geek Girl Dinners movement.

Friday, 25 April 2008

The Snake and The Emerald in The Mesh

Back in the first days of the new millenia when .NET pamphlets first hit the desks of Microsoft shops the world over one of the great and exciting features being sold was multilanguage development. Microsoft painted a world where the UI team could beaver away happily and productively in VB.NET while the back end team got hard core writing business logic in C#. Microsoft even talked about other vendors writing languages for .NET including Perl (which was actually one of the languages supported by the original ASP through the Windows Scripting Engine) and Microsoft Marketing painted a picture of a world blind to the prejudices of different languages.

Fairly soon the dust settled over the pamphlets and everyone forgot about the great multi-language dream, .NET was as polorized as British politics: there was Labour and Tory, C# and VB, no other language got a look in and those that existed were merley academic exercises of no importance to your MVP. There were many critics of the importance of multi-language support in .NET and they were feeling proven right.

At the same time another important trend was occuring: the rise of static languages: Java, C#, VB.NET are all strongly typed. Now even VB was strongly typed MS developers felt confident to dismiss dynamic typed languages as toys for script kiddies, web designers and network engineers. Grown-up enterprise development required things like type safety and checking.

So now the world is strongly typed and .NET settles around VB and C# and Java is just Java, the battle lines are clear: who is the king of the strongly typed. Then all of a sudden, out of nowhere, the alpha geeks decide that dynamic languages are the thing: Ruby, Python and Groovy, people are re-realising that dynamic languages can do very, very cool things which strongly typed languages struggle to express.

A new level starts in the arms race between Sun and Microsoft as people start trying to implement dynamic languages on top of the JVM and CLR. Java gets Jython and JRuby and a glut of projects attempt dynamic languages on the CLR including Microsoft's own IronPython but then all of a sudden people realize something: the CLR wasn't designed to do dynamic languages: sure you can build languages on top of the CLR but gone is the dream of having C# assemblies seemlessly call Python assemblies without even knowing it.

Fortunately Microsoft had the guts (or rather Jim Hugunin did) to sort this problem out and get .NET back to where it should be and the Dynamic Language Runtime was born. The DLR sits ontop of the CLR and allows all the dynamic goodness of languages like Ruby and Python (and now VB 10) to work as equals alongside C# and VB.NET code. The DLR will allow a new phase of the polyglot dream to emerge: C# calling Python calling Ruby calling VB and every combination in between.

Microsoft are going to start pushing IronPython and dynamic languages hard.  It is one of the main features of Silverlight 2.0 and being expanded to ASP.NET. Interestingly MS is positioning dynamic languages firmly in the web and UI arena (which makes sence as this is where they are traditionally strong). In reality dynamic languages aren't restricted to the UI layer and entire applications can be written in them, though I think Microsoft aren't pushing this point because they don't want to scare or alienate their core developer community.  Any how the people who would want to do will try and do it.

There are a few interesting issues arising out of the dynamic languages race:
When is Ruby/Python not Ruby/Python?
As languages run on the the CLR can talk to the .NET framework and other .NET libraries they break compatability between other interpreters: though it's still legal Ruby/Python code it isn't going to run on any other interpreter. DLR languages can also be compiled to .NET assemblies breaking all compatability with anyone else. Some see a risk here of MS "restandardising" pointing to HTML as an example.
Why run IronRuby/Python when you could just Ruby/Python?
Technically there are a few answers about integration with .NET etc. but they are pretty weak when it comes to writing apps in one language. Leveraging the power of dynamic languages from within a .NET app (i.e. polyglots) is the main selling point, otherwise, for those who are simply going to write pure Ruby/Python code, then the big thing is ratification: for those .NET shops out there who still believe the MS FUD of previous years simply putting MS in front of the language makes it acceptable.
What about open source?
Both Python and Ruby are open source languages so isn't this a bit incompatable with MS? Interestingly both IronPython and IronRuby are open source (under the Microsoft Public License) and because the DLR came from the work on IronPython it is also open source. IronPython is hosted on CodePlex but IronRuby - in an attempt to engage the Ruby community - is hosted on RubyForge.

Tuesday, 18 March 2008

Polymonoism (AKA the legend of cross platform .NET)

After using IntelliJ for the last nine months or so I have realised how much Visual Studio sucks (even with Resharper).  The problem I have with VS is the IDE seems to be focused on everything but writing code and I feel there is only ten percent of it I use and that only does ten percent of what I can do with IntelliJ.  I, like many others, really wish there was an IntelliJ plugin for .NET (in particular C#) or even a whole IntelliC, however the news on the street is despite JetBrains hinting rather explicitly that such a thing was in the pipe line they've shelved the idea (BOOO).

I can't blame JetBrains for wanting to focus their efforts on Resharper: MS developers, as a herd, generally keep to the MS straight and narrow and fear wandering from the vendor's path of least wisdom.  It makes no commercial sence to develop an alternative IDE from Visual Studio when most MS devs won't even bother to look beyond the MS brochure.  As a plugin Resharper is going to hit a bigger market.

This is a shame and a loss for choice: the Java community has healthy competition with its IDEs and plenty of innovation with it but, Borland aside, this culture doesn't exist in the mainstream MS world (hence why Visual Studio's 'refactoring' and 'testing' features are a joke). 

The other issue is that Visual Studio only runs on one platform (Windows) for one vendor (MS funnily enough); from the ground up most Java IDEs support multiple platforms and multiple vendors of the JDK and compilers.  Why is this of any relevance for .NET - who would want to develop it on anything else when it only runs on Windows anyway?  Firstly I don't want to develop on Windows: I find it an awful OS for doing development on and I am far more productive on Linux or OSX (like many I have a preference for a different OS which happens not to be Windows: why should that even be a statement?), secondly I don't necessarily want to run my .NET applications on Windows: after the luxury of working with true multi platform languages such as Java and Ruby I find it really frustrating to have to ditch everything positive about working cross-platform (and that means working on Windows too) and be shoved into a corner where my choice is simply XP or one of the 26 variations of Vista. 

Even though I may not express a preference for working on Windows or with Visual Studio but there are many things about .NET I really like: there are things about the cleanliness of the language and the SDK which trumps Java (generics anyone?).  The real advantage Java has over .NET is the community around it and the way Sun has left people free to contribute to it, there is far more innovation coming from the Java community than from the .NET one (hell, the .NET community is just trying to port as many Java projects as quickly as it can).  However the .NET community is growing (especially with the ALT.NET movement) and it isn't to hard to wriggle out of the MS straight jacket.  All in all there's a real feeling of excitement around .NET at the moment despite MS's attempts to lump as many bad practices into it as they can.  As a result .NET is a serious contender to Java except it falls flat on its face when it comes to cross platform support.

Well there may be some hope out there: mono is coming along nicely (with almost full 2.0 compatibility) and comes as part of Gnome (so for Linux it's already there) and there is a version for OSX.  With a bit of support and real world proof mono has the potential to become a real Java killer. 

The problem is you're not going to be able to compile to mono in Visual Studio and even if you could you can still only run VS on Windows solving only half the problem.  The other problem is Mono IDEs suck: monodevelop, a sterling effort, is like going back in time 15 years.  SharpDevelop (from which monodevelop was originally forked) would be cool but again it only runs on Windows (booooo to you icsharp).  

A bit of research and I stumbled across a little IDE from Omniture call X-Develop.  Not only does it run on Windows, OSX and Linux but it can handle C#, J#, Visual Basic and Java compiling to whatever framework you choose including mono.  The word on the blogoshpere is that X-Develop is a usable, productive UI and despite not being as feature rich as IntelliJ (it's refactoring support is weaker) or Visual Studio (UI designers) is a slick, quick, lightweight, cross platform IDE, which includes all the essentials including basic refactoring (one up on VS), error highlighting (another up on VS) , debugging etc.  The good news for fans of other IDEs is that you can choose to map keybingins from Visual Studio, IntelliJ, Eclipse and others.

The downside is you have to pay for it and at $499 per license it isn't the sort of thing you'd buy on a whim.  Naturally I'd prefer it to be open source but I'm going to be realistic that people have to make money though a cut down OS version without the designers etc. for free may be a wise move to get people hooked.  Omniture seem to be giving a serious proposition that no other vendor can match in terms of true cross platform, cross framework development and that is a fantastic thing.

The problem Ominiture are going to have is appealing to the Java and Linux community who do have a preference for free software.  The problem mono has is that without a decent cross platform IDE it's not going to gain serious ground.  I think both sides need to reach out and touch each other to ensure mono gets the real-estate it deserves.  I for one would be seriously excited about developing true cross platform applications in C# on my Mac or Ubuntu.  Hopefully it may be a future arriving quite soon and not just another broken pipe dream.

Monday, 17 March 2008

The rise of the Nu-Geeks

At QCon last Thursday Kent Beck gave a keynote on Trends in Agile Development.  There were lots of interesting slides about the rise in tests, quick releases and lots of other agileness but the most interesting aspect of the talk for me was the rise of the new generation of tech savvy business professionals.  The old "wizards" detectable by their strange socially inappropriate behaviour are out as a generation of Nu-Geeks with social skills like listening, team work and emotional intelligence are rising to the challenge of making businesses happy.
I've never been one for the old skool geek, I'd go as far to say I am a NAG (Not A Geek) and have found myself often frustrated by people trying to tar me with the brush of demeaning stereotypes - the most extreme example being a senior manager who put the IT department in the basement believing we would be more comfortable far from the real world of human interaction (no clients were ever bought to the basement by the way: except if they were techies themselves) - so I identify strongly with this rise.   This is one of the many reasons I was attracted to Agile, listening to Kent Beck talk reminded me that what I found refreshing about Extreme Programming Explained was the focus on the social side of development and the reason I signed the Agile Manifesto was the belief in "people over process".

This all supposes that the stereotype ever existed.  The feminist and existentialist Simone de Beauvoir (friend and influencer of Jean-Paul Sartre) argued that stereotyping is a form of subjugation and always done in societies by the group higher in the hierarchy to the group lower in the hierarchy so that the lower group became the “other” and had a false aura of mystery around it.  How accurately does that describe the IT industry with the exception that perhaps there is a bi-directional purpose to the stereotype: one from outside the group to keep the geeks in and the other from inside to keep the women out?

Hopefully as the geeky male image melts faster than the ice caps we will start to see more women join the fray.  Recent news seems to offer a strong promise of this trend.

Girl's found computers too macho back before the turn of the millennium and research blamed the strong male images and metaphors such as pirates, ships and planes opposed to softer, feminine images (apparently teddy bears  and flowers).  Now the tables have turned and research by Tesco found that girls are more computer savvy than boys.  So as the last bastion of strictly male territory falls so will the old stereotype of the geek-knight on a white mac coming to the rescue of the maiden caught by the evil Word dragons.  Unfortunately this will leave a horde of male geeks without any chance of female contact.

The trend is fierce and girls are not only better at computers than boys but are also more prolific with it.  Apparantly the growth of social networking and blogging is "almost entirely fuelled by girls".  Gaming is another area which women are conquering with girl gamers being the fastest growing group in the entertainment industry.  Not only that but there are more Nintendo DSs sitting snuggly in the hands of the fairer sex (54%) than the soft unworked hands of the coffee crunching, light fearing, cellar dwelling male geek of old (only 46%).  Nintendo's own research show that it "continues to reach more women ... a significant percentage of all Touch Generations software buyers are female".  No wonder the new face of Nintendo is Nicole Kidman.

ThoughtWorks is taking the challenge on to help resolve the problem.  My suspicion is that Agile itself may be the greatest weapon in the battle: a development methodology with a more people centric, reality focused approach which values the softer skills and attempts to bridge the gulf between writing code and actually creating real things.   It is those real things I am motivated by and I know that personally, without Agile, I would be struggling to maintain my sanity in the IT industry of old.

Monday, 10 March 2008

"I'll show you mine if you show me yours" vs "You tell me and I'll tell you"

Avoiding breaking encapsulation can sometimes be difficult. The most common encapsulating breaking habit is using field accessors (properties/getters and setters), these can break encapsulation as the object looses control over how it's information should be interpreted and also a language is never built up. Here is an example: in a banking application the system needs to know if the account is overdrawn, it would be common to do:

if(account.balance < 0) ... do something

This code could be scattered across the system: however, what if a new business rule came in to say that if an account is frozen it shouldn't be marked as overdrawn? All those statements are incorrect and have to be changed. If behaviour had been put on the account it would have been simpler to do:

if(account.is_overdrawn) ... do something

Then the Account is in complete control over what it considers as being overdrawn. This is a simple example and easy to solve but what if there is an exchange of information between two objects? Breaking encapsulation seems a hard thing to avoid. For example:

if(loan.amount + account.balance < 0) ... do something

This is a classic case of "I'll show you mine if you show me yours": the loan exposes it's amount and the account exposes it's balance, both objects have lost control of their data. In the real world this would create scenarios of ridiculous bureaucratic proportions. Let's prove this with an application which models a host offering a guest a drink. Using the non-encapsulated method is the equivilant of having a third party ask both of you for private information and then doing the selection for you. Here it is in code:

class IllShowYouMineIfYouShowMeYours
def main
host.drinks.eachType | drinkType | do
if(guest.drinks.containsType(drinkType)) do
drink = drinks.get(drinkType)

if(drink.is_consumed) do
throw AlreadyConsumedException.new
end

guest.energy.add(drinks.get(drinkType).calories)
drinks.remove(drink)
drink.is_consumed = false
end
end
end
end

A better way to solve this is to use "You tell me and I'll tell you". In the real world the host would ask "what would you like to drink?" and the stock reply is "what have you got?" they would then tell you what drinks they have and you'd tell them which drink you want: neither of you expose any data: there is no case of the guest rummaging through the host's cupboards, the host can select their drinks themselves and the guest is allowed to decide what they'd like. By telling the Host to offer the drinks the Host can tell the Guest to choose one and encapsulation isn't broken. Here is the alternative:

class YouTellMeAndIllTellYou
def main
drink = host.give_drinks_to(guest)

if(drink.is_consumed) do
. . .
end
end

class Host
def give_drinks_to(guest)
drink = drinks.get(guest.which_drink(drinks.getTypes))
end
end

class Guest

def which_drink(drinkTypes)
drinkTypes.each |drinkType| { return drinkType if drinks_i_like.contains(drinkType) }
end

end

There is room for further encapsulation: the consumption of the drink still relies on outside manipulation, we have another case of "I'll show you mine" but even worse as it's not only showing it but it's letting just about anyone touch it too! So let's tell the guest to take the drink and tell the drink to give nutrition to the guest.

class YouTellMeAndIllTellYou
def main
drink = host.give_drinks_to(guest)
end
end

class Host
def give_drinks_to(guest)
drink = drinks.get(guest.which_drink(drinks.getTypes))
guest.give(drink)
drinks.remove(drink)
end
end

class Guest
.
.
.

def give(drink)
drink.consume(self)
end

def increase_energy(increase_by)
calories = calories + increase_by
end

end

def Drink
def consume(consumer)
if(is_consumed) do
throw AlreadyConsumedException.new
end

consumer.increase_energy(calories)
is_consumed = true
end
end

By encapsulating the behaviour we have given ourselves a number of advantages. The first and most obvious of them being testing: the encapsulated code is much easier to test as the behaviour of each class can be independantly tested and verified. We also stop spread: without those getters and setters it is very difficult to add behavior centric to those classes in any other parts of the application: all behaviour to do with the class is in one place, this means less repetition, less bugs and less maintenance. We also allow Single Responsibility: if we wanted to change the way the drinks worked (say from a list to a hash) then we can do safelty without breaking any code. Lastly we have code which supports polymorphism: for example if we wanted to add alcoholic drinks to the system, we can polymorphically add a different type of drink which causes a guests to become drunk:

class AlcoholicDrink
def consume(consumer)
if(is_consumed) do
. . .
end

consumer.increase_alcohol_levels(units)
. . .
end
end

The guest can also be made polymorphic:

def TeaTotalGuest
def give(drink)
if(drink.is_alchoholic) throw IDontDrinkException.new
end
end

def LightWeight
def increase_alcohol_levels(units)
total_units += units
if(total_units > 3) spew
end
end

def PartyAnimal
def increase_alcohol_levels(units)
total_units += units
if(total_units > 10) start_dancing
end
end

All of the above polymorphic behavior can be easily added without ever changing the code of any consumers, in the non-encapsulated version there would be a nightmare or nested if's and switch statements which would make even our TeaTotalGuest dizzy and want to spew. Or to quote Neal Ford:
"getters/setters != encapsulation. It is now a knee-jerk reaction to automatically create getters and setters for every field. Don't create code on auto-pilot! Create getters and setters only when you need them 10 Ways to Improve Your Code".

As a final note to readers: please drink responsibly!

Friday, 7 March 2008

Balancing Greed with Anemia

I am many things to many people. If I go to the doctors I am a patient, when at work I am an employee, when at home, with my wife, I am a husband. I cannot be all these things at the same time and I need to behave differently with different people and what's more my doctor isn't interested in me as an employee, my employee cares not for my detailed medical history and my wife certainly doesn't care what languages I can program in let alone the content of my blog!

Readers of Domain Driven Design will be familiar with the concept of Aggregates: simply put an aggregate provides a boundary around concepts which are closely related and provides an entry point to those other entities. If you were modelling people the Person class would be an aggregate, within the person class would be other classes and methods to do with my medical state, languages I can program in and package private methods between my wife and I. Using a behaviour centric domain finding we can write code like this:

class Client 
def do
john = employeeRespotory.find("John")

if(john.is_not_skilled_in(:AnyJava)) do
john.train(:BeginnersJavaCourse)
end

john.can_do_job(Job.new(:SqlServer, :DotNet))
end
end

class Person < Skilled
skills

def is_skilled_in(skill)
if(skills.not_contains(skill.type)) do
return false
end

return skills.get(skill.type).is_at_level(skill.level)
end

def is_not_skilled_in(skill)
!is_skilled_in(skill)
end

boolean train(Training)
if(skills.not_contains(Training.skill) do
skills.add(Training.skill)
else
skills.get(Training.skill).upgrade(Training.level)
end
end

def can_do_job(Job)
Job.matches_skills(this)
end
end

class Job
def matches_skills(skilled)
Skills.each | skill | do
return false if skilled.is_not_skilled_in(skill)
end
end
end

class Test
def can_be_skilled_in_something
skills = Skills{:BasicJava}
testPerson = new TestPerson(skills)

assert_true(testPerson.is_skilled_in(:BasicJava))
end

def can_be_trained_in_something
testPerson = TestPerson.new(:NoSkills)
skill = Skill.new(Java, Basic)

testPerson.train(Training.new(skill))
assert_true(testPerson.is_skilled_in(skill))
end
... plus all the other tests
end

The problem is if we placed all of this behaviour and data in one Person class it will quickly get on the big side. This is what I call a Greedy Aggregate: in the same way I don't try to be all things to all people a class shouldn't try to be all things to all clients.

The biggest criticism I have heard about placing behaviour on Domain objects is the problem of Greedy Aggregates: huge classes that end up with bags of methods and test classes as long as your arm. The solution often presented is to move to a Service paradigm instead. I agree with the complaint of Greedy Aggreates but not the solution as the service paradigm moves code away from being object orientated and towards procedural. The above in service orientated code would be:

class Client 
def do
john = employeeRespotory.find("John")

if(employeeService.is_not_skilled_in(john, :Java)) do
employeeService.train(john, :BeginnersJavaCourse)
end

employeeService.can_do_job(john, Job.new(:SqlServer, :DotNet))
end
end

class EmployeeService
skillsRespository
def is_skilled_in(person, skill) do
if(skillsRespository.not_contains(person.id, skill.type)) do
return false
end

return skillsRespository.get(skill.type).is_at_level(skill.level)
end

def is_not_skilled_in(person, skill)
!is_skilled_in(person, skill)
end

def train(person, training) do
if(skillsRepository.not_contains(person.id, training.skill)) do
skillsResponsity.add(person.id, Training.skill)
else
skillsResponsity.get(prson.id, taining.skill).upgrade(training.level)
end
end

boolean can_do_job(person, job) {
job.eachSkill |skill| do
return false if is_not_skilled_in(person, skill)
end

return true
end
end

def Test
def canBeSkilledInSomething
testPerson = TestPerson.new
skill = new Skill(Java, Basic)
MockRepository {
expect.contains(testPerson.id, skill.type)
will.return(true)
expect.get(testPerson.id, skill.type)
will.return(new Skill(:Java, :Basic))

}

assert_true(employeeService.is_skilled_in(testPerson, :BasicJava))
end

def can_be_trained_in_something
testPerson = TestPerson.new
Skill = Skill.new(:Java, :Beginner)

MockRepository {
expect.contains(testPerson.id, skill.type)
will.return(false)
expect.add(testPerson.id, skill.type)
expect.get(testPerson.id, skill.type)
will.return(new Skill(:Java, :Basic))

}

employeeService.train(testPerson, Training.new(skill))
assert_true(employeeService.is_skilled_in(skill))
end
... plus all the other tests
end

The service client code feels more difficult to read: it flows less as a sentance making the Service the subject and not John who has disapeared somewhere in the parantheses. The Service code itself is more difficult to read than the behaviour class and the service test class is significantly more complex. Also the service requires a more complex repository and the Person class is reduced to being nothing more than a data holder. Another problem with service based is you often have to break encapsulation to get it to work and, as a result, you can end up with a lot of repetation in code.


I believe the issue with Greedy Aggregates mainly stems from making code centric to O/R mapping tools. To simply model our Person domain we end up with:

  • A Person object which maps to a Person table

  • A Medical History class with a table with a Person_Id foreign key

  • A Skill class with a table with a Person_Id foreign key


This makes it difficult to split the Person into smaller more specific classes as the O/R mapper requires a definate class to map to. In the above code we may want to split Person into two classes: one which represents the core aspects of a Person (name, age etc.) and another for their skills lets call it PersonWithSkills. In many O/R mappers this is difficult because we cannot create a mapping for PersonWithSkills as two classes cannot map to the same table. However we can create a repository which ties them together:

class PersonWithSkillsRepository
def get(id)
person = personRepository.get(id)
skills = skillsRepostitory.get(person)
return PersonWithSkills.new(person, skills)
end
end

This is how I've tended to advocate it in the past but recently I was playing with Ruby, and using its cool dynamic powers I approached it in a different way: essentially I merley extended the Person class using a module like so:

class Person 
has_many :skills

def with_skills
self.extend PersonWithSkills
end
end

module PersonWithSkills
def is_skilled_in
... # all skills based methods here
end

The only issue with this method is all of the ActiveRecord declarations have to be on the Person class - there may be a way around this but I don't know Ruby well enough to say for sure. It also has the disadvantage of not working for any classes outside of the core package (though knowing Ruby there may be a way around this to). However if you want to do more complex logic between role based aggregates you can. For example:

class Person
def as_traveller
self.extend PersonAsTraveller
end
end

module PersonAsTraveller < Locatable ... end

module TravellingPersonWithSkills < Skilled
def can_do_job(job)
job.matches_location(self.as_traveller) && job.matches_skills(skills)
end
end

class Job
def matches_location(locatable)
return locatable.matches(location)
end
end

Dynamic languages such as Ruby make it nice and easy to do the above as it has the ability to mix in methods. That doesn't mean we can't do something similar in a static langauge such as Java or C# it simply means that we have to jump through a few more hoops and use delegation instead.

So now that we are using behaviour based domain objects and moved away from services and have managed to cut those Greedy Aggregates down to size when is it right to use a service? A service will need to be introduced when there is something normal domain objects cannot be trusted to deal with something by themselves and require some co-ordination or greater authority to do it for them. The service must be stateless. A good example of this is transferring money between accounts: you don't want to leave the accounts to sort it amongst themselves so you will need a service to deal with the interaction:

class AccountTransferService
def transfer(account_from, account_to, amount)
if(account_from.has_funds(amount)) do
account_from.debit(amount)
account_to.credit(amount)
end
end
end

There are a number of ways of dealing with Greedy Aggregates in both dynamic and static langauges. What is important is being able to clearly identify aggregates and not be to restricted by the O/R mapper or simply give up and rely on services.

Saturday, 19 January 2008

The One Minute Build

The project I am working on has a build which used to take under a minute and has slowly crept up to around one minute forty five seconds. Recently I have begun to feel the pain of this longer build; it is surprising just how much a paltry forty-five seconds increases those periods of sitting and waiting.

The build is an essential part of the code base, it is what gives you the developer and the rest of the team feedback on the state of your code. Continous Integration tell us that we should make as small changes as possible, verify them using the build, then check in (then verify the build on the build server). Under these rules we should probably aim for a optimum integration rate - the frequency of check-ins (per pair). I believe a optimum integration rate should be around once per hour.

A slow build can be a blocker to good CI practice: the longer a build takes to run the less often people will run it, the less they will check in and the bigger the change list they create. Martin Fowler's original article on CI states that "the XP guideline of a ten minute build is perfectly within reason" however I want to contest that guideline and bring it down to a minute. Why? because the difference between a build that takes under a minute and one that is over a minute is quite considerable in trying to keep your change list down.

On average a developer will run three builds per change, the first being on the change itself - which is usually run in the IDE and will often have some failing tests (though not always) - the second to verify the change and the third to verify the update. So the general rhythm goes: make a change, run the tests, fix the broken tests, verify the build on the command line, update, verify the build again, commit. Of course it is possible to make a change and have no tests failing (meaning two builds per change) but even then most devs will run the testsuite in the IDE and then verify the full build against the command line.

In the case of a merge conflict (either in code or failing tests on update) we add an extra two builds per conflict: the first to verify the fix, the second to verify the fresh update before check-in.

Three changes per build means that the total amount of time spent building is the build time multiplied by three: therefore any build which takes one minute will consume three minutes of developer productivity. If we check-in once every hour that is 3/60 or 5% of your devs time spent building. Take the build up to just two minutes and we have 6/60 or 10%. Take a build of ten minutes and we have 30/60 or 50% of devs time spent building! If there was a merge conflict on a ten minute build it will consume 50/60 or over 80% of that hour.

On a ten minute build a productivity ratio of 1:2 is not acceptable, so to compensate we adjust the optimum integration rate. This is achieved, essentially, by trying to bring the ratio back to an acceptable level, so if 10% loss (equivalent to a two minute build) is acceptable the check-in rate becomes once every five hours. Comparatively 10% on a one minute build is a check-in every 30 minutes verses once every five hours!

Decreasing check-ins is a dangerous game; the longer changed code is out of the repository the more out-of-date it is. The difference between your repository and your code becomes greater (assuming, of course, that you are making changes over that period) and the difference between your code and your fellow developers also becomes greater. By checking in frequently the codebases are constantly re-aligned minimizing the impact of future changes. The most obvious side effect to diverging code bases is the chance of conflict increases - small, frequent check-ins reduce this to an extent where it can become a non-issue - big check-ins mean big conflicts, big conflicts mean loss of productivity, stress, more time your code is out of sync and more times you have to run the build.

To demonstrate this lets create a concept of a "window of opportunity", this window is the space between doing the update and checking in and the opportunity is for another pair to check-in before you do! The size of this window is equivalent to the length of the build; we all know that if we are going to check in we try to grab this window (how often do we say "hang on a minute I've just got to run the tests and check in this build"?). The reason for this is we don't want to find that someone else has checked in between the last update and us running the build. The greater the length of the build, the greater the chance that someone else has committed (which increases based on the size of the team) and the more times you have to run your build.

There are other side-effects to long builds, you can't keep the change list small and people will find ways around running the build; from only running it once out of the three times (increasing the chance of broken builds) or avoiding full runs by only running the tests they believe to be impacted (again increasing the chance of broken builds). None of these is a good practice. Big builds also mean loss of attention: running the build, doing an update, running the build again, then checking in takes just two minutes on a one minute build but twenty on a ten. Two minutes won't disrupt to flow of development and probably works as a nice gap to discuss things with your pair or just give the brain a rest. The ten minute build equals a wait of twenty minutes: enough time to eat lunch! At the end of twenty minutes any focus you had has gone.

A one minute build may sound unrealistic but I believe it is possible. In some ways it is an indication to healthiness of your code base and by that I mean both production and test - poorly written and bad performing test code is equally as bad as poorly written, bad performing production code. It is very easy to be slightly relaxed about build times, treat them as an inevitability and the watch them slowly go from one minute builds to ten.

It's all very easy to preach about one minute builds when I am in the privilliged position to be working on a code base that only takes one minute forty five seconds. The speed of the build is due to the drive, early on in the project, not to tolerate long builds: several times it's been looked at when it started to get a bit overgrown and it's been hacked back down to size. If we had been more relaxed I'm sure it would have crept up a lot higher.

About Me

My photo
West Malling, Kent, United Kingdom
I am a ThoughtWorker and general Memeologist living in the UK. I have worked in IT since 2000 on many projects from public facing websites in media and e-commerce to rich-client banking applications and corporate intranets. I am passionate and committed to making IT a better world.