How I Learned to Let My Workers Lead

I recently came across a really interesting article written by Ralph Stayer titled ‘How I Learned to Let My Workers Lead‘ about his experiences at Johnsonville Foods.

It describes the way that he was able to help change the company culture from one where he made all the decisions and took all responsibility to one where everyone in the company was involved in decision making, resulting in a more successful organisation.

One of the interesting early parts of the article talks about how the problems created are entirely the fault of the author who is the CEO of the company:

I started by searching for a book that would tell me how to get people to care about their jobs and their company.

And yet, I told myself, why not? I had made the company so I could fix it. This was an insight filled with pitfalls but it was an insight: the fault was not someone else’s, the fault was mine.

It reminds me a lot of the following quote which is attributed to Dr Paul Batalden (although apparently also to several others!) who was influenced by W. Edwards Deming.

“Every system is perfectly designed to get the results it gets.”

I think this is something which is very easy to forget and we probably end up placing too much emphasis on the individual and forget the context in which they are operating.

For example, it’s much easier to perform well working in a team in an organisation which really buys into the agile/lean way of doing things than it is in one where a strong culture of hierarchy, a tendency to favour the big up front approach and a culture where politics and politics and bureaucracy are rife.

Another interesting observation is that his employees were so used to him solving their problems that even when given permission to solve problems they struggled to do so:

They were good soldiers, and they did their best, but I had trained them to expect me to solve their problems. I had nurtured their inability by expecting them to be incapable; now they met my expectations with an inability to make decisions unless they knew which decisions I wanted them to make.

I wonder if this explains why when you try to work in an agile way with a team which is used to a strict hierarchy they will initially find it difficult to challenge any decisions and solve their own problems.

This links well with another thing I noticed as I was reading the article - it takes a long time to change a system. The article covers a period of around 5 years and still there is more that can be done to make the organisation even better.

Another good insight is that we don’t need to have a grand plan in order to initiate change – we can just do it:

These system changes taught me two more valuable lessons. First, just start. Don’t wait until you have all the answers…if I had waited until I had all the answers, I’d still be waiting. A grand plan was impossible…I just knew I had to change something in order to alter expectations and begin moving toward my goal.

This links closely to the idea of asking for forgiveness rather than getting permission which I’ve had drilled into me by my more experienced colleagues over the years! I’m sure there are situations in which that advice doesn’t apply but the majority of the time it seems like a pretty good mantra to follow and encourages you to be more active and try and make something good happen.

There is a tendency when coaching that as soon as someone isn’t doing something as well as you would/think you would to immediately take back control of the problem which the author identifies:

I wanted coordinators who could build problem-solving capacities in others rather than solve their problems for them…I took every opportunity to stress the need for coaching skills…whenever someone became a coordinator, I made sure word got around that the promotion was for demonstrated abilities as a teacher, coach, and facilitator.

This new promotion standard sent a new message: to get ahead at Johnsonville, you need a talent for cultivating and encouraging problem solvers and responsibility takers.

The problem with doing that is that you encourage the wrong behaviour but equally we need to ensure that
it is safe to fail otherwise people will be scared to make the wrong decision.

In software we can design this into the system by ensuring that we have tight feedback loops and by automating out the possibility of human error.

Another observation which I imagine will be fairly familiar to anyone working in software development is the following:

In our early enthusiasm, we had played down the technical aspects of our business, encouraging everyone to become a coordinator, even those who were far better suited to technical specialties.

A career team recommended that Johnsonville set up dual career tracks — one for specialists and one for coordinators — that would enable both to earn recognition, status, and compensation on the basis of performance alone.

ThoughtWorks seems to do this pretty well compared to a lot of companies where you end up becoming a manager if you are a very strong technician a.k.a The Peter Principle

Stayer ends with some interesting ideas on improving performance in organisations of which the stand out points for me were:

  • People want to be great. If they aren’t, it’s because management won’t let them be.
  • Learning is a process, not a goal. Each new insight creates a new layer of potential insights.

He also introduced a learning and personal development team to help employees improve themselves which seems like an interesting idea and one I hadn’t thought about before:

The traditional personnel department disappeared and was replaced by a learning and personal development team to help individual employees develop their own Points B and A — their destinations and starting points — and figure out how to use Johnsonville to reach their goals.

The summary of his learnings is perhaps the most insightful though:

I’ve learned that change is the real job of every effective business leader because change is about the present and the future, not about the past. There is no end to change. This story is only an interim report.

This is the idea of continuous improvement that lean thinking encourages us to embrace – it’s all about the journey and not the destination.

Reading this reminded me a lot of the way my colleague Pat Kua works in helping other people in his teams developer their skills and I’m hoping that InfoQ have recorded his talk from QCon London ‘Building the next generation of next leaders‘ which I’m told covers similar ground.

The Poppendieck’s also have an interesting video recorded at Google where they cover the role of leadership in software development.

Posted in software-development | 2 Comments

Saved from an episode of bear shaving

As part of our continuous integration build we have a step in the build which tears down a Windows service, uninstalls it and then reinstalls it later on from the latest files checked into the repository.

One problem we’ve been having recently is that despite the fact it should already have been uninstalled a lock has been kept on the log4net dll in our build directory, a directory that we tear down as one of the next steps.

It was a bit of a sporadic failure and whenever we went on the build machine and checked for file handles with Process Explorer the log4net dll never showed up on the list.

I wrongly assumed that it couldn’t be getting locked by the Windows service because the Windows service would already be gone by that stage.

We therefore started on a bear shaving expedition which involved trying to make use of Unlocker and File Assassin to release the file handle so that we’d be able to delete the directory.

We weren’t able to get either of those tools to do the job from the command line and luckily at this stage another colleague had the idea to check whether or not the Windows service was actually immediately removed in Task Manager when we tore it down.

After realising that it wasn’t we were able to address this problem and put a step in the build to look for that process and kill it as part of the build.

I guess the real solution to this problem would be for the uninstall to block until it was properly uninstalled but this seems to be the closest we can get to addressing the cause rather than the effect.

Posted in software-development | 1 Comment

Reading code: underscore.js

I’ve been spending a bit of time reading through the source code of underscore.js, a JavaScript library that provides lots of functional programming support which my colleague Dave Yeung pointed out to me after reading my post about building a small application with node.js.

I’m still getting used to the way that JavaScript libraries are written but these were some of the interesting things that I got from reading the code:

  • There are a couple of places in the code where the author has some code which runs conditionally and this is achieved by including that expression on the right hand side of an ‘&&’.

    For example on line 129 in the ‘filter’ function:

    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    
      // Return all the elements that pass a truth test.
      // Delegates to JavaScript 1.6's native filter if available.
      _.filter = function(obj, iterator, context) {
        if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
        var results = [];
        each(obj, function(value, index, list) {
          iterator.call(context, value, index, list) && results.push(value);
        });
        return results;
      };

    I would probably have used an if statement to check the result from calling ‘iterator’ but this way is more concise and pretty neat.

    The same type of thing is done on line 150 in the ‘every’ function:

    145
    146
    147
    148
    149
    150
    151
    152
    153
    
      _.every = function(obj, iterator, context) {
        iterator = iterator || _.identity;
        if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
        var result = true;
        each(obj, function(value, index, list) {
          if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop();
        });
        return result;
      };

    The result is collected and the loop will also exit if the value of ‘result’ is ever false which is again a cool way to organise code.

  • It’s also quite cool that you can assign a value to a variable from within a conditional – this isn’t possible in any of the other languages that I’ve used previously as far as I’m aware.

    It’s even more evident in the ‘max’ function:

    191
    192
    193
    194
    195
    196
    197
    198
    199
    
      _.max = function(obj, iterator, context) {
        if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
        var result = {computed : -Infinity};
        each(obj, function(value, index, list) {
          var computed = iterator ? iterator.call(context, value, index, list) : value;
          computed >= result.computed && (result = {value : value, computed : computed});
        });
        return result.value;
      };

    ‘result’ is conditionally assigned on line 196 but only if the computed value is greater than the current computed value. Again an if statement is avoided.

    Another interesting thing about this function is that it specifically checks the type of the ‘obj’ passed in which reminded me about the discussion around Twitter having those sorts of checks in their Ruby code around a year ago. I guess that type of thing would be more prevalent in library code than in an application though.

  • I hadn’t come across the !! construct which is used to turn a JavaScript expression into its boolean equivalent:
    506
    507
    508
    
      _.isArray = nativeIsArray || function(obj) {
        return !!(obj && obj.concat && obj.unshift && !obj.callee);
      };

    Without using ‘!!” the expression would return ‘undefined’ in the case that one of those functions on ‘obj’ was not set. ‘!!’ forces the return value to be ‘false’.

  • Another technique used in this code base is that of dynamically adding methods to the prototype of an object:
    666
    667
    668
    669
    670
    671
    672
    673
    
      // Add all mutator Array functions to the wrapper.
      each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
        var method = ArrayProto[name];
        wrapper.prototype[name] = function() {
          method.apply(this._wrapped, arguments);
          return result(this._wrapped, this._chain);
        };
      });

    This is quite a cool use of meta programming although it isn’t initially obvious how those functions end up on the object unless you know what to look for. It does significantly reduce the code needed to add these functions to the ‘wrapper’ object’s prototype, avoiding the ‘same whitespace, different values‘ problem that Neal Ford outlines in his article about harvesting idiomatic patterns in our code.

Posted in javascript | 5 Comments

Finding the assumptions in stories

My colleague J.K. has written an interesting blog post where he describes a slightly different approach that he’s been taking to writing stories to help move the business value in a story towards the beginning of the description and avoid detailing a solution in the ‘I want’ section of the story.

To summarise, J.K.’s current approach involves moving from the traditional story format of:

As I...
I want..
So that...

To the following:

As I... 
I want..
By...

I quite like this idea and I’ve noticed that even without using this story format technical solutions are sometimes described as the business requirement and we need to look beyond the ‘I want’ section of the story card to find the real value and locate assumptions which have led to the story being written in that way.

To give a recent example, a colleague and I picked up the following story:

As the business
I want a HTTP module to be included on the old site
So that I can redirect a small percentage of traffic to the new site

We assumed that other options for redirecting traffic must have already been analysed and written off in order for this to be the suggested solution so we initially started looking at how to implement it.

After a bit of investigation it became clear that this was going to be quite an invasive solution to the problem and would involve re-testing of the whole old site (since we would be making a change there) before it could be put into production. That would take 2 weeks.

Speaking with Toni and Ashok about the problem it became clear that it should be possible to control whether traffic was going to the old or new site by changing the configuration in our load balancer, Netscaler.

Discussing this further we found out that this had been tried previously and hadn’t quite worked out as expected which was why it hadn’t been considered as an option.

We spent some time talking through using Netscaler with the network team and agreed to try it out on a performance environment and see whether it would balance traffic in the way that we wanted which it did.

We still need to make sure that it works as expected in production but it was an interesting example of how solutions can be excluded based on prior experience even though they might still be useful to us.

I’ll certainly be more aware of noticing when a story details a solution and try and look for the actual requirement after this experience.

Posted in agile | 4 Comments

Selenium, Firefox and HTTPS pages

A fairly common scenario that we come across when building automated test suites using Selenium is the need to get past the security exception that Firefox pops up when you try to access a self signed HTTPS page.

Luckily there is quite a cool plugin for Firefox called ‘Remember Certificate Exception‘ which automatically clicks through the exception and allows the automated tests to keep running and not get stuck on the certificate exception page.

One other thing to note is that if the first time you hit a HTTPS page is on a HTTP POST then the automated test will still get stuck because after the plugin has accepted the certificate exception it will try to refresh the page which leads to the ‘Do you want to resend the data’ pop up.

We’ve previously got around this by writing a script using AutoIt which waits for that specific pop up and then ‘presses the spacebar’ but another way is to ensure that you hit a HTTPS page with a GET request at the beginning of the build so that the certificate exception is accepted for the rest of the test run.

To use the plugin in the build we need to add it to the Firefox profile that we use to run the build.

In Windows you need to run this command (having first ensured that all instances of Firefox are closed):

firefox.exe --ProfileManager

We then need to create a profile which points to the ‘/path/to/selenium/profile’ directory that we will use when launching Selenium Server. There is a much more detailed description of how to do that on this blog post.

After that we need to launch Firefox with that profile and then add the plugin to the profile.

Having done that we need to tell Selenium Server to use that profile whenever it runs any tests which can be done like so:

java -jar selenium-server.jar -firefoxProfileTemplate /path/to/selenium/profile
Posted in selenium, testing | 1 Comment