ThoughtWorks Studios

ThoughtWorks' Agile Project Management application

ThoughtWorks' Continuous Integration and Release Management application

ThoughtWorks' Collaborative Test Automation application

ThoughtBloggers

(feed)
Aaron Erickson (feed)
Abdul Salam (feed)
Adrian Wible (feed)
Agile Hong Kong (feed)
Akshay Dhavle (feed)
Akshay Rawat (feed)
Alex Hung (feed)
Alex Scordellis (feed)
Alexandre Martins (feed)
Alistair Jones (feed)
Amey Shyamchandra Dhoke (feed)
Anand Iyengar (feed)
Anand Vishwanath (feed)
Andy Marks (feed)
Anthony Pitluga (feed)
Antonio Terreno (feed)
Avishek Sen Gupta (feed)
Benjie Davis (feed)
Bhavin Javia (feed)
Brandon Hastings Byars (feed)
Brian Guthrie (feed)
Cam Swords (feed)
Carl Ververs (feed)
Chad Wathington (feed)
Chirag Doshi (feed)
Chirdeep Shetty (feed)
Chris Bushell (feed)
Chris Leishman (feed)
Chris OMeara (feed)
Chris Stevenson (feed)
Christian Blunden (feed)
Christopher Read (feed)
Cliff Morehead (feed)
Continuous Delivery (feed)
Cruise development team (feed)
Dahlia Bock (feed)
Dan Abel (feed)
Daniel Aragao (feed)
Daniel Worthington-Bodart (feed)
Danilo Sato (feed)
Darci Dutcher (feed)
Darren Smith (feed)
David Cameron (feed)
David Leigh-Fellows (feed)
David Rupp (feed)
Dean Cornish (feed)
Dinesh Tantri (feed)
Duncan Cragg (feed)
Eric Liu (feed)
Erik Doernenburg (feed)
Erik Stepp (feed)
Evan Bottcher (feed)
Fabio Pereira (feed)
Farooq Ali (feed)
Felix Leipold (feed)
Flex Testing (feed)
Francisco Trindade (feed)
Geek Snack (feed)
Gitanjali Venkatraman (feed)
Grant Joung (feed)
Grzegorz Gigon (feed)
Grzegorz Gigon (feed)
Hakan Raberg (feed)
Halvard Skogsrud (feed)
Hao (Vincent) Xu (feed)
Ian Cartwright (feed)
Ian Robinson (feed)
Jae Lee (feed)
James Barritt (feed)
James Crisp (feed)
James Lewis (feed)
Jason Furnell (feed)
Jason Yip (feed)
Jeff Norris (feed)
Jeff Rogers (feed)
Jez Humble (feed)
Jiangmei kang (feed)
Jie Xia (feed)
Jie Xiong (feed)
Jim Arnold (feed)
Jim Webber (feed)
Jinzhou Chen (feed)
Joe Poon (feed)
John Hume (feed)
John Johnston (feed)
Jonathan Andrew Wolter (feed)
Jonathan McCracken (feed)
Jonny Leroy (feed)
Josh Cronemeyer (feed)
Julias Shaw (feed)
Julio Maia (feed)
Kai Hu (feed)
Kai Ramuenke (feed)
Kailuo Wang (feed)
Ketan Padegaonkar (feed)
Kraig Parkinson (feed)
Kris Kemper (feed)
Kristan Vingrys (feed)
Lachlan Heasman (feed)
Lasse Westh-Nielsen (feed)
Liang Huang (feed)
Liang Qiao (feed)
Liz Douglass (feed)
Luca Grulla (feed)
Luke Barrett (feed)
Manish Chakravarty (feed)
Manish Kumar (feed)
Marc McNeill (feed)
Marjorie Pries (feed)
Mark Burnett (feed)
Mark Needham (feed)
Martin Fowler (feed)
Matthew Dunn (feed)
Matthieu Tanguay-Carel (feed)
Mayur Wadhwa (feed)
Michael Jones (feed)
Michael Norton (feed)
Michael Patricios (feed)
Mike Mason (feed)
Ming Jin (feed)
Mo Li (feed)
Neal Ford (feed)
Nicholas Bailey (feed)
Nick Drew (feed)
Ning Lu (feed)
Nitin Dhall (feed)
Nolan Evans (feed)
Ola Bini (feed)
Patric Fornasier (feed)
Patrick Kua (feed)
Paul Hammant (feed)
Paulo Caroli (feed)
Perryn Fowler (feed)
Peter Gillard-Moss (feed)
Philip Calcado (feed)
Prabin Deka (feed)
Pramod Sadalage (feed)
Prasanna Pendse (feed)
Preetam Reddy (feed)
Premanand Chandrasekaran (feed)
Pritika Gulliani (feed)
Qihui Qin (feed)
Rajveer Singh Rathore (feed)
Ranjan D Sakalley (feed)
Raphael Speyer (feed)
Renee Ovcina (feed)
Reshmi Buthello (feed)
Richard Durnall (feed)
Ritesh M Nayak (feed)
Rohan Kini (feed)
Rohith Rajagopal (feed)
Ross Pettit (feed)
Ryan Greenhall (feed)
Saager Suhas Mhatre (feed)
Sachin Dharmapurikar (feed)
Sam Newman (feed)
Santosh Sagar Reddy (feed)
Sarah Taraporewalla (feed)
Sean Doran (feed)
Shakir A Shakiel (feed)
Sharlene Mckinnon (feed)
Shaun Jayaraj (feed)
Shaun Jayaraj (feed)
Sidu Ponnappa Kariappa Chonira (feed)
Simon Brunning (feed)
Srihari Srinivasan (feed)
Sriram Narayan (feed)
Sriram Narayanan (feed)
Stephen Chu (feed)
Steven List (feed)
Stuart Caborn (feed)
Sudhindra Rao (feed)
Sumeet Moghe (feed)
Suresh Harikrishnan (feed)
Suzi Edwards (feed)
Tarek Abdelmaguid (feed)
Thomas Czarniecki (feed)
ThoughtWorkers on Open Source (feed)
ThoughtWorks Studios (feed)
Timothy Camper (feed)
Tomas Varsavsky (feed)
Troy Gould (feed)
Vivek Prahlad (feed)
Vivek Singh (feed)
Wen Tao (feed)
William Hegarty (feed)
Xuemin Guan (feed)
Ye Zheng (feed)
Yogi Kulkarni (feed)
Yuexin Chu (feed)
Zubair Khan (feed)
__ThoughtBlogs-Admin (feed)

We Love xkcd

Share and Enjoy: TwitThis Digg del.icio.us Reddit Technorati Facebook Google Bookmarks LinkedIn MySpace



I’ve been using Mobile Me since 2002. (Then it was called .Mac). One of the features I really like is the iDisk. This is really convenient when you have to transfer large files. Also, I use it to keep a set of files I need again and again for my work as an agile coach. To make the access transparent and fast you can keep a copy of your iDisk on the local Macintosh HD and use it like any other drive. There is a sync process running in the background taking care of the data syncing. Very nice and convenient. In the beginning I could put a symbolic link into the local iDisk to reference a folder with the files on my local hard drive. Then the files were synced onto the iDisk in the cloud and I could access them from anywhere.

However, with the release of Leopard this stopped working. Well, rather annoying but not a real big problem. I just created a folder which I kept up date manually. But, since the iPhone has an iDisk app I started to read and re-read certain documents while on public transport. As you can guess, it happened again and again, that I forgot to do the manual update and therefore could not read important documents.

rsync to the rescue. With rsync you can keep folders in sync. I use it to keep the folder on the iDisk an exact copy of the folder containing the documents.

Well, next problem. Now, I have the copy process automated but I still need to run the script manually. The fix for this is crontab. Crontab is a list of scripts to be executed by the cron demon at certain times. I cannot tell you how much I like that OS X is Unix based. A nice UI with the power Unix underneath, what a great combination.

Now at midnight, the documents are automatically synced from the local folder on my hard drive to my iDisk. There I can access them using my iPhone or my notebooks. (iDisk also has a Windows client).

If you run into the same problems, then hopefully this shed some light onto it.

A few weeks back, Andy and I got together to walk through all the different iPhone examples that we’ve been playing around with. We both learned a great deal.

I’ve found that teaching whilst learning is actually the most effective way of learning. There’s something about trying to put words to the things that you think you know that makes you reason actually how little you really know.

I think the best learning model where this experience fits in is the following model:

Unconscious Incompetence -> Conscious Incompetence -> Conscious Competence -> Unconscious Competence

The act of trying to explain something is trying to raise you from one level to the next. If, for instance, you think you know what you’re doing and then find yourself having difficulty explaining something, you’re perhaps you are at a stage of Unconscious Incompetence. However if you know you are already incompetence (Conscious Incompetence), then the act of explaining is helping your understanding, testing the boundaries of where your knowledge fails. You are trying to move from Conscious Incompetence to Conscious Competence.

Interestingly, articulating your competence (or lack of) is an integral part to both a software craftsmanship model and pair programming, where in both you are expected to articulate your reasoning. The benefits work at all sorts of levels including the novice-novice and even the expert-novice pairing arrangement.

A week or two ago I attended the Open Space Coding day arranged by Alan Dean, and held at the Conchango offices. The Alt.Net community is very good at getting together and talking about code, software, and how it should all be done, but the focus of this meeting was to get on and write [...]
Why do Ruby developers brag about true OO vs Class based OO?
This post is in response to Tim Ross’s post on ‘Are Burndowns Evil?‘ Tim asks how useful a Burndown chart is, especially in the case of a new team with a new or unknown code base. A burn down chart (with an ideal line) for a new team immediately gives a team ’schedule pressure’. Some may say [...]
One of the great things about Agile software development that I’ve noticed is sustainable pace. Planning poker, point based estimation and velocity are all great tools for finding a team’s sustainable pace. Knowing a team’s velocity and consistent estimating by the entire team, allows a team to commit to as much work as it is [...]
In an effort to get our teams understanding ‘Done Done’ we’ve started looking at acceptance testing. We’ve moved, over the last 18 months or so, from a traditional waterfall process to a full on Agile one, our final hurdle is the QA process. We still have a very waterfall-esque QA approach. We’ve done lots in terms [...]
Following on from my entry on the altnetuk session on Agile Process, I’m just going to layout the different types of estimating with points that I know of. I’m not sure why but at that session it felt like someone had put and end to point to complexity estimating and forgot to let me know! Pure [...]
So to start the conference I chose to take part in a session about agile development and processes. I think mainly because I wanted a refresher on some of the points and to see if I could contribute. It’s nice to see plenty of people there new to Agile as I was at my first [...]
So, I’ve just got back from the altdotnet conference in London. This is my second altdotnet conference, and it was as good as I remember. You could see people had moved on, and it was nice to see that altdotnet has had its affect on uSwitch.com in a positive way. 5 attendees were currently employed [...]
My first blog post on this wordpress site. How exciting, I’m trying to get other the initial, “I’m not worthy of publishing my thoughts” thing that I’m sure all those that blog need to get over, so please bear with me. I’ve also got to keep my sentences shorter! Hopefully, I’ll be able to use this blog [...]

While working on some code with Toni we realised that we'd managed to create two functions that were almost exactly the same except they made different service calls and returned collections of a different type.

The similar functions were like this:

private IEnumerable<Foo> GetFoos(Guid id)
{
    IEnumerable<Foo> foos = new List<Foo>();
    try
    {
        foos = fooService.GetFoosFor(id);
    }
    catch (Exception e)
    {
        // do some logging of the exception
    }
    return foos;
}
private IEnumerable<Bar> GetBars(Guid id)
{
    IEnumerable<Bar> bars = new List<Bar>();
    try
    {
        bars = barService.GetBarsFor(id);
    }
    catch (Exception e)
    {
        // do some logging of the exception
    }
    return bars;
}

We're defining the empty lists so that if the service throws an exception we can make use of an empty list further on in the code. A failure of the service in this context doesn't mean that the application should stop functioning.

My thinking here was that we should be able to pull out the service calls into a function but the annoying thing is that they return different types of collections so I initially thought that we'd be unable to remove the duplication.

Thinking about the problem later on I realised we could just define the return value of the service call in the function to use generics.

We therefore end up with this solution:

private IEnumerable<Bar> GetBars(Guid id)
{
	return GetValues(() => barService.GetBarsFor(id));
}
private IEnumerable<Foo> GetFoos(Guid id)
{
	return GetValues(() => fooService.GetFoosFor(id));
}
private IEnumerable<T> GetValues<T>(Func<IEnumerable<T>> getValues)
{
    IEnumerable<T> values = new List<T>();
    try
    {
        values = getValues();
    }
    catch (Exception e)
    {
        // do some logging of the exception
    }
    return values;
}

I think the code is still quite readable and it's relatively obvious what it's supposed to be doing.

I came across an interesting post that Roy Osherove wrote a few months ago where he talks about 'Willed vs Forced Designs' and some common arguments that people give for not using TypeMock on their projects.

I'm not really a fan of the TypeMock approach to dealing with dependencies in tests because it seems to avoid the fact that the code is probably bad in the first place if we have to resort to using some of the approaches it encourages.

Having said that Roy makes the following point which I think is quite accurate:

You let an automated tool (rhino mocks, Moq etc..) tell you when your design is OK or not. That point alone should go against anything ALT.NET has ever stood for, doesn’t it? If you need a tool to tell you what is good or bad design, then you are doing it wrong.

While it is true that it's useful to be able to know for ourselves whether our code is drifting into territory where it's become way too complicated, I think it is useful to have the tests as a reminder that this is becoming the case.

It's quite easy when you have a delivery deadline and are under pressure to stop being as observant about the quality of what you're coding and to rush to complete our particular task.

In these situations it can be useful to be restricted by our framework to the extent that the pain we'll feel in trying to test our code will act as an indicator that we're doing something wrong.

What I found interesting when reading Roy's post is that the arguments sound sounds quite similar to the discussion a couple of years ago with respect to whether using Mockito instead of jMock was bad because it hides design problems that you have with dependencies. Steve Freeman wrote the following comment on Dan's post:

But, it also became clear that he wrote Mockito to address some weak design and coding habits in his project and that the existing mocking frameworks were doing exactly their job of forcing them into the open. How a team should respond to that feedback is an interesting question.

In the meantime, I’ve found that I /can/ teach using the existing frameworks if I concentrate on what they were intended for: focusing on the relationships between collaborating objects. I’ve seen quite a few students light up when they get the point. In fact, the syntactic noise in jMock really helps to bring this out, whereas it’s easy for it to get lost with easymock and mockito.

In this case I definitely prefer the style of mocking that we get with Mockito over jMock even though I've worked on code bases where we've created objects with way too many dependencies and haven't felt the pain as much because the framework is so easy to use.

I can't think of a compelling argument for why this is different to the TypeMock vs other mocking frameworks argument. It seems to be a similar argument around dependencies in our code.

The other thing I'm intrigued about is whether the choice of framework should be in some way linked to the level of skill of the people who are going to use it.

If someone is a Dreyfus Model novice with respect to object oriented design then it would make much more sense to use a tool which makes it really obvious that they're doing something wrong. In that case using a perhaps more limited tool would just be a quick feedback mechanism.

Once we have a bit more skill then it would seem more appropriate to use the more powerful tool which we have the ability to abuse but hopefully now have the experience to know when we can and cannot get away with doing so.

In the end the argument seems quite similar to ones I've often heard about programming in Ruby and whether or not we should give programmers powerful language features because they're liable to hang themselves.

In conclusion I'm thinking that perhaps TypeMock in experienced hands isn't such a bad thing and could actually be useful in some select situations but would probably be quite a dangerous tool for someone new to the whole unit testing game.

Scala可以与Java互操作,因为Scala代码可以编译成Java的字节码。



下面是一个非常简单的Scala类,

class Person(val name:String) {

  def showMe = println("My name is " + name)

}

(Person.scala)



编译一下:

  scalac Person.scala



一切正常的话,我们会得到一个Person.class。用javap反编译之前得到的结果:

  javap Person



这里用到的是Scala 2.8,使用稍早的版本编译结果会略有差异,但不会影响理解:

public class Person extends java.lang.Object implements scala.ScalaObject{

    public Person(java.lang.String);

    public void showMe();

    public java.lang.String name();

}



一起来看一下这个编译结果。



继承自java.lang.Object是所有没有明确标明基类的类的共同属性,此外,这个类还实现了scala.ScalaObject接口。实际上,scala.ScalaObject是一个trait,这一点可以从Scala的文档中看到。由此推断,trait可能会编译成接口。



class Person(val name:String)

定义出了一个构造函数,其参数是一个字符串,同时还有name()方法,用以访问字段name。



def showMe = println("My name is " + name)

定义出一个方法:showMe()。Scala可以进行类型推演,在这里推演showMe的返回值是Unit,对应到Java字节码上就是void。



从结果不难看出,这就是一个标准的Java类,而且与代码之间几乎就是完全直白的一一对应。由此,我们也就不难理解为什么Java可以使用Scala代码编译出来的代码。



有些JVM上的编译语言,比如JRuby,也可以编译成字节码,但编译出来的结果却没有这样对应,所以,Java代码里很难理解它们生成的字节码。对这样的语言而言,它们与Java的交流几乎的是单向的。



当然,这只是最简单的情况,只是一个开始。









I am part of a team at ThoughtWorks helping out organizing the very first RubyConf in India. I’m very excited about this. So if you have the possibility to come to Bangalore, the event will be March 20 and 21.

We already have some solid speakers lined up. Chad Fowler will keynote, and so will I, and we have a number of other people coming in. A few of my colleagues from ThoughtWorks, such as Sarah Taraporewalla, Sidu Ponnappa and Aman King. Other speakers include Hemant Kumar, Pradeep Elankumaran, Arun Gupta and others. Finally, Nick Sieger will also come to Bangalore for this event!

So as you can see, this is gearing up to be a great event! Hope to see you there.

Agile Metrics<object height="355" width="425" style="margin:0px"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=agilemetrics-091215150548-phpapp01&stripped_title=agile-metrics-2725666" /><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><embed allowfullscreen="true" type="application/x-shockwave-flash" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=agilemetrics-091215150548-phpapp01&stripped_title=agile-metrics-2725666" allowscriptaccess="always" height="355" width="425"></embed></object>

Do you find yourself feeling frustrated when you collaborate with certain people? Do you feel like they respond to your written communication in fits and spurts? Sometimes the conversation flows but other times they act like a communication black hole, killing the exchange in the process.

I think there's a certain kind of collaborator whose primary characteristic is that, when it comes to written communication especially, they think deeply and seriously before responding. These people are pensive and I think I am one.

I find it very difficult to participate in online forums, mailing lists and even, to some extent, email conversations. I'm not overly private but I'm coming to understand I'm pensive. Written communication comes to me after deliberation.

I read a thing and I think, "Oh, I have an opinion about that." I'll explore the opinion enough to give it a mental title, a headline maybe. But then it needs to sit. There's a part of my brain that fleshes out opinions and makes connections while I'm doing, well, pretty much anything else. The anything else could be paid work like consulting or programming. It could be exercise or taking my wife on a date or a hike with my son. I may come back, do a little research to fill in gaps in my understanding, then put the conversation back on the shelf. At some point the processing is done. I have an opinion and am ready to elucidate that opinion. I'm faced with a dilemma. Do I actually engage in the conversation? Is my pensively-formed opinion still relevant?

Face-to-face I don't have the same problem. It makes me wonder why writing is such a different kind of process.

If you come across someone who seems to respond in fits and spurts to your emails or tweets you might ask yourself if they are pensive collaborators.



I’ve been trying to get my head around cryptography on the iPhone so that I can create a native iPhone app (iPasskeep) that interoperates with my JPasskeep password keeper application. It has taken a while to get my head around CommonCrypto APIs – how to use them, how not to use them and their limitations. It then took a bit of fiddling to find the right incantations in Java to get an interoperable cryptographic transformation.

Caveat: The following Objective-C code is not yet production ready or quality. It passes unit tests, but I haven’t checked it for memory leaks, performance, etc.

Hope this helps.

Listing: Cipher.h

#import <Cocoa/Cocoa.h>

#import <CommonCrypto/CommonDigest.h>
#import <CommonCrypto/CommonCryptor.h>

@interface Cipher : NSObject {
	NSString* cipherKey;
}

@property (retain) NSString* cipherKey;

- (Cipher *) initWithKey:(NSString *) key;

- (NSData *) encrypt:(NSData *) plainText;
- (NSData *) decrypt:(NSData *) cipherText;

- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData;

+ (NSData *) md5:(NSString *) stringToHash;

@end

Listing: Cipher.m

#import "Cipher.h"

@implementation Cipher

@synthesize cipherKey;

- (Cipher *) initWithKey:(NSString *) key {
	self = [super init];
	if (self) {
		[self setCipherKey:key];
	}
	return self;
}

- (NSData *) encrypt:(NSData *) plainText {
	return [self transform:kCCEncrypt data:plainText];
}

- (NSData *) decrypt:(NSData *) cipherText {
	return [self transform:kCCDecrypt data:cipherText];
}

- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData {

	// kCCKeySizeAES128 = 16 bytes
	// CC_MD5_DIGEST_LENGTH = 16 bytes
	NSData* secretKey = [Cipher md5:cipherKey];

	CCCryptorRef cryptor = NULL;
	CCCryptorStatus status = kCCSuccess;

	uint8_t iv[kCCBlockSizeAES128];
    memset((void *) iv, 0x0, (size_t) sizeof(iv));

	status = CCCryptorCreate(encryptOrDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
							 [secretKey bytes], kCCKeySizeAES128, iv, &cryptor);

	if (status != kCCSuccess) {
		return nil;
	}

	size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length], true);

	void * buf = malloc(bufsize * sizeof(uint8_t));
	memset(buf, 0x0, bufsize);

	size_t bufused = 0;
    size_t bytesTotal = 0;

	status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length],
							 buf, bufsize, &bufused);

	if (status != kCCSuccess) {
		free(buf);
		CCCryptorRelease(cryptor);
		return nil;
	}

	bytesTotal += bufused;

	status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);

	if (status != kCCSuccess) {
		free(buf);
		CCCryptorRelease(cryptor);
		return nil;
	}

	bytesTotal += bufused;

	CCCryptorRelease(cryptor);

	return [NSData dataWithBytesNoCopy:buf length:bytesTotal];
}

+ (NSData *) md5:(NSString *) stringToHash {

	const char *src = [stringToHash UTF8String];

	unsigned char result[CC_MD5_DIGEST_LENGTH];

	CC_MD5(src, strlen(src), result);

	return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];
}

@end

Listing: Cipher.java

package com.tomczarniecki.iphone;

import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class Cipher {

    private final String password;

    public Cipher(String password) {
        this.password = password;
    }

    public byte[] encrypt(byte[] plainText) throws Exception {
        return transform(true, plainText);
    }

    public byte[] decrypt(byte[] cipherText) throws Exception {
        return transform(false, cipherText);
    }

    private byte[] transform(boolean encrypt, byte[] inputBytes) throws Exception {
        byte[] key = DigestUtils.md5(password.getBytes("UTF-8"));

        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
        cipher.init(encrypt, new KeyParameter(key));

        ByteArrayInputStream input = new ByteArrayInputStream(inputBytes);
        ByteArrayOutputStream output = new ByteArrayOutputStream();

        int inputLen;
        int outputLen;

        byte[] inputBuffer = new byte[1024];
        byte[] outputBuffer = new byte[cipher.getOutputSize(inputBuffer.length)];

        while ((inputLen = input.read(inputBuffer)) > -1) {
            outputLen = cipher.processBytes(inputBuffer, 0, inputLen, outputBuffer, 0);
            if (outputLen > 0) {
                output.write(outputBuffer, 0, outputLen);
            }
        }

        outputLen = cipher.doFinal(outputBuffer, 0);
        if (outputLen > 0) {
            output.write(outputBuffer, 0, outputLen);
        }

        return output.toByteArray();
    }
}

This tweet from Ron Evans (aka @deadprogram on Twitter) of Dead Programmer Society fame forced me to think about my role in the Ruby and XP/Agile communities:



My rules for social media: find something cool=tweet it, learned something cool=blog it, mastered something cool=present it

It makes some sense to me in terms of a progression of sharing. I like it as a checklist to remember to be a fully participating member in my communities.

I'm working on following the rules.



Last week I did struggle finding out why a test was failing only on our Cruise box, only in the Cruise build.

I wanted to get a screenshot of each failing tests, and I think I found a clever solution: aop.

We already use PostSharp on our code base for logging, transaction demarcation and hibernate session support, so I wrote a simple annotation for our acceptance tests:

  1. using System;
  2. using PostSharp.Laos;
  3.  
  4. namespace Web.UI.AcceptanceTests
  5. {
  6.  [Serializable]
  7.  public class ScreenCaptureAttribute : OnExceptionAspect
  8.  {
  9.   public override void OnException(MethodExecutionEventArgs eventArgs)
  10.   {
  11.    SeleniumManager.Selenium.CaptureScreenshot(string.Format("C:\\{0}.jpg", eventArgs.Method.Name));
  12.   }
  13.  }
  14. }

Every time a test will throw an Exception Selenium will take a screenshot of the screen: pretty simple.

The only caveat is that it won’t work if Cruise is running as a service, and to get a decent result you’ll probably need to maximize the web browser windows.

Conflict is a natural part of your every day life, whether it is at work or home. A certain amount of conflict is healthy as long as you work out how to resolve it.

Liv Wild and I will look at a number of conversation models we’ve found healthy teams use, in agreeing to agree. We’re holding it at the Thoughtworks UK office from 7pm this Tuesday (9 Feb). More details can be found here.

These walls are kind of funny like that. First you hate them, then you get used to them. Enough time passed, get so you depend on them. That’s institutionalizing

来自《肖申克的救赎》。

越来越觉得,所有的咨询工作,最终的目的,是唤醒被体制化的人,唤醒他们原本的认知,唤醒他们原本为之追求的希望,唤醒那些原本属于他们现在却不得不依赖于指令规则的直觉。

Last year I blogged about a neat trick in Django to have multiple views per HTTP verb. Since then I’ve been playing with RESTful applications and decided to see if there was a nicer way to expose “resources” in Django. The following is what I’ve come up with so far.

Listing: router.py

from django.http import Http404, HttpResponseNotAllowed

def get_handler_method(request_handler, http_method):
    try:
        handler_method = getattr(request_handler, http_method.lower())
        if callable(handler_method):
            return handler_method
    except AttributeError:
        pass

class Resource:

    http_methods = ['GET', 'POST', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']

    @classmethod
    def dispatch(cls, request, *args, **kwargs):
        request_handler = cls()

        if request.method in cls.http_methods:
            handler_method = get_handler_method(request_handler, request.method)
            if handler_method:
                return handler_method(request, *args, **kwargs)

        methods = [method for method in cls.http_methods if get_handler_method(request_handler, method)]
        if len(methods) > 0:
            return HttpResponseNotAllowed(methods)
        else:
            raise Http404

Listing: views.py

from django.shortcuts import render_to_response, get_object_or_404
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from router import Resource
from models import Document
from django import forms
import identity

class DocumentForm(forms.Form):
    one = forms.CharField()
    two = forms.CharField()
    date = forms.CharField()

def index(request):
    document_links = []
    for document in Document.objects.all():
        url = reverse('document', args=[document.id])
        document_links.append({ 'identity': document.id, 'url': url })

    new_form_url = reverse('document', args=[identity.NEW])
    model = { 'document_links': document_links, 'new_form_url': new_form_url }
    return render_to_response('index.html', model)

def success(request, document_id):
    document = get_object_or_404(Document, pk=document_id)
    form = DocumentForm(document.get_values())
    form.is_valid()

    model = { 'form': form.cleaned_data, 'index_url': reverse('index') }
    return render_to_response('success.html', model)

class DocumentView(Resource):

    def get(self, request, document_id):
        if identity.is_new(document_id):
            form = DocumentForm()
        else:
            document = get_object_or_404(Document, pk=document_id)
            form = DocumentForm(document.get_values())

        model = { 'form': form, 'index_url': reverse('index') }
        return render_to_response('form.html', model)

    def post(self, request, document_id):
        if identity.is_new(document_id):
            document = Document()
        else:
            document = get_object_or_404(Document, pk=document_id)

        document.set_values(request.POST)
        document.save()

        form = DocumentForm(document.get_values())
        if form.is_valid():
            url = reverse('success', args=[document.id])
        else:
            url = reverse('document', args=[document.id])

        return HttpResponseRedirect(url)

Listing: urls.py

from django.conf.urls.defaults import *
from django.conf import settings
import os, views

urlpatterns = patterns('',
    url(r'^document/(?P<document_id>[A-Za-z0-9\-]+)/$', views.DocumentView.dispatch, name='document'),
    url(r'^success/(?P<document_id>[A-Za-z0-9\-]+)/$', views.success, name='success'),
    url(r'^$', views.index, name='index'),
)

if settings.DEBUG:
    urlpatterns += patterns('',
        (r'^static/(?P<path>.*)$', 'django.views.static.serve',
            {'document_root': os.path.join(os.path.dirname(__file__), 'static')}),
    )

It does add a little bit more magic to the views (since you don’t actually see the dispatch method at all) but it benefits from simpler mapping in urls.py, as well as an easier way to figure out what instance method on a Resource subclass gets called for each HTTP verb. Never felt that comfortable with popping-off of kwargs in last year’s listing.

有一天,和米高聊起了在外工作。因为工作的关系,我们已经有很长时间都没有坐在自己公司的办公室里面,好好写写代码了。在外面时间长了,心理是非常疲惫的。我早就表达过自己不喜欢在外工作

凡事有利有弊,虽然不情愿,但在外工作的这段时间,确实也是我“被成长”的一段时间。



参加工作的第一年,有一次,我出差到北京。刚到宾馆把东西放好,项目负责人就把我叫到了现场。

项目负责人:你把程序装一下。

我:什么程序?

项目负责人:就是我们的程序。

我:我没带。

项目负责人:你干什么来了!



当时,项目负责人的咆哮让我恨不得找个地缝钻进去。幸好,第二天来的同事把程序都带来了,没有造成太大的损失。从那时起,我开始知道什么叫责任。



从2008年12月份至今,我以咨询师的身份在外工作了10个月。之前写过的《和客户一起学习》是我那段时间的学习总结。如果说在上海的工作让我更深刻的理解敏捷,开始关注人,那么在西安的工作,让我开始思考大团队的运作,关注人的成长。想到的很多内容,在blog上或多或少的体现了一些。

在西安这段时间,因为工作的原因,我经常有机会接触到一些客户的领导。为了不在他们面前显得太白痴,我这个从来对管理不感冒的人开始读一些管理、系统化思考等方面的书。得益于这些内容的帮助,我不再以单纯的程序员角度看待问题,也可以更好的理解人们做出种种决定的原因。



每个人内心都有一个舒适区。对我而言,公司就是个舒适区。坐在公司工作,我会感觉很放松。出门在外,离开了心中的舒适区,会有很多不适,内心而言,会很痛苦。正所谓“生于忧患”,痛苦逼迫我不断调整,适应这个新环境,一段时间下来,就不知不觉成长了。虽然可能学到的不是我预期,但回过头来看,很多东西是有益的。



出门走走,呼吸一下外面的空气是有好处的,在外被成长也不全然那么糟糕。









I've been browsing through Chris Smith's Programming F# book and in the chapter on pattern matching he describes the 'function' key word which I haven't used before.

It's used in pattern matching expressions when we want to match against one of the parameters passed into the function which contains the pattern match.

For example if we have this somewhat contrived example:

let isEven value = match value with 
                    | x when (x % 2) = 0 -> true
                    | _ -> false

That could be rewritten using the function keyword to the following:

let isEven  = function 
               | x when (x % 2) = 0 -> true
               | _ -> false

It's a relatively straight forward way to simplify code like this although one thing I noticed while looking back through some old code I've written is that if we use this syntax then we need to ensure that the parameter we want to pattern match against is passed as the last parameter to a function.

For example this function which is used to parse the arguments passed to a script was originally written like this:

let GetArgs initialArgs  =
    let rec find args matches =
        match args with
        | hd::_ when hd = "--" -> List.to_array (matches)
        | hd::tl -> find tl (hd::matches) 
        | [] -> Array.empty
    find (List.rev (Array.to_list initialArgs) ) []

If we want to use 'function' then we'd need to put 'args' implicitly as the second argument passed to the recursive 'find' function:

let GetArgs initialArgs  =
    let rec find matches =
        function
        | hd::_ when hd = "--" -> List.to_array (matches)
        | hd::tl -> find (hd::matches) tl
        | [] -> Array.empty
    find [] (List.rev (Array.to_list initialArgs) )

I'm not sure that the resulting code is necessarily more intention revealing if the function has more than one argument passed to it. The second version of this function could be very confusing if you didn't know what the 'function' keyword actually did.

I’ve released a new version of my long-running password keeper application: JPasskeep. This new release is now able to handle a Command-Q keystroke on the Mac, giving a user (i.e. me) an chance to save any updated entries. No more mousing around to close a window.

The actual mechanism to do this was to reflectively call Apple’s EAWT application classes to allow me to register the correct event listener. Hmm, run anywhere with java GUI apps.

You can download the cross-platform and mac DMG binaries from the project’s GitHub repository.

As Instructional Designers, its always a challenge to balance meaningful instruction with information. Cathy Moore's action mapping framework is a great way to create lively elearning that allows you to include just the right amount of information in your elearning course. That said, our SMEs and clients will often say to us things like, "But we need to include _______ in the course as well." or "All that's fine, but they need to KNOW ______ as well."



Its a consulting challenge to make the trade-off between meaningful instruction and information overload in such cases. That being said, there are a few simple strategies that you can use to ensure that your course has the right impact and you can include your client's request for additional information too! Here they are.



Provide information through scenarios

As you may have noticed in my last post, I have a strong preference towards scenario based elearning. Scenarios allow us as designers to present our audience with a real life challenge. Of course, real life challenges are tough to solve without background knowledge and sound instructional thinking can allow us to weave in this important information, without being too top heavy about it. When your audience accesses knowledge from a state of pain, they're more likely to appreciate its value and remember it at their day job. What this makes us do, is think hard about the information that is really of consequence for the performances we target.



Try organising optional information in tabs

Regardless of how hard we try however, there's some information that just is so sacrosanct that it HAS TO BE part of the course. But then, what if this 'valuable' information just doesn't add value to the performance we seek and expect our audience to demonstrate during the course? I've found a middle path, especially when using Articulate Studio '09. You see, Articulate Studio allows you to customise your player to include some of this information in tabs. When we tuck away some of this really 'nice to have' yet apparently 'important' information in tabs, we have one more way to satisfy our clients and at the same time ensure that the course stays lively, engaging and useful. Take a look at this really elementary demo that I put together for this very technique.



Provide your audience with Job Aids

I've always believed that people learn over time and that learning is a process not an event. So its impractical to include roll all of the support an individual needs, into a single course. In recent months I've been surprised to see so many wonderful courses that don't link to any follow up information such as a job aid or performance support. And to think that after all that effort in putting together a great course, it should be really easy for you to put together a one-page summary of how people can perform specific tasks! So my suggestion is to include a few things for people to use as a follow up for your course:

  • a definite action that you'd like them to perform once they're done with the program;
  • a set of people that can help them answer questions if they're stuck;
  • a set of resources and job aids that can help your audience long after they've forgotten your hard-work on the course

Enable supervisors with Job Instruction

One of our problems as elearning instructional designers is that we often forget about other, lightweight methods of creating learning. I believe that people learn a lot from mentoring and apprenticeship. And who better to provide this support than the supervisors themselves? Fortunately we don't have to go down the heavyweight colocated training approach to achieve maximum benefits. In recent days I've become a big fan of the training within industry (TWI) approach of the Lean world. While the TWI set of practices dates back to second world war, the approaches make more sense today than ever. One of the practices from TWI is job instruction. The idea was to help supervisors get inexperienced workers 'up to speed' faster. So they taught supervisors to break down jobs into closely defined steps, show the procedures while explaining the key points and the reasons for the key points, then watch the student attempt under close coaching, and finally to gradually wean the student from the coaching. The course emphasized the credo, "If the student hasn't learned, the teacher hasn't taught".



Job Instruction sheets considerably simplify this activity for the supervisor and its great investment to provide them with such material to support their teams. You'll find some excellent examples of job instruction sheets at this location. Take a look, download the ones you like and start putting together these single sheet plans for supervisors to support your course. I believe the impact could be tremendous. 
One of the things that I'm always curious about is how we can do more with less. What simple, yet high impact methods are you discovering to support learning for your clients or company? Yes, my intention is to steal your ideas and use them at work, but more importantly I'm keen to learn about what's happening across the world in terms of inexpensive innovation in the field of learning. So as always, place your thoughts in the comments section of this blogpost and also let me know what you thought of this article. I'm always keen to hear your thoughts.

The family medical issue has been resolved happily, so I’m free to go back on the road. We’ve thus rescheduled the events I was supposed to do last month in Texas.

  • On February 23rd I’ll be speaking at DFW Scrum in Dallas.
  • On February 25th ThoughtWorks is organizing a technology forum in Austin.

As is usual for me, I haven’t planned exactly what I’ll talk about yet, but it’ll revolve around my usual topics of software design and agile methods.

I was trying to setup Time Machine on my MacBook to create backup on network storage. It seems that by default it is impossible to do it, if you don’t have Time Capsule.

There is a handy command though that gives you permissions to see all types of storage in Time Machine setup.

defaults write com.apple.systempreferences TMShowUnsupportedNetworkVolumes 1

I am able to see my Network Storage in Time Machine now :)
Greg

Another opportunity to tighten it up, thanks to Robbie Mac Iver and Houston APLN.

Post to Twitter Tweet This Post

Share/Bookmark

Related posts

One of the common discussions that I've had with several colleagues when we're making use of some of the higher order functions that can be applied on collections is whether to use the LINQ style syntax or to chain the different methods together.

I tend to prefer the latter approach although when asked the question after my talk at Developer Developer Developer I didn't really have a good answer other than to suggest that it seemed to just be a personal preference thing.

Damian Marshall suggested that he preferred the method chaining approach because it more clearly describes the idea of passing a collection through a pipeline where we can apply different operations to that collection.

I quite like that explanation and I think my preference for it would have probably been influenced by the fact that when coding in F# we can use the forward piping operator to achieve code which reads like this.

For example if we had a list and wanted to get all the even numbers, double them and then add them up we might do this:

[1..10] |>
List.filter (fun x -> x % 2 = 0) |>
List.map (fun x -> x * 2) |>
List.fold (fun acc x -> acc + x) 0

If I was in C# I'd probably do this:

Enumerable.Range(1, 10)
.Where(x => x % 2 == 0)
.Select(x => x * 2)
.Sum(x => x);

I found it quite difficult to work out what the equivalent LINQ syntax would be because I don't use it but I think something like this would be what you'd need to write to do the same thing:

from x in Enumerable.Range(1, 10)
where x%2 == 0
select x * 2).Sum(x => x);

I'm not sure if there's a way to do the sum within the LINQ statement or whether you need to do it using the method as I have here.

Even just writing this example I found that the way I had to write the LINQ code seemed quite counter intuitive for me with the way that I typically try to solve problems like this.

At least now thanks to Damian I now understand why that is!

to cover the iPad and other tactile tablets at The Tablet Times. Until I actually get my hands on an iPad the blog will focus on news and opinions. Once the iPad is released you can expect to start reading product reviews, developer insights, and tips and tricks for users.

Share and Enjoy: TwitThis Digg del.icio.us Reddit Technorati Facebook Google Bookmarks LinkedIn MySpace



Reading Martin's ConversationalStories renewed my confidence in this draft post from about an year ago. I just couldn't put it in the right words and gave up on it. I keep talking about deterministic universes over randomness and stuff like that but the gist of the matter is simple.


Writing stories is not the JOB of a Business Analyst in agile development. Writing stories is a collaborative effort in which Customer, BA, Dev, QA should all take part. This is the N in the INVEST principle.


And here's the post


==============


I have been talking about tracking and trends and smells and quantum physics for sometime but here's a post that takes us back to the basics. This is about the very problems (with waterfall) that we are trying to solve using alternative approaches (agile, lean, hybrid, etc).



As everything in life should start, we start by defining the problem. Waterfall is an approach that borrows heavily from Einstein's idea of a deterministic universe. The idea is that
If you know the position and velocity of each atom in the universe, you can accurately determine the state of the universe at a given point in future or the past.
The point is that this is just a theory. I am not contradicting the theory but I am just pointing to the simple fact that gathering knowledge about the position and velocity of each atom takes too much time to be of any use.



Waterfall tries to do the same thing at a very small scale; at a project level. And the argument remains the same. It'll take you too much time to understand every aspect of a problem for you to be able to successfully solve it while it's worth solving.



Agile is about improvisation. You accept the inherent randomness of the universe. This might be genuine randomness OR it might just feel random because we are not able to understand it, but at any rate the universe is random to Human Beings.



So we say, given that things are going to change in ways that cannot be determined, let's do our best to adapt to those changes as quickly as possible. To adapt is to understand what has changed, how it affects us and what can we do to "maximize our happiness" in the given situation.



This is where you require the key component of anything worth calling a success. Collaboration.



In the deterministic world of waterfall, the Business Analyst is supposed to be this wizard, who understands the whole problem, whose affected and how and formulates a solution to it all by herself. Few have succeeded at meeting this unrealistic expectation.



Agile says let us all work together towards solving this problem and I think that's a more realistic way of getting an optimum solution. Now what this means is that nobody's word is final on any solution unless everyone is happy. Neither the client, nor the Business Analyst and nor the Developers. That is what it means when we say that a user story is Negotiable (i-N-v-e-s-t).



* Increasing happiness as in the sole purpose of life.



==========
If a team has to deliver a certain amount of functionality by a certain date, then the act of estimation becomes an act of commitment. The team has essentially committed to cost, schedule, quality and scope. There are no levers left. In such a situation, velocity becomes a target rather than just a measurement. Targeting velocity makes points based estimation a charade. The team is better off estimating in real days in this case. It helps the cause of commitment. Points based estimation is useful when you agree to the following:

  1. Plan the story list for a release with only about 70% must-have functionality and the rest as negotiable. This implies it is potentially okay to release (go into production) with just that 70% functionality.
  2. By definition, estimates are approximations. Software estimates are more so.
  3. It is counterproductive to insist that your IT vendor/team deliver x points of functionality by date y. Scope negotiation does not mean x remains x. Yes, sometimes only the contents of x need change. At other times, x may become x ± delta. This is not a rip-off. It doesn't make business sense for your IT vendor to rip you off because you won't give repeat business if you are ripped off. Without repeat business, your IT vendor is likely to become uncompetitive because the cost of new business development is very high.
"Embrace change" is a two way street. IT delivery team should embrace changes to requirements and priorities. Clients should also embrace changes to scope when delivery work proceeds at a different pace than originally expected.

Here's a common misconception about agile methods. It centers on the way user stories are created and flow through the development activity. The misconception is that the product owner (or business analysts) creates user stories and then put them in front of developers to implement. The notion is that this is a flow from product owner to development, with the product owner responsible for determining what needs to be done and the developers how to do it.

A justification for this approach is that this separates the responsibilities along the lines of competence. The product owner knows the business, what the software is for, and thus what needs to be done. The developers know technology and know how to do things, so they can figure out how to realize the demands of the product owner.

This notion of product owners coming up with DecreedStories is a profound misunderstanding of the way agile development should work. When we were brainstorming names at Snowbird, I remember Kent suggesting "conversational". This emphasized the fact that the heart of our thinking was of an on-going conversation between customers and developers about how a development project should proceed.

In terms of coming up with stories, what this means is that they are always something to be refined through conversation - and that developers should play an active role in helping that definition.

  • spotting inconsistencies and gaps between the stories
  • using technical knowledge to come up with new stories that seem to fit the product owner's vision
  • seeing alternative stories that would be cheaper to build given the technological landscape
  • split stories to make them easier to plan or implement

This is the Negotiable principle in Bill Wake's INVEST test for stories. Any member of an agile team can create stories and suggest modifications. It may be that just a few members of a team gravitate to writing most of the stories. That's up to the team's self-organization as to how they want that to happen. But everyone should be engaged in coming up and refining stories. (This involvement is in addition to the develpers' responsibility to estimate stories.)

The product owner does have a special responsibility. In the end the product owner is the final decider on stories, particularly their prioritization. This reflects the fact that the product owner should be the best person to judge that slippery attribute of business value. But having a final decision maker should never stop others from participating, and should not lead people astray into a decreed model of stories.

I’ve been invited to give my talk on “the stuff I see all the time and wish I didn’t” at the London BCS-SPA meet-up in early March. Description of the talk and details of the venue below. Venue: Title: SPA-237 – Agile Adoption Anti-Patterns Presenter: James Lewis, ThoughtWorks Date: Wednesday 3rd March 2010 Time: 18:30 Venue: BCS Davidson Building, 5 Southampton [...]

I’m helping to organise the first nation-wide Agile conference in Brazil, that will take place in Porto Alegre next 22-25th June. Agile Brazil 2010 is a joint effort to bring together all the Agile communities around Brazil (industry and academy), and the conference goal is to promote communication and collaboration among its attendees aiming to disseminate the Agile culture in the whole country. Some of the confirmed international guest speakers are ThoughtWorks’ Chief Scientist Martin Fowler, Philippe Kruchten, and David Hussman.

After working the past month on building the submission system, I’m happy to announce that we’re inviting you to join as a speaker of this great event too! Tell Brazil about your experiences, present your research and share your products and learnings! You can find the deadlines and the submission guidelines at:

http://submissoes.agilebrazil.com

To find out more about the conference, please visit our website, or follow @agilebrazil on Twitter.

Post to Twitter

Related posts:

  1. Coding Dojo London: Next session is February 12th
  2. [Falando em Agile] Conference Report

Agile has shown that doing prolonged analysis upfront bears little to no value to the customer. However, doing none means the project lacks the direction that it needs. The question is, how much analysis is enough before the project starts? This will be the theme of my recently accepted “Inception Workshop: Kickstarting an Agile project” that will be pair-presented with Jenny at XP2010, in Trondheim, Norway.

My journey to find the right balance between a generalist/specialist in software has led me to projects where I had to play not only the developer role, but several to varying degrees (PM, BA, QA, Architect, Coach, team lead, …) This is my attempt to share my knowledge towards those different areas, by pairing with an experienced BA and talking about Agile project initiation.

In this workshop, we will share our experience of participating in several project inceptions. Participants will work in a condensed project inception, solving a business problem and using some tools to shape the project for delivery. Our goal is also to learn from other practitioners about the tools and techniques they’re using successfully in their projects.

More details about the session can be found at the XP2010 session description:

http://xp2010.agilealliance.org/node/5380

We are very excited about this session, and we hope to see you in Norway to participate and share your experiences too!

Post to Twitter

Related posts:

  1. [Agiles 2008] Lean Lego Workshop in Buenos Aires

One of the things which Nat Pryce and Steve Freeman suggest in their book Growing Object Oriented Software guided by tests is the idea of wrapping any third party libraries that we use in our own code.

We came across a situation where we did this and then later on I made the mistake of not following this advice.

To start with my colleague David had created a DSL which kept all the calls to Selenium nicely wrapped inside one class.

The problem we were experiencing was that we hadn't evolved the DSL with the webpage evolution to the point where we weren't taking into account that some fields on the page weren't visible until ones before them had been filled in.

We needed to change the DSL slightly and it seemed like an interesting opportunity to try and convert them to use Webdriver as it seems more suited for heavy filling in of forms which is our use case.

My first thought was that it should just be possible to change those Selenium calls to call the equivalent Webdriver methods instead but having done that we realised that the way the two tools interact with the page is slightly different so the direct replacement approach wasn't really working.

We decided to adopt a different approach whereby we would just try and change individual tests to use Webdriver instead and leave all the other tests as they are using Selenium.

I thought about creating another version of the DSL to encapsulate the Webdriver interaction with the page but decided against the idea as it didn't seem like it would add much value and the only way I thought of at the time was to create a clone of the original DSL.

We managed to get one of our tests working more effectively using Webdriver having sorted out the problems with the different interactions between fields but unfortunately the current C# API doesn't seem that stable and seems to fail somewhat randomly for reasons we haven't been able to work out yet.

As a result we now want to convert those tests I'd rewritten to take advantage of the new way they're written but to use Selenium instead!

Sadly the approach I took has made this really difficult and it's now a very frustrating journey to get the tests back into shape.

It's quite frustrating to make this type of mistake especially when I read about a solution so recently.

In hindsight I think a better approach may have been to pull our an interface to represent our DSL – currently it's a series of method calls on a few classes – and then create Webdriver and Selenium specific versions of that.

A few of things stand out for me from this experience:

  • I talked myself out of wrapping Webdriver because I saw the main reason for doing so being to shield us in case we chose to change the library and I didn't anticipate having to do that. As it is I was wrong but I didn't totally appreciate how we can benefit from defining an API that defines how we want to interact with the web page rather than how the library wants us to.
  • We need to evolve our DSLs with the application and not be afraid to change them if the application changes.
  • It probably wasn't a good idea to try and fix the DSL and change the underlying library at the same time. Small steps!

A few years ago, I was sharing a drink with a friend of mine. He was about to become a fully qualified architect. In the UK, one cannot call themselves an architect without having carried out the full, three part course, which takes at least seven years. Typically, as the course involves working in the industry, architects often took more than seven years to complete their ‘part three’ – my friend completing it in the minimum possible time made him one of the youngest qualified architects in the country. As he was about to be fully qualified, he was explaining the need to get indemnity insurance, as his opinion as a qualified architect made him liable for the quality of advice given, even advice given informally down at the pub.

There has been a short history of various individuals, companies and professional bodies within IT attempting to define and issue certification. By and large, they have not caught on. There is no belief that software delivered by ‘certified’ individuals is any better than that developed by uncertified individuals. Nor is there any evidence that in terms of getting jobs that certification counts for anything other than in specific, narrow (mostly vendor specific) technical domains – something that few serious software professional would consider worthwhile.

So, in general, why does certification exist? Societal pressure determines where certification is essential. It is important that key individuals in positions of power are properly vetted – and recognised – for the role they play in society. Which is why there are laws governing who can call themselves a lawyer, architect, engineer, surveyor. Which is why certified profesionals have responsibility placed upon them regarding the veracity of information and quality services they provide as a member of that profession.

In terms of architecture – in similar terms to medical doctors for example – society has deemed the roles they play as being important enough that certification carries with it legally enforceable expectations regarding their competency. With this responsibility, comes recognition – and a clear understanding as to how the profession is valued by society as a whole.

Certification in the land of IT is not being driven by a need for society to ensure that we are doing our jobs properly – to ensure that only competent individuals call themselves ‘programmers’, ’sysadmins’ or whatever. Nor is it being driven by a societal desire to recognise our contribution to society as as a whole. It is being driven by IT itself – at best as a misguided attempt to recognise an ability in a certain set of skill, at worst as a way of generating money. As such, certification in the world of IT is a toothless concept, lacking in any sense of legitimacy, and distracts us from the more worthy goal of understanding how we contribute to the world around us, and how we grow competency to the point where we can even consider ourselves a profession at all.

On February 11th I’ll be presenting Hydras and Hypermedia at London Geek Night.

Do you know what your enterprise apps get up to in their time off? Fighting fantasy, pick-your-path, hypermedia-driven, RESTful Web application adventures – of course.

In this speculative dungeon delve I’ll show how we can use hypermedia-driven Web applications to model rich workflows. We’ll tackle the many-headed Hydra of HATEOAS, the “Hypermedia as the Engine of Application State” monster; level up through the Web services maturity heuristic; and meet the dwarves with grudges. On the way, we’ll learn how to model business processes as domain application protocols, implement them in terms of resource lifecycles, and advertise them using HTTP idioms, media types and link relation values.

Event
London Geek Night
Description
Hydras and Hypermedia
Date
11th February
Time
7 pm10 pm
Location
ThoughtWorks UK Office
Berkshire House 168-173 High Holborn London WC1V 7AA

The book that Dave Farley and I have been working on for nigh on four years, Continuous Delivery, is finally up as a rough cut on Safari. I’m also very proud to announce that it has recently been accepted into Martin Fowler’s Signature Series. The book covers build and deployment automation, continuous integration, test automation, managing infrastructure and environments, configuration management, version control practices, data migration automation, and even governance. That’s a lot of material, and read like this it seems like a bit of a grab-bag of activities that normally gets second billing when you’re delivering software. However these turn out to be absolutely essential activities if you want to get high quality software into the hands of users as fast as possible, and then keep delivering them valuable new features1.



The book has two themes: automation and collaboration. Delivering software of any complexity involves people with a bunch of skills: testers, developers, and sysadmin / operations personnel. The last group of people often gets left out of the process of delivering software until the end, and even testers are often not as heavily involved in the development process as they should be. It’s a pattern we see over and over again when helping people deliver software, and it inevitably leads to unacceptable numbers of defects, poor architectural decisions, and lengthy and unpredictable delays to getting releases out of the door. So one of the main aims of the book is getting everybody involved in the delivery process working together right from the beginning2.

Automation is key to enabling collaboration. If deploying software to testing environments, managing infrastructure, testing, building and releasing your software are manual activities, they are of course terribly error-prone. Worse, delivery teams then typically spend a large proportion of their time fire-fighting to get branches merged and new builds created so that they can be deployed into a production-like environment and tested. This inevitably means that the feedback loop from testing is incredibly slow, and doing things like load testing on staging environments gets left till late in the process, rather than being done from the beginning when problems can be fixed cheaply. Automating as much as possible of the delivery process ensures a much tighter feedback loop, and frees people to focus on high-value activities like evolving an appropriate architecture, exploratory testing, and making deployments and releases low-risk, push-button processes.

There is also an organizing principle for all of these activities: the deployment pipeline3. The description and elaboration of this pattern forms the core of the book. The idea behind the deployment pipeline is to model the part of your project’s value stream that goes from check-in to release, and then to automate it. Every check-in triggers a new build, which then passes through the deployment pipeline as shown below (inspired by Chris Read).

Deployment Pipeline Sequence Diagram (thanks to Chris Read)

The deployment pipeline allows everybody involved in delivering software to get fast feedback on the status of every change that is introduced to an application. It makes it simple to trace which builds have been through which environments, what the results were, and what’s currently in each environment. Finally, it allows testers and operations people to self-service the build of their choice into the environment they control. The upshot is faster feedback, better collaboration within delivery teams, and – because each process from check-in to release is automated – fewer errors, more reliable releases, and shorter cycle times.

The book is still in Rough Cuts, which means we’re actively seeking out feedback to help us improve it. Please let us know what you think: the book has a feedback section, and we’ve created a group to discuss the issues we cover in the book. We’ll be posting outtakes, code examples, and further material from the book here, as well as providing regular updates on the state of the art in this space. We look forward to seeing you here!


1 We got the idea for the book’s name from the first of the Twelve Principles behind the Agile Manifesto: “Our highest priority is to satisfy the customer through early and continuous delivery of valuable software”.

2 There’s a whole movement devoted to increasing collaboration between developers and operations types.

3 Dave, along with Mark Rickmeier, came up with the idea of deployment pipelines back in 2004. The idea then circulated within ThoughtWorks for some time, and was first documented publicly in 2005 (in a blog entry by our colleague Sam Newman). Dave and I have both written papers on the subject. More recently, there has been a new variation on the theme in the shape of continuous deployment.

Last year, I ran a workshop at XP2009 and Agile 2009, helping people map behaviours to the different levels in the Dreyfus Model. Being a workshop for only 90 minutes, we only had time to introduce the model, generate a set of behaviours mapping them to each level in the model and only a small fraction of time thinking about where this might be useful in a coach’s toolbox.

I tend to use it as a way of encouraging people to self-assess their own behaviours, and as a way of seeing concrete, specific sets of behaviours that people in more advanced stages might find themselves.

We didn’t really get an opportunity to discuss the limitations of using the model in this way (remembering that all models are inherently limited in some manner).

Most useful for Novices

Ironically enough, this set of behaviours mapped in this way is only most useful to those who still remain Novices and less so, the Advanced Beginner. Novices need concrete rules, and directions. Advanced Beginners start to see context, yet it’s often helpful being specific about what sets of behaviours you might see at different stages.

Ironically, as you progress, using the Dreyfus Model in this way becomes less useful as you progress. I like to introduce this set of behaviours after people have had some experience with a certain practice. It helps people answer the question, “What does good look like?”

It’s not an exhaustive list

When I’ve run these workshops with other coaches, I find it interesting to see how they notice different sets of behaviours from what I would observe. Even when looking at a single practice, you have a multitude of behaviours at lots of different levels. It’s preciseness at describing specific sets of behaviour also has the risk of people only focusing on the prescribed behaviours instead of thinking about the sorts of behaviour that sits at this level.

I can’t imagine trying to list every single set of behaviour. As interesting as that might be, I think it would be impossible to capture, and difficult to communicate succinctly.

Best for personal development, not as performance evaluation criteria

It’s easy for managers to see a list of different levels, and then attempt of fit people into a box for performance evaluation. As much as their intention might be good good (professional growth) I think it’s easy to game.

I like to emphasise that this model is best used as a way for coach’s to help people self-assess, and for people to set their own goals about where they want to be.

Not the only tool to use

I like using this tool as a transitional tool, helping people jump the gap from Novice to Advanced Beginner and from Advanced Beginner to Competent. Beyond that, I would use less of this tool and look at other tools that help people self discover their information.

构建发布管理系统可以让软件团队仍使用他们自己熟悉的版本控制工具,而由它来处理后台的各种情况。开发人员可以进行代码的检入、检出、分支等各种操作,而不受任何影响。一旦他们认为某个版本已经条件具备,它就会被自动地推送给构建发布管理系统,并按照一个已定义好的软件开发生命周期,完成你规定的所有任务,比如自动化的过程、工作流、通知机制和授权管理等。构建发布管理可以轻松地跟踪任何变化,提供必备的报告。

One of the more interesting higher order functions that I've come across while playing with F# is the partition function which is similar to the filter function except it returns the values which meet the predicate passed in as well as the ones which don't.

I came across an interesting problem recently where we needed to do exactly this and had ended up taking a more imperative for each style approach to solve the problem because this function doesn't exist in C# as far as I know.

In F# the function makes use of a tuple to do this so if we want to create the function in C# then we need to define a tuple object first.

public class Tuple<TFirst, TSecond>
{
	private readonly TFirst first;
	private readonly TSecond second;
 
	public Tuple(TFirst first, TSecond second)
	{
		this.first = first;
		this.second = second;
	}
 
	public TFirst First
	{
		get { return first; }
	}
 
	public TSecond Second
	{
		get { return second; }
	}
}
public static class IEnumerableExtensions
{
	public static Tuple<IEnumerable<T>, IEnumerable<T>> Partition<T>(this IEnumerable<T> enumerableOf, Func<T, bool> predicate)
	{
		var positives = enumerableOf.Where(predicate);
		var negatives = enumerableOf.Where(e => !predicate(e));
		return new Tuple<IEnumerable<T>, IEnumerable<T>>(positives, negatives);
 
	}
}

I'm not sure of the best way to write this function – at the moment we end up creating two iterators to cover the two different filters that we're running over the collection which seems a bit strange.

In F# 'partition' is on List so the whole collection would be evaluated whereas in this case we're still only evaluating each item as it's needed so maybe there isn't a way to do it without using two iterators.

If we wanted to use this function to get the evens and odds from a collection we could write the following code:

var evensAndOdds = Enumerable.Range(1, 10).Partition(x => x % 2 == 0);
 
var evens = evensAndOdds.First;
var odds = evensAndOdds.Second;

The other thing that's nice about F# is that we can assign the result of the expression to two separate values in one go and I don't know of a way to do that in C#.

let evens, odds = [1..10] |> List.partition (fun x -> x % 2 = 0)

We don't need to have the intermediate variable 'evensAndOdds' which doesn't really add much to the code.

I'd be interested in knowing if there's a better way to do this than what I'm trying out.

A CEO friend of mine recently asked my opinion about Tony Karrer's Startup CTO or Developer article.

I think the part time CTO could work. Here's why.

From a development and operations perspective, the common element in successful software businesses seems to be the technical leader. Their primary characteristics are deep technical skills and a hacker mentality (about the word hacker). They tend to have the knack for architecture. They tend to be capable planners when it comes to issues like performance and security. They tend to have the programming background to lead competent people by example and dig in and prove it where necessary. They tend to know where to find good help in terms of employees and consultants. They tend to know the operations side of a software business well enough to be the one overseeing deploys, crafting the infrastructure plans, and monitoring the health of the product. They tend to be plugged in to tech news sources to be aware of trends and understand how those trends could impact the business. They tend to understand the product management side of the product well enough to guide the technology in a complementary way.

I think that's the person you need. Common sense says you'd do your best to hire or otherwise permanently engage that lead developer. If you think that's person you need, the question becomes "what else do you expect a CTO to contribute?"

The answer to that question is contextual, based on what you, as CEO, and your board believe your "Founder Developer Gap" (reference to the Tony Karrer blog entry) to be. Surely there are some business and technology strategy problems you're going to need help with that your lead developer can't help you answer. Assuming you can't or don't want to afford a full-time CTO, that seems like the perfect fit for a consultant and that seems to be where this idea of consultant CTO makes sense.

In thinking about this problem I asked around a fair amount and couldn't find any solid answers to the question "where have you seen someone in the role of CTO for a startup do a great job?" My colleagues and I interact with startups a fair amount because we're consultants. Many of us have done freelance work in the past, often for startups. We each pointed to key technical leaders that drove the development and operations parts of the businesses. A few had the title CTO but they all fit the technical rock star and hacker profile.

The main thought that gives me pause is that of earned authority. It's about leading by example. Depending on how much face time the consulting CTO has with the team, it could be extremely difficult for a consulting CTO to effect change. The consultant's advice would have to be filtered through the leaders in the trenches. Yourself and your lead dev, along with your other key leaders like product and sales managers, would need to listen, internalize and execute the strategy. I doubt a consulting CTO would have the privilege and honor of earning your team's respect directly. That generally comes from running the business together.

The other problem area is that of growth. Assuming your business succeeds and grows you'll need a proper CTO at some point. Your lead dev may or may not make sense to grow into that full-time CTO position. You could have the same problem hiring for other leadership roles too like Director Of Software Development or Master Bottle Washer. It feels like tomorrow's trouble to me but it's something to keep in mind.





I love a good process diagram…. its not just a pretty picture – the content and the form need to complement and build on each other. They are tricky things to design.

I did this one recently, and to be honest it needs more thought. The steps shown are all at different scales so its not perfect but it does manage to get 3 independent iterative cycles positioned within a larger iterative cycle.

This one is a much better view of the “Deliver” Cycle, with better entry and exit points. I also like the floating assets and people bits that complement the process itself.

This one focuses on the describing the different scales of time in cyclical activities. Who said you cant mix a flat process diagram with a 3D desk and people !

And lastly, well the sketchy nature and purple makes it look straight up crazy (there is a bit of “Magic Happens” to it) – so i like it :)

I’ve put these together – XP2010 and Better Software – because they occur one after the other. So I may be insane for considering this, but I’m just so psyched that these conferences are embracing my work on Facilitation Patterns and Antipatterns.

Now to work on the second deck of cards for March (SDC2010) – I want to have two variants of the deck ready to go for all three conferences.

Post to Twitter Tweet This Post

Share/Bookmark

Related posts

I love talking about this stuff, and David Giard gave me the opportunity at the CodeMash 2010 conference.

http://technologyandfriends.com/archive/2010/02/01/tf0067.aspx

Post to Twitter Tweet This Post

Share/Bookmark

Related posts

I’ve been suffering of selenese flu for months, being on a .net project we were using selenium RC. The typical symptoms are flaky, slow tests and sometimes a lot of sleeps in your code to make it work.

Selenium has its age and it struggles to cope with the current web 2.0 asynchronous calls & rich javascript.

Fortunately old good Simon is working hard at Google on webdriver, and in December the official port has been released also for the .net platform.

It works alright, there are some classes missing and you have to put the IE dll on your project as a content so that it gets copied on the bin folder to make it work.

A part from that, it’s faster, more reliable, more fun to write.

It’s time to cure your flu, webdriver is your medication.

A friend of mine recently started as the CEO of an exciting new Software as a Service business. He asked me what I thought about helping him evaluate the quality of the software asset he now manages.



Code quality is such a huge topic. It’s a question of fitness for purpose. Your answer varies widely depending on what you need that software asset to do for you. For example, the method you use to assess the quality of a program to scrape Craig’s List is vastly different from the method you use to assess a web application you use to operate your online auction. This friend of mine has something closer to the auction site than the Craig’s List scraper.

Here are 10 questions I suggested he explore with someone technical he trusts:

  1. How stable is the product right now? What are the outstanding functional defects and non-functional rough edges?

  2. How well specified is the application? If we broke a feature tomorrow, how would we know? Are the specifications executable or do we need a person to manually verify new builds?

  3. How complex is the application right now? How long would it take someone generally familiar with the technology to isolate and repair a problem? Unneeded complexity increases the likelihood of future defects and makes it more difficult to find and retain developers.

  4. What third-party dependencies exist? Open source and commercial libraries imply license terms, fees, etc.

  5. How does the application scale? What can you support on the current infrastructure and what’s the incremental cost of selling new subscriptions?

  6. What provisions are in place to deal with disasters? What is the physical server architecture? How does the system handle losing critical components like servers, switches, load balancers, etc?

  7. What does the development environment look like? What does it take to bring new developers into the team and get them productive?

  8. How is the source code managed? How do you reproduce particular configurations of the app for historical or bug-fixing reasons?

  9. What is the build and release process? How do versions of the software promote through different environments from development through testing to production? How do I safely push new releases into the production environment and how do I revert to previous versions if that becomes necessary?

  10. How do you know how the app is performing? Does it notify you when something goes wrong? Are there any monitoring or management services keeping watch?



I was writing some helpers for OAuth Twitter authorization. One of the problem I got was the encoding. OAuth is using UTF-8 and percent encoding (special style of URL ecoding).

I couldn’t find anything build-in in Java or Groovy so I wrote a very short little method that does it.

def encodeString(def stringToEncode){

def reservedCaracters = [32:1, 33:1, 42:1, 34:1, 39:1, 40:1, 41:1, 59:1, 58:1, 64:1, 38:1, 61:1, 43:1, 36:1, 33:1, 47:1, 63:1, 37:1, 91:1, 93:1, 35:1]

def encoded =  stringToEncode.collect { letter ->

reservedCaracters[(int)letter] ? “%” +Integer.toHexString((int)letter).toString().toUpperCase() : letter

}

return encoded.join(”")

}

If you ever need something similar, use it ;)

Greg

Disclaimer: ThoughtWorks embraces the individuality of the people in the organization and hence the opinions expressed in the blogs may contradict each other and also may not represent the opinions of ThoughtWorks.