Skip to content


Exception Erasure

One of Scala’s biggest selling points is its seamless integration with regular Java code. Another, albeit much smaller selling point is the lack of checked exceptions. However when mixed, these two features can cause some confusion when Scala code is called from Java code.

Let’s take the following small example. I have some Scala library code that pulls the protocol off a URL represented as a String. Nothing complicated, it just news up a URL object and returns whatever getProtocol does.

package org.mccv
 
import java.net.URL
 
class CheckedEraser{
  def getProtocol(urlStr:String):String = {
    val url = new URL(urlStr)
    url.getProtocol
  }
}

What does the same thing in Java look like? Something like this

package org.mccv;
 
import orc.mccv.CheckedEraser;
 
import java.net.URL;
import java.net.MalformedURLException;
 
public class CheckedJava {
    public String getProtocol(String urlStr)
    throws MalformedURLException{
        URL u = new URL(urlStr);
        return u.getProtocol();
    }
}

Note that I have to declare that it throws MalformedURLException here. This isn’t surprising… as a Java developer working with URLs I’m probably all too familiar with MalformedURLException. Now comes the tricky part. I want to call my Scala code from Java. Here we go…

package org.mccv;
 
import orc.mccv.CheckedEraser;
 
import java.net.URL;
import java.net.MalformedURLException;
 
public class CheckedCaller {
    public static void main(String [] args){
        String urlStr = "www.google.com";
        String protocol = null;
 
        // Scala
        System.out.println("trying with Scala...");
        CheckedEraser ce = new CheckedEraser();
        protocol = ce.getProtocol(urlStr);
    }
}

As you can see, I didn’t actually pass in a valid URL… so what happens? I get a MalformedURLException thrown. Ok, so I should catch that. But does this work?

        try{
            protocol = ce.getProtocol(urlStr);
        }catch(MalformedURLException e){
            System.out.println("caught an exception of type " 
               + e.getClass().getName());
            e.printStackTrace();
        }

Nope, won’t compile. My Scala method doesn’t throw a MalformedURLException, because I was lazy and didn’t add my throws annotation. I’m forced to just catch Exception, and deal with refinement of that exception in my catch block, which is pretty ugly.

So a word of caution when handing Scala libraries over to Java developers… if you aren’t rigorous on your throws annotations, you are handing them a different exception handling contract. This may be ok, but it almost certainly needs to be explicitly stated. Note that this same exception erasure issue applies to Groovy, and likely other JVM languages that lack typed exceptions.

Posted in scala.

Tagged with , .


Things that are easier in Scala vol. 2

I’ve been working with Cassandra recently, and have been using its Thrift interface quite a bit. Cassandra stores values as byte arrays, which offers a lot of room for flexibility, but also makes it a bit clumsy to get values in. The following Java code shows a minimal Cassadra example, opening a connection and mutating a few rows.

package org.mccv;
 
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransportException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.TException;
import org.apache.cassandra.service.Cassandra;
import org.apache.cassandra.service.InvalidRequestException;
import org.apache.cassandra.service.UnavailableException;
 
import java.io.UnsupportedEncodingException;
 
public class CassandraJava {
    public void insertCassandra(String cassHost, int cassPort){
        try{
            // boilerplate to get Cassandra set up
            TSocket sock = new TSocket(cassHost, cassPort);
            TBinaryProtocol tr = new TBinaryProtocol(sock);
            Cassandra.Client c = new Cassandra.Client(tr,tr);
            sock.open();
 
            // run the inserts
            c.insert("MyTable","key","colFamily:colName1",
                    "foo".getBytes("UTF-8"),
                    System.currentTimeMillis(),false);
            c.insert("MyTable","key","colFamily:colName2",
                    "bar".getBytes("UTF-8"),
                    System.currentTimeMillis(),false);
            c.insert("MyTable","key","colFamily:colName3",
                    "baz".getBytes("UTF-8"),
                    System.currentTimeMillis(),false);
        }catch(TTransportException e){
            e.printStackTrace();
        }catch(TException te){
            te.printStackTrace();
        }catch(InvalidRequestException ire){
            ire.printStackTrace();
        }catch(UnavailableException ue){
            ue.printStackTrace();
        }catch(UnsupportedEncodingException uee){
            uee.printStackTrace();
        }
    }
}

A few things to note. First, calling getBytes(“UTF-8″) on strings is sorta ugly. Note that this gets even worse when you switch to Cassandra trunk/0.4, as the column names also become byte arrays. Second, I have to pass in my table, key, timestamp and blocking arguments on each call even though they don’t change.

Let’s see if we can solve the first problem with Scala. The following sample is a first attempt. Note the implicit function defined at the beginning of the object. This tells the Scala compiler that anywhere (well, anywhere that implicit function is in scope) that you need an Array[Byte] and have String, you can execute the function to do the conversion.

package orc.mccv
 
import org.apache.thrift.transport.{TSocket,TTransportException}
import org.apache.thrift.protocol.TBinaryProtocol
import org.apache.thrift.TException
import org.apache.cassandra.service.{Cassandra,
  InvalidRequestException,UnavailableException}
 
object CassandraScala{
  // create a transparent conversion of strings to byte arrays
  private implicit def string2ByteArray(s: String): Array[Byte] =
    s.getBytes("UTF-8")
 
  def cassInsert(cassHost:String,cassPort:Int) = {
    // boilerplate to get cassandra set up
    val sock = new TSocket(cassHost, cassPort)
    val tr = new TBinaryProtocol(sock)
    val c = new Cassandra.Client(tr,tr)
    sock.open
    // run the inserts
    c.insert("MyTable","key","colFamily:colName1",
            "foo",System.currentTimeMillis(),false)
    c.insert("MyTable","key","colFamily:colName2",
            "bar",System.currentTimeMillis(),false)
    c.insert("MyTable","key","colFamily:colName3",
            "baz",System.currentTimeMillis(),false)
  }
}

The resulting code is quite a bit shorter. Note that I’m cheating a bit by not catching all the exceptions… but it’s still a fair bit more concise.

But what about all the duplicate arguments? Here we can use currying to create a new function with our default arguments applied, leaving us to just supply the changing arguments.

package orc.mccv
 
import org.apache.thrift.transport.{TSocket,TTransportException}
import org.apache.thrift.protocol.TBinaryProtocol
import org.apache.thrift.TException
import org.apache.cassandra.service.{Cassandra,
  InvalidRequestException,UnavailableException}
 
object CassandraScala{
  // create a transparent conversion of strings to byte arrays
  private implicit def string2ByteArray(s: String): Array[Byte] =
    s.getBytes("UTF-8")
 
  def cassInsertCurried(cassHost:String,cassPort:Int) = {
    // boilerplate to get cassandra set up
    val sock = new TSocket(cassHost, cassPort)
    val tr = new TBinaryProtocol(sock)
    val c = new Cassandra.Client(tr,tr)
    sock.open
    // create a partially applied function with our
    // default arguments in place
    val insert = c.insert("MyTable","key",_:String,_:String,
      System.currentTimeMillis(),false)
    insert("colFamily:colName1","foo")
    insert("colFamily:colName2","bar")
    insert("colFamily:colName3","baz")
  }
}

Here we create a new Function object call ins. The syntax _:String in our call means that those arguments are not applied, and will need to be supplied in calls to ins. Since Function defines an apply method, you can call it just like a normal method. The currying call may throw some people, but the resulting insert calls are almost certainly more readable than the version that has six args.

Posted in scala.

Tagged with , .


What is timestamp used for in all those Cassandra calls?

While working on scassandra, I ran across a mailing list thread asking about Cassandra’s MVCC support. I figured it had it, as most of the column data structures and most of the thrift API calls have it. Wrong. Timestamp is just used for eventual consistency support, as a way to track which mutations are older than others. The timestamp on a mutation is always provided by the client. In general this should be one of

  • The time at which the data to be mutated was generated
  • The current system time if the former is not available

Note that a lot of the Cassandra examples use a timestamp of zero, but this is just to make the examples independent of system clocks.

Posted in cassandra.


Cassandra get_columns_since gotcha

This makes sense once you think about it, but it doesn’t appear to show up anywhere in the doc. If you call get_columns_since on a column family that is not ordered by Time, the call succeeds but always returns zero rows. To get this working you’ll need a column defined like this

            <ColumnFamily ColumnSort="Time" Name="Statuses"/>

Posted in cassandra.


Running Scala specs tests in Maven with JUnit 4

My first foray into Scala unit testing wasn’t quite as smooth as I’d wanted, but I have it working now. The specs doc is pretty good. However what it doesn’t tell you is that JUnit 4.0 doesn’t work. Or 4.1. If you try these you’ll run into a “No runnable methods” found, with the following trace

java.lang.Exception: No runnable methods
        at org.junit.internal.runners.TestClassMethodsRunner.testAborted(TestClassMethodsRunner.java:42)
        at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:33)
        at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
        at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
        at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52)
        at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
        at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
        at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:338)
        at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:997)

Upgrading to JUnit 4.4 did the trick. Pom snippet is

        <dependency>
            <groupId>org.scala-tools.testing</groupId>
            <artifactId>specs</artifactId>
            <version>1.5.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.4</version>
            <scope>test</scope>
        </dependency>

Test snippet is

package org.mccv.cassandra
 
import org.specs._
import org.specs.runner._
/**
 * Created by IntelliJ IDEA.
 * User: mmcbride
 * Date: Jul 24, 2009
 * Time: 10:43:31 AM
 * To change this template use File | Settings | File Templates.
 */
 
class cassandraTest extends JUnit4(BasicCassandra)
 
object BasicCassandra extends Specification {
  val cass = Cassandra("localhost",9160)
  doBefore {
    cass.connect()
  }
  doAfter {
    cass.close()
  }
  "Cassandra(\"localhost\",9160)" should {
    setSequential()
    "create a Cassandra instance" in {
      cass must_!= null
    }
    "provide for creation of a Db" in {
      cass.db("SocialGraph") must_!= null
    }
    "allow insertion of values" in {
      cass.insert("SocialGraph","mccv","Details:name","Mark McBride".getBytes("UTF-8"))
    }
  }
 
  "cass.Db(\"SocialGraph\")" should {
 
  }
}

Posted in maven, scala.


Highlighting vs. Fixing Mistakes

This is an email I need to send myself every three months or so… every time I hit one of my jaded cycles and turn into a sarcastic cynic.

It’s not so hard to find fault in projects, people, processes, etc. It’s not hard to point these things out publicly, and to make people feel small when they challenge your analysis. What’s more challenging, and what separates the good leaders from the merely average is working with people to address the faults in a productive manner.

The uncivilized leader (me in my cynical phases) sees faults and looks for the least tedious solution. It’s often tempting to discount people as incompetent and processes as useless. The quickest solution seems to be to marginalize people and ignore processes. However in the long run (at least in a large corporation) this leads to a team made up of mostly marginalized people, and chaotic processes that start crushing projects.

Instead of marginalizing a problem person, ask how they could make a productive contribution to the group. Instead of bitching about a process, propose a new, better one. Instead of tearing apart a technical design somebody has a deep emotional investment in, coach them on how to fix the current design and build a better one next time.

Posted in organization.


TalkingPuffin Twitter API Enhancement Samples

Dave recently pushed some of my API changes to the main TalkingPuffin. There are quite a few updates. The API is more complete now, more resilient, supports optional REST arguments, and has a method to load all pages of various APIs. I thought I’d show a few of the enhancements here.

This first listing shows how to use the new TwitterArgs class.

package org.talkingpuffin.twitter
 
object ShowAPI {
 
  def main(args: Array[String]) = {
    // set up our credentials and session
    val user = "foo"
    val password = "bar"
    val sess = TwitterSession(user,password)
    // same method as before
    var friendsTweets = sess.getFriendsTimeline();
    System.out.println("got " + friendsTweets.size + " tweets from old style method")
    // use per page count
    friendsTweets = sess.getFriendsTimeline(TwitterArgs.maxResults(200))
    System.out.println("got " + friendsTweets.size + " tweets using per page count")
    // use chained twitter args
    friendsTweets = sess.getFriendsTimeline(TwitterArgs.maxResults(200).page(2))
    System.out.println("got " + friendsTweets.size + " tweets using chained twitter args")
  }
}

There are a variety of methods that support passing in a TwitterArgs instance. These can be constructed by calling the various methods on the TwitterArgs object, e.g.

val args = TwitterArgs.maxResults(200)

If you want to pass in multiple optional arguments you can make calls on an existing args instance, e.g.

val args = oldArgs.page(2)

These get converted to a URL query segment, and are appended to the URLs called for twitter data.

The next listing shows some Scala functional programming neatness, and builds on my previous post about retry logic.

package org.talkingpuffin.twitter
 
object ShowAPI {
 
  def main(args: Array[String]) = {
    // set up our credentials and session
    val user = ""
    val password = ""
    val sess = TwitterSession(user,password)
 
    // demo load all... this just loads the first page
    var myTweets = sess.getUserTimeline("mccv")
    System.out.println("got " + myTweets.size + " tweets from my timeline")
    // now we show load all.  loadAll just wants a function that takes an int as an arg,
    // which is the page.  Scala's partially applied functions make this pretty easy
    // to use in a general purpose way
    myTweets = sess.loadAll(sess.getUserTimeline("mccv",_:Int))
    System.out.println("got " + myTweets.size + " tweets using loadAll")
    // this is even fancier.  Here I add retry logic to load all.
    // note that retryPage is a function I defined here... but the session
    // doesn't care.  It keeps iterating through pages, retrying and loading
    // until it reaches the end.
    myTweets = sess.loadAll(retryPage(_:Int,sess.getUserTimeline("mccv",_:Int)))
    System.out.println("got " + myTweets.size + " tweets using loadAll and retries")
  }
 
    /**
    * this is a function that is sort of a thunk through to tryNTimes.
    */
    def retryPage[T](page:Int, func: (Int) => T):T = {
        // here we define a privately scoped function
        // that can be passed to tryNTimes
        def tryPage() = {
            func(page)
        }
        // and now we try N (5) times
        tryNTimes(tryPage,5)
    }
 
    /**
    * from the last blog post, a retrier
    */
    def tryNTimes[T](func: () => T, runNumber: Int):T = {
      try{
          func()
      } catch {
        case e if runNumber > 1 => tryNTimes(func,runNumber - 1)
        case e => throw e
      }
    }
 
}

Hopefully this code is more or less self documenting. The first session call just gets the first page of the user timeline. This is usually sufficient for writing a Twitter client, but if you are doing data mining it isn’t so great. The new API introduces a method called loadAll of type (f:(Int) => List[T]) => List[T]. This means that any method that takes a single int argument (a page number) and returns a list can be passed to loadAll. It keeps executing the passed in function with increasing page numbers until an empty list is returned (note that this must be the behavior on page overruns as currently implemented. If the overrun URI returns a 404 we’ll get an exception thrown. Luckily Twitter currently just returns an empty list).

The second call shows this in action. It’s using a slightly more complicated case, because getUserTimeline takes a String and an Int. Scala’s partially applied functions make this a snap. The line

sess.getUserTimeline("mccv",_:Int)

Takes the getUserTimeline call with one bound argument and one unbound. It returns a function of type (Int) => List[TwitterStatus], which is exactly what loadAll wants.

The third call is even more complicated um, sophisticated. Let’s say we want to retry operations five times, just in case we get dropped connections in the middle of a big load. Well, all we need to do is get a function that takes an int and returns a list into loadAll.

In a previous blog post I wrote about implementing a retryable method. You can see this more or less unchanged at the end of the file. Unfortunately its signature isn’t quite what we want. So we define retryPage, which acts as an adapter from loadAll to tryNTimes. With this setup in place, we can set up our last call, which uses two partially applied functions. The first converts getUserTimeline into the page-argument-only form, and the second converts retryPage into a page-argument-only form.

Running the two samples combined this gives us the following output

got 20 tweets from old style method
got 199 tweets using per page count
got 200 tweets using chained twitter args
got 20 tweets from my timeline
got 824 tweets using loadAll
trying to get page 1
trying to get page 2
trying to get page 3
trying to get page 4
trying to get page 5
trying to get page 6
trying to get page 7
trying to get page 8
trying to get page 9
trying to get page 10
trying to get page 11
trying to get page 12
trying to get page 13
trying to get page 14
trying to get page 15
trying to get page 16
trying to get page 17
trying to get page 18
trying to get page 19
trying to get page 20
trying to get page 21
trying to get page 22
trying to get page 23
trying to get page 24
trying to get page 25
trying to get page 26
trying to get page 27
trying to get page 28
trying to get page 29
trying to get page 30
trying to get page 31
trying to get page 32
trying to get page 33
trying to get page 34
trying to get page 35
trying to get page 36
trying to get page 37
trying to get page 38
trying to get page 39
trying to get page 40
trying to get page 41
trying to get page 42
trying to get page 43
got 824 tweets using loadAll and retries

Posted in scala.


A slightly cleaner Java Retryable

In my last post I walked through an implementation of a class that retries an operation N times before failing. However after reading this post I realized that using Java’s Callable class cleans things up quite a bit. This completely removes the need for a Retryable interface, and leaves you with Retrier implemented as

package org.mccv;
 
import java.util.concurrent.Callable;
 
/**
 * The implementation of our retrying class
 */
public class Retryer<T> {
	/**
	 * The retryable we will call
	 */
	private Callable<T> retryable;
 
	/**
	 * Just assign our retryable field 
	 */
	public Retryer(Callable<T> retryable){
		this.retryable = retryable;
	}
 
	/**
	 * Try to execute our retryable n times 
	 */
	public T tryTimes(int times) throws Exception{
		// store the last thrown recoverable exception
		RecoverableException lastException = null;
		// try the specified number of times
		for(int i = 0; i < times; i++){
			System.out.println("running it with " + (times-i) + " tries remaining");
			try{
				return retryable.call();
			}catch(RecoverableException re){
				lastException = re;
			}
		}
		throw lastException;
	}
}

And an implementation/usage demonstration as

package org.mccv;
 
import java.util.concurrent.Callable;
 
/**
 * An implementation of the Retryable interface
 */
public class RetryableImpl implements Callable<String>{
	/**
	 * Show usage of the retryer
	 */
	public static void main(String [] args){
		// create a new retrier
		Retryer<String> retrier = new Retryer<String>(new RetryableImpl());
		// run the retrier 
		try{
			System.out.println("result = " + retrier.tryTimes(3));
		}catch(Exception e){
			System.out.println("failed after 3 tries");
		}
	}
 
	/**
	 * An intentionally flaky operation
	 */
	public String call() throws Exception{
	    if(Math.random() > 0.3){
	        throw new RecoverableException();
	      }else{
	        return "foo";
	      }
 
	}
}

The Scala version is still cleaner, but this Java version is a substantial improvement over the first version. As Andrew said in the biotext post, getting to know (or in my case remembering) the more advanced Java concurrency classes is a good thing.

Posted in Uncategorized.


Things that are easier in Scala vol 1

Last week I ran into a cose where needed to add some logic to retry certain operations a number of times before failing. These operations can throw a variety of exceptions, some of which are recoverable, some of which are not. Due to a variety of issues the code in question must be Java. At least for the time being. So I set out to do this. The solution I came up with wasn’t bad as Java solutions go…

Step 1: identify recoverable exceptions. Because I control the code that can throw the exceptions this isn’t so bad. I create a simple RecoverableException class.

package org.mccv;
 
/**
 * A marker class for recoverable exceptions
 */
public class RecoverableException extends Exception{
 
}

Step 2: create an interface that defines a retryable operation.

package org.mccv;
 
/**
 * An interface that defines an execute operation to retry
 */
public interface Retryable<T> {
	public T execute() throws Exception;
}

Step 3: implement a class that will retry a retryable n times before failing.

package org.mccv;
 
/**
 * The implementation of our retrying class
 */
public class Retryer<T> {
	/**
	 * The retryable we will call
	 */
	private Retryable<T> retryable;
 
	/**
	 * Just assign our retryable field 
	 */
	public Retryer(Retryable<T> retryable){
		this.retryable = retryable;
	}
 
	/**
	 * Try to execute our retryable n times 
	 */
	public T tryTimes(int times) throws Exception{
		// store the last thrown recoverable exception
		RecoverableException lastException = null;
		// try the specified number of times
		for(int i = 0; i < times; i++){
			System.out.println("running it with " + (times-i) + " tries remaining");
			try{
				return retryable.execute();
			}catch(RecoverableException re){
				lastException = re;
			}
		}
		throw lastException;
	}
}

Step 4: implement the retryable interface with the operation we want retried

package org.mccv;
 
/**
 * An implementation of the Retryable interface
 */
public class RetryableImpl implements Retryable<String>{
	/**
	 * Show usage of the retryer
	 */
	public static void main(String [] args){
		// create a new retrier
		Retryer<String> retrier = new Retryer<String>(new RetryableImpl());
		// run the retrier 
		try{
			System.out.println("result = " + retrier.tryTimes(3));
		}catch(Exception e){
			System.out.println("failed after 3 tries");
		}
	}
 
	/**
	 * An intentionally flaky operation
	 */
	public String execute() throws Exception{
	    if(Math.random() > 0.3){
	        throw new RecoverableException();
	      }else{
	        return "foo";
	      }
 
	}
}

This works, and you can use anonymous inner classes to wrap stuff that doesn’t directly extend retryable. But it’s ugly. You have to make a lot of things final you wouldn’t otherwise (for instance let’s say you want your retryable to set a status code and response message. This gets difficult due to having to mark things final). It’s also a bit clumsy in that you have a Retryer class in play, plus an implementation of Retryable. What I really wanted was a way to say

retry(myOperation,nTimes).

With Scala I got a lot closer.

package org.mccv
 
/**
 * A marker trait indicating an exception that is recoverable.
 * Note that we could make this a trait as well.
 */
class RecoverableException extends Exception
 
/**
 * Usage of our retryable class
 */
object Retryer {
	/**
	* The workhorse.  Runs the operation, and if successful returns the result.
	* If unsuccessful calls itself recursively with a decremented run number.
	*/
	def tryNTimes[T](func: () => T, runNumber: Int):T = {
	  println("running it with " + runNumber + " tries remaining")
	  try{
		  func()
	  } catch {
	    case e:RecoverableException if runNumber > 1 => tryNTimes(func,runNumber - 1)
	    case e => throw e
	  }
	}
}
 
object Main {
   def main(args: Array[String]):Unit = {
    val tries = 3;
    try{
    	println(Retryer.tryNTimes[String](flakyMethod,tries))
     }catch{
       case e => println("failed after " + tries + " tries")
     }
  }
 
  def flakyMethod():String = {
    if(Math.random > 0.3){
      throw new RecoverableException()
    }else{
      "foo"
    }
  }
}

This is almost exactly what I’d like. I define a simple object that has a tryNTimes method. Because it’s an object it’s sort of like a Java static method… I can call Retryer.tryNTimes() directly. This is a recursive call. If a RecoverableException is caught, it just calls tryNTimes with the number of tries decremented. The beauty of this is that you can pass in any zero argument function. It doesn’t matter what class it’s defined in… it just has to know about recoverable exceptions.

I’ll be keeping an eye out for things that are easier in scala and keeping this series up to date. I’m sure I’ll be running into more of them.

Posted in scala.


You can’t clone superstars

Something that comes up fairly frequently in my organization is the question of how to replicate success. When team A does really really well, there’s an urge to copy whatever magic it is they had. Unfortunately the approach usually devolves into how to copy the successful team, not copy the success of that team.

As an example, let’s say team A had a fantastic development lead. Somebody who could keep an eye out for development progress, overall quality, and what the customer really wanted. This development lead was granted fairly wide ranging influence over various parts of the project. They managed quality assurance, development, and were the final authority on what features made it into the project. And everything went great.

So now team B is spinning up. They have a good, but not fantastic development lead. However they do have a few quality assurance engineers who are rock stars, and a very good project manager. Should you grant the same authority to the development lead you did for team A? Of course not.

Replicating success is a matter of first getting good people. In big companies this can be fairly tough, as you usually have to play the hand you’re dealt. Teams often get paralyzed as they try to find the equivalent of the rock star development lead from team A. It’s critical to identify whether you can alter the members of the team (or to what extent you can swap out the members of the team) before planning the structure of that team.

After getting the people, the most critical factor is structuring the team so that team strengths are provided the freedom to succeed, and team weaknesses are appropriately supported. This is rarely accomplished by just applying the template from another team. The good leaders understand this, and are constantly looking for the factors that make a team successful. They then carefully consider the makeup of the next team, and put a structure in place to allow those specific team members to succeed.

Posted in organization.