Wrong Communication In Distributed Teams
One of the big challenges faced by distributed teams is how to get over the communication gap created by the physical distances that separates them. We all know that communication, either verbal or non-verbal, is fundamental for any project to be delivered successfully. When a team is good at communicating, they cultivate a more effective sense of collectivity and cooperation, having faster feedback, by sharing information (knowledge) and having valuable discussions.
But this is not quite the real world for distributed development teams. It’s much harder, not to say almost impossible, to know what exactly is happening on each other’s mind. What problems and technical challenges are they facing? What are they doing now? What points are they considering when designing a new feature? How important is for them to write tests? Are they following the project development standards?
Blame the "Bandwidth Limited" Communication Tools!
Software development teams, by the nature of their work, needs to discuss and assess different ideas to solve complex problems. And they are very difficult to communicate when using tools such as email or telephone, which on the book they call “bandwidth limited”. And those are exactly the ones available for most distributed teams. So face-to-face communication suits better for this kind of discussions, using the assistance of diagrams or sketches, not to mention the use of body language. This would give us immediate feedback, just by looking into the other person’s eyes, which communicate understanding.
* Extracted from The Organization and Architecture of Innovation: Managing the Flow of Technology (with some modifications).
And as you can't always minimize distances to allow verbal communication, you have to look for other ways, and maximizing non-verbal communications is definitely a road to go down.
Some Bad Outcomes
Poor Code Quality
- Code Duplication (see)
- Reinventing the wheel (see)
- Code For The Others (and for yourself)
- Broken Builds
It's quite usual. For example, the guy wants to load a XML file as a String so that he can perform some assertions over the result. He will implements something like a FileLoader class. But what he doesn't know is that another developer has already implemented a class with this behaviour.
This is partially caused by lack of communication and partially a result of the programmer's discipline. When adding a new library to the project the team must have a discussion and look for the benefits earned by using it. Before adding a XML parsing library that you're used to, have a quick chat with the team will let you know if is there any other parsing library being used. Maybe someone could make a walk-through with you on it. But it is your responsibility to know how to use it afterwards.
When coding, you should always ask yourself if your peers would be able to understand what are you producing. Better still, you should ask if you would easily understand it again in a couple of weeks from now. It's quite common when coding, you get contextualized with what you need to do to deliver that functionality. This context will always get lost after finishing, unless you share it with the others or document it. There are some good materials out there that shows you how to write clean and readable code.
In a distributed team, a broken build not only just affects the people in your room, it also affects people in rooms into other cities. So reverting a broken build should be taken into account, specially when you have a slow build, then definitely the commiter would get himself into a big problem! Imagine a long build that takes about 30 minutes for example, and someone commits something broken. If he fixes it really quickly, it still may take 1 hour for the other team to be able to commit its changes and consequently 1 hour and a half lost in productivity in the other cities. It's all about communication - the quicker the build, the quicker the feedback. So a fast and successful build is mandatory!
Fear of Refactoring
Poor code quality results in fear of refactoring. Who hasn't been in a situation, working on a tightly coupled system, where it was quite hard to do any refactoring? Any attempt would propagate the changes deep in the source code, ending up shaving the yak, not going anywhere.
Absence of Trust
I see this one as a result of the other two I mentioned above. When your team is biased to go off the tracks when trying to comply with code standards, some precautionary measures are generally created to avoid the worse.
I've seen a case where a pair, assigned to implement a story, and almost completing the development, ended up realising that another pair was also looking at it. Don't ask me why!
I've also seen people creating triggers on the version control system, so that for each commit from one team, the other received an email with all the commit information. This is good in one side, because you can easily identify cowboy commiters that don't write tests. But this is also used to check if the code is acceptable, reverting if not!
My Current Experience
The team I'm currently working with is facing some of these problems, and during all last week, when I was on the other side of the fence, visiting the other part of out team on Tasmania, this became even more highlighted. Although we were having daily stand-up meetings, I felt like I was missing something, specially because there was another team in Melbourne joining us and I still didn't know how it was going to work out. Chatting with my friend Mark Needham about it, he recommended me a book called The Organization and Architecture of Innovation: Managing the Flow of Technology, where there's a chapter dedicated exclusively to this point, and that I could probably get some ideas of how to overcome this problem.
Taking actions
It seems obvious that an organization that wants its technical staff members to communicate needs to ensure the distances among them are minimized. Unfortunately, the traditional and most common form of office configuration does just the opposite. Not to mention when they are in separated buildings.
The quote above also extracted from the book, doesn't tell anything new, and that's exactly one of the issues we wanted to fix. Now, with three teams we agreed that we would need to have them communicating face-to-face more often. So the rule is that every week we should have at least one person from each team visiting a different one. Apart from that, we are continuing with our daily stand-up meetings, each team separately, and later on another daily meeting, but between teams (in the Scrum world called Scrum of Scrums). This one involves, by default, only the iteration manager and the tech lead, but everyone else is also welcome to attend.
We also had to put more effort on improving the non-verbal communication, as they are more required on distributed teams. With this separation teams have to be even more strict with what they permit or not in the codebase. We introduced development tools such as Checkstyle and Compile With Walls to ensure this. Checkstyle acts as a hammer on misbehaved commiters and Compile With Walls ensures that project structure is being respected. Sometimes quite good threads (over IM or email) are created by people trying to understand why a Checkstyle rule has failed.
(Thanks to Tom Czarniecki for helping me with this one.)
Hamcrest Out Of Test Code!
It's been a while since I read some interesting posts showing creative uses of Hamcrest library out of test code. Since then I've been proscrastinating to implement my own version, trying strongly typed java delegates.
Thankfully this week I came across a nice API called hamcrest-collections. It uses Hamcrest to implement features such as select, reject, map, reduce and zip familiar from languages like Ruby and Python.
Selectors
Selectors can be used to select or reject items that matches a given Matcher, from any iterable object. It reminds me the Specification Pattern from Domain-Driven Design, which is also used for querying objects that satisfies defined specifications.
public static final Person john = new Person("John", 28);
public static final Person nicole = new Person("Nicole", 12);
public static final Person ryan = new Person("Ryan", 23);
public static final Person nathan = new Person("Nathan", 18);
public static final List list() {
return Arrays.asList(john, nicole, ryan, nathan);
}
The code below selects from the list of users defined above, the ones that are under twenty.
@Test
public void should_select_only_people_under_twenty_years_old() {
List users = Person.list();
Iterable underTwentyList = select(users, underAge(20));
assertThat(underTwentyList, hasItems(nicole, nathan));
assertThat(underTwentyList, not(hasItems(john, ryan)));
}
The code below rejects all the users that are under twenty.
@Test
public void should_reject_every_people_under_twenty_years_old() {
List users = Person.list();
Iterable aboveTwentyList = reject(users, underAge(20));
assertThat(aboveTwentyList, hasItems(john, ryan));
assertThat(aboveTwentyList, not(hasItems(nicole, nathan)));
}
Map and Reduce
Map is used to apply a function onto each item in any iterable object, whereas Reduce combines all these elements, applying a Reducer implementation. In our example, we map the timesTwo function, that doubles each element in the list, and then we reduce it by adding up all of them.
@Test
public void should_double_each_number_in_the_list_then_sum_all_of_them() {
List numbers = Arrays.asList(1, 2, 3);
MultiplyBy timesTwo = new MultiplyBy(2);
Iterable result = map(numbers, timesTwo);
assertThat(result, hasItems(2, 4, 6));
Integer sum = reduce(result, new Sum());
assertThat(sum, equalTo(12));
}
public class MultiplyBy implements Function{ private Integer factor; public MultiplyBy(Integer factor) { this.factor = factor; } public Integer apply(Integer number) { return (int)number * factor; } }
public class Sum implements Reducer{ public Integer apply(Integer first, Integer second) { return first + second; } }
Despite the bias created by some developers, that Hamcrest should not be used anywhere else but test code, specially after JUnit has defined it as its new matcher library, just ignore it and add these features to your runtime library, so that you can let your creativity drive you when developing. Get rid of "for" loops from your life!
First Sydney Coding Dojo
Last Wednesday, 5th of November, we run our first Coding Dojo session at Sydney office. We had a reasonable number of attendants, and the experience was fantastic, although we still have some points to improve.
The Initiative
The idea was originally from my friend and flat-mate Mark Needham. Since we moved in to our new place, he came up with the idea of getting together every week to solve some CodeKatas at home, exploring a different language. We decided it would be more interesting if we could broaden the idea, and decided to organise a session at the Community College in the ThoughtWorks office.
How did we run:
There were six people attending, so we decided to split it into three pairs, each with their own solution, rotating every ten minutes.
We had three design discussion breaks, one in the beginning, one in the middle and another at the end of the session. Since the focus was on object-oriented design, we chose to implement the bowling game, extracted from Uncle Bob Martin's book. We did it following the Object Calisthenics rules, which are:
- Use only one level of indentation per method
- Don't use the else keyword
- Wrap all primitives and strings (strong types)
- Use only one dot per line
- Don't abbreviate
- Keep all entities small
- Don't use any classes with more than two instance variables
- Use first-class collections
- Don't use any getters/setters/properties
What was cool:
Apart from being an amusing experience, it was quite interesting to see the different approaches that people take to solve the same problem, - the design, the way they write tests, the code style, pretty cool. The pair swapping was also another nice experience. It was gratifying to pair with ThoughtWorkers other than the ones on my current project, like David Cameron and Nick Carroll.
Future improvements:
For the next session, I would like to experiment with another approach.
Restrict the number participants from seven to ten developers. And instead of splitting them into as many pairs as possible, having all seated around a table, where there would be only one pair working on the solution, while the others are watching through a projector. They are free to help whenever they want, providing suggestions, ideas for design, algorithm, etc. The developers pairing would be swapped every ten minutes, by other ones participating. Although the number of developers participating is restricted, anyone is welcome to attend as a watcher.
I reckon we would be much more productive this way, when everyone is working on the same thing, centralizing the focus, and learning even more from other developers.
…From Musician to Software Developer…
Before start working as a software developer on 2002, I spent three years being a musician. I played drums in a handful of bands from pop to contemporary jazz, and of course, also a lot of rock and roll!
I had great time doing this, I met most of my friends during this period, and it taught me quite a few lessons that I can use in other areas than music, especially in software development.
Mastering music (drums), and software development require a lot of dedication, both on reading and practicing.
In music, the first thing I did when I decided to take it seriously was to look for a music school to learn how to read and interpret music. Then I read most of the books related to drum techniques and rhythms, attended workshops, spent nights and weekends practicing to improve my ability and velocity. Practicing is very important! It’s when you give yourself the chance to commit mistakes and to let all the ugliness to happen; after all, no one is watching you. The intention is not to sound good, but to stretch your limits, so that you can perform perfectly on the stage.
In software development, it’s pretty much the same, you have to read a lot (books, blogs, articles, magazines), learn programming languages (choose two or three to specialise, and get a higher overview of others), attend workshops, meet people, practice by trying and evaluating different technologies, creating a blog to post your experiences, joining open-source projects, registering for coding competitions, solving some of the CodeKata challenges, preferably pairing with someone else, in summary, stretch your limits!!!! (Have you seen this before? ☺) Doing so will give you more self-confidence for you to perform well during your show, at client site.
[WTF] Eureka!
If you think you know how to work out the age of a person, based on his date of birth, it'd be better to review your concepts about implementing this functionality. Enjoy the code!!
public UserImpl( UserTO user, String status ) {
_user = user;
_status = status;
_age = 0;
Calendar today = Calendar.getInstance();
Calendar birthdate = Calendar.getInstance();
birthdate.setTimeInMillis( getBirthdate().getTime() );
birthdate.roll( Calendar.YEAR, 1 );
while ( today.after( birthdate ) ) {
birthdate.roll( Calendar.YEAR, 1 );
_age++;
}
}