Thursday, March 11, 2010

Pairing isn't the Solution

In 2007 & 2008 I wrote several blog entires on Pair Programming (tagged with pair programming). Pair programming solved a lot of problems for me: knowledge transfer, mentoring, code review, etc. It also solved another problem at the same time, even though I wasn't aware of it. Pairing helps reduce the number of cooks in the kitchen.

These days I'm working on a project with some really talented people. The pace at which we deliver features is far faster than any project I worked on before I joined DRW. However, I've seen two effects of having so many talented developers on the same team: wiki coding and spork sharing. (both metaphors coined by my tech lead, badams)

Wiki coding occurs when the churn on a class or component is so great that whoever commits last ends up deciding what it should do. Wiki coding leads to inconsistent design and lack of convention. Spork sharing occurs when a fork is designed and a spoon is also needed. Instead of creating a spoon, you want to share the handle, so you create a spork instead. Now, you have no spoon or fork, you have a spork, and sporks suck if you really want a spoon or a fork. Both problems seem to stem from differing vision for the classes or components.

It appears that the more talented programmers you put on a team, the more fractured the vision for the project becomes. Of course, complexity (as well as many other factors) can also increase the fracture.

You won't catch me advocating for 'hard-working average programmers'. What I do believe is: you should stock your team with only rockstars, between 2 and 4 of them. I've worked on teams that only had 3 people. I've worked on teams with about 16. I was a consultant, I've worked on a lot of teams - big and small. My experience was that the smaller teams were much more effective, every time.

Reflecting on the past few years, I came up with the following reasons for keeping your teams small:
  • New Technology: Small teams can more easily come to a decision to try a new technology. Also, if a small team selects a new technology, the entire team is likely to learn the new technology. However, an individual on a larger team may find a way to never learn the new technology and never contribute to that area of the code. Worse, a larger team may shy away from trying new technology because they cannot come to a consensus. New technology can offer productivity boosts, and missing those boosts can hurt a teams efficiency.
  • Smaller Problems: Smaller teams generally implies solving smaller problems. Most problems can be broken down into smaller, less complex problems. Once the problem is broken down, it should be easier for the small teams to craft elegant solutions that can integrate to solve the larger business need.
  • Improved Maintainability: Smaller teams generate less code, which allows all team members to have depth and breadth concerning a solution. Having depth and breadth allows you to easily share vision and fix broken windows.
  • Ownership: Ownership isn't bad. Single points of failure are bad, but having a small team that feels ownership over an application will generally lead to higher quality and more emotional attachment to it's success.
  • Context Switching: Smaller codebases maintained by small teams solving a smaller problem will context switch less, because there's nothing else to context switch to.
  • Responsibility: The Bystander Effect applies to code (e.g. production bugs) as well.
  • Unified Vision: In a large team it's easy to have an opposing vision and never be proven wrong. In a small team it's likely that you will agree on a vision for the project (process, technology, etc) as an entire team.
  • Adding: Adding one more person to a 2 person team will likely result in a new productive team member relatively quickly. Smaller team, smaller problem, smaller codebase = easier team to join.
Sometimes I wonder if consultancies sell large teams, and then use pairing to make the large teams more effective. It's definitely my experience that large teams pairing are much more effective than large teams that aren't pairing. However, I wonder if anyone ever stopped to ask: would a smaller team have been sufficient (or, better)?

I still believe pairing is an answer to many problems. However, the best solution to making a 8 person team more effective isn't pairing. I believe that a superior solution is finding a way to solve the problem with a smaller, more effective team (or teams).

Wednesday, February 24, 2010

Shorter Syntax for Creating Stubs with Mockito

As part of my efforts to create more concise Unit Tests in Java, Steve McLarnon and I recently added the ability to create a stub and stub one method with only one line.

The implementation relies entirely on Mockito, so my example assumes you were already using Mockito to create the stub.

The Mockito documentation has the following example for stubbing:
LinkedList mockedList = mock(LinkedList.class);
when(mockedList.get(0)).thenReturn("first");
Using the code Steve and I put together you can simplify this to the following single line.
LinkedList mockedList = create(aStub(LinkedList.class).returning("first").from().get(0));

The implementation is simple, but does rely on static state. There are ways to improve the implementation; however, this works for us. If you have more specific needs, feel free to change it to suit you.

The implementation follows:
public class MockitoExtensions {
public static T create(Object methodCall) {
when(methodCall).thenReturn(StubBuilder.current.returnValue);
return (T) StubBuilder.current.mockInstance;
}

public static StubBuilder aStub(Class klass) {
return new StubBuilder(mock(klass));
}

public static class StubBuilder {
public static StubBuilder current;
public final T mockInstance;
private Object returnValue;

public StubBuilder(T mockInstance) {
current = this;
this.mockInstance = mockInstance;
}

public T from() {
return mockInstance;
}

public StubBuilder returning(Object returnValue) {
this.returnValue = returnValue;
return this;
}
}
}

The Maintainability of Unit Tests

At speakerconf 2010 discussion repeatedly arose around the idea that unit tests hinder your ability to refactor and add new features. It's true that tests are invaluable when refactoring the internals of a class as long as the interface doesn't change. However, when the interface does change, updating the associated tests is often the vast majority of the effort. Additionally, if a refactoring changes the interaction between two or more classes, the vast majority of the time is spent fixing tests, for several classes.

In my experience, making the interface or interaction change often takes 15-20% of the time, while changing the associated tests take the other 80-85%. When the effort is split that drastically, people begin to ask questions.

Should I write Unit Tests? The answer at speakerconf was: Probably, but I'm interested in hearing other options.

Ayende proposed that scenario based testing was a better solution. His examples drove home the point that he was able to make large architectural refactorings without changing any tests. Unfortunately, his tests suffered from the same problems that Integration Test advocates have been dealing with for years: Long Running Tests (20 mins to run a suite!) and Poor Defect Localization (where did things go wrong?). However, despite these limitations, he's reporting success with this strategy.

In my opinion, Martin Fowler actually answered this question correctly in the original Refactoring book.
The key is to test the areas that you are most worried about going wrong. That way you get the most benefit for your testing effort.
It's a bit of a shame that sentence lives in Refactoring and not in every book written for developers beginning to test their applications. After years of trying to test everything, I stumbled upon that sentence while creating Refactoring: Ruby Edition. That one sentence changed my entire attitude on Unit Testing.

I still write Unit Tests, but I only focus on testing the parts that provide the most business value.

An example
you find yourself working on an insurance application for a company that stores it's policies by customer SSN. Your application is likely to have several validations for customer information.

The validation that ensures a SSN is 9 numeric digits is obviously very important.

The validation that the customer name is alpha-only is probably closer to the category of "nice to have". If the alpha-only name validation is broken or removed, the application will continue to function almost entirely normally. And, the most likely problem is a typo - probably not the end of the world.

It's usually easy enough to add validations, but you don't need to test every single validation. The value of each validation should be used to determine if a test is warranted.
How do I improve the maintainability of my tests? Make them more concise.

Once you've determined you should write a test, take the time to create a concise test that can be maintained. The longer the test, the more likely it is to be ignored or misunderstood by future readers.

There are several methods for creating more concise tests. My recent work is largely in Java, so my examples are Java related. I've previously written about my preferred method for creating objects in Java Unit Tests. You can also use frameworks that focus on simplicity, such as Mockito. But, the most important aspect of creating concise tests is taking a hard look at object modeling. Removing constructor and method arguments is often the easiest way to reduce the amount of noise within a test.

If you're not using Java, the advice is the same: Remove noise from your tests by improving object modeling and using frameworks that promote descriptive, concise syntax. Removing noise from tests always increases maintainability.

That's it? Yes. I find when I only test the important aspects of an application and I focus on removing noise from the tests that I do write, the maintainability issue is largely addressed. As a result the pendulum swings back towards a more even effort split between features & refactoring vs updating tests.

Tuesday, December 29, 2009

Presenting Lessons I've Learned

Up until a few years ago I'd never done any type of public speaking. I'm outspoken among friends, but generally shy around strangers. However, some opportunities presented themselves and I decided to take the leap into the world of presenting. I thought it might be helpful to document some lessons I've learned. If you decide to take the leap into presenting, I hope these ideas make your journey a bit easier than mine.
  • Get Help - I took a class at Speakeasy (NYC). The class that I took forced me to stand in front of a small group of strangers, present on any topic I liked, and have the entire thing recorded. I learned about things that I was doing wrong, but I also got to see what mistakes the other people in the class were making. It was the single largest thing that improved my public speaking.
  • Practice - the last public talk I gave was at QCon SF 2008. In the weeks leading up to that talk I rehearsed the presentation at least 25 times. There's so many reasons why a presentation can go wrong, so you'll want to make sure you have the content down cold. You'll lose the audience's trust if at any time you look as though you don't have the content down 100%.
  • Don't Script Jokes - at QCon London 2008, I was feeling nervous and chatting with Jim Webber. Jokingly, I said "maybe I'll open with: My name is Jay Fields, and yes, I'm American, but I guess you already knew that from my weight problem". Jim thought it was "brilliant". So I opened with the joke. But, it didn't come out smooth or well-timed, it came out dry and forced. No one laughed, and I got to start out my presentation with awkward silence. If you're naturally funny, it's fine to improv a joke in the middle of the presentation; otherwise, I suggest sticking to the content.
  • Know Your Audience - Audience's will react to your content in different ways based on several factors, it's important to consider these factors when putting together your content. For example, a local Rails User Group may laugh at your joke about DBAs. However, at QCon there are likely to be DBAs, CTOs, and other audience members who may not find your DBA humor amusing. It's also valuable to consider language barriers. In Europe, where my audiences often very mixed, jokes never seemed to amuse the audience in my talks or any that I attended. Maybe, the humor didn't translate well, or maybe I was moving too quickly. Either way, I made a mental note to stick to the content when my audience was likely to speak English as a second language.
  • Look Natural - At Speakeasy I learned that "arms at your sides" is how to look natural to the audience. It's extremely uncomfortable and feels unnatural to me, but I have the recorded video to show that I'm wrong. The problem is, if you are always waiving your arms around, or hiding them behind your back, you distract the audience. That's not to say you should never move your arms, but do it less often. I tend to point or gesture way too often, so whenever I notice that I am, I just naturally put my arms down and focus on doing that for a bit.
  • Face Forward - When you turn your back on the audience, you lose them. Especially if you are talking with your back to them. Instead, take small, backward steps and always face the entire audience.
  • Pictures - pictures are really the way to go. If you put text on the screen, people will read the text and tune you out. Some presenters are amazing enough that they get away with no slides at all. I don't suggest starting there. Technical conference-goers are used to slides. However, you can stick to pictures for your slides. If you have pictures that support your ideas, you can have slides while still forcing the audience to pay attention to you for content delivery.
  • Short Text - If you must use text, don't use sentences, paragraphs, definitions, or anything else lengthy. A few words, as little as possible is the only way to go. If the audience is reading, they aren't listening to you.
  • No Bullets - If you must you text, avoid bullets. Instead, show one line at a time and hide or shade the other lines.
  • Code Is Acceptable - Some ideas are more easily expressed with a snippet of code. Don't avoid code when code is the best choice. Instead, when you bring the code up, give the audience 30 seconds (or whatever is appropriate) to digest the code, and then begin to discuss it. Just remember, as long as the code is on the screen, there will be people reading, and not paying attention to you.
  • No Distractions - Distractions can ruin a presentation. Excessive transitions, morphing text, blinking text, etc all take away from the message that you are trying to express. I remember seeing a Flex presentation at RailsConf where the presenters showed their Flex Twitter Client. It was really pretty, and kept popping up tweets from conference attendees. Putting it up was awesome, leaving it up was the worst possible choice. I can't remember anything they said after they put up the application. I tuned them out for the remainder of the talk, and read all the tweets that kept popping up. I didn't mean to, but I was drawn to the shiny objects. After the talk I asked a few friends if the presentation was any good. They had no idea, we were all entranced by the twitter client.
  • Start Small, Build Up - My wife is the first to hear (suffer) though any presentation that I put together. I practice it a few times, then present it to her, then practice a few more times, then move on to a slightly larger venue. A User Group or some peers at work are good audiences for a new talk. After you present to 10-20 people, you should feel pretty confident about giving the same presentation to 100-200 people.
  • Be Original - If you use a template provided with Powerpoint or Keynote, it's likely that someone else at the conference will be using the same template.
  • Be Yourself - In my presentations I almost always swear and make some kind of sarcastic remark. That's how I act among friends and when I act like myself in presentations people tend to accept that what I'm saying is what I believe, not what I'm trying to pitch.
  • Record Coding - Don't live code unless you've practiced it 100 times, know how to deal with all possible problems, and are Justin Gehtland. Okay, I'm (sort-of) kidding about having to be Justin. However, the reality is that live coding is really, really hard. Often, you can express the same thing with a recorded coding session and there's little to no chance that things will go wrong. Justin has acting, teaching, and presentation training. He's also ridiculously smart. Those things combined mean he can carry a live coding session even when things go very wrong. If you have the same background, go for it. Otherwise, stick with the, much more likely to succeed, recorded coding session.
  • Questions - Pause for questions a few times during your presentation. It allows you to give color on ideas that you may not have clearly expressed. It also gives the audience the chance to see that you really know what you are talking about. For me, it also helps me relax and provide conversation, instead of simply lecturing.
  • Breathe - You know your content, the audience doesn't. Chances are you are going too fast. The simple rule of thumb is, the audience is always at least 5 seconds behind whatever you are saying. If you take the time to breathe or take a sip of water, you give them the opportunity to catch up.
  • Relax - The best presentation ratings I've ever gotten were when I gave a presentation entirely hungover. I thought I was going to be terrible. But, I was too hungover to be nervous, and I gave a straightforward, natural presentation on the ideas. I'm not advocating that you get drunk the night before your presentation, but do take steps to relax, if you know how. For me, I like to have friends in the audience, a drink about an hour before the presentation and a drink right after. It's my ritual and it helps ensure that I'm as relaxed as possible.
Almost everything I learned I got from Neal Ford, Jim Webber, and Dan North. Thanks for the ideas, gentlemen. If I left anything out, it would be cool to see additional lessons that you've learned throughout the years.

Update:
Steve Vinoski said...
I'd add the following:
  • Always repeat any questions asked of you before answering them. This is important not only for the audience in front of you, but also especially for any audience viewing a recorded session at a later time.
  • Don't be afraid to answer "I don't know" if someone asks you a question you don't know. The audience would rather hear honesty than some made-up BS. Presumably you possess specialized knowledge or wisdom, otherwise you wouldn't be up there speaking, but that doesn't mean you know everything, and frankly the audience doesn't expect you to.
  • Ask the audience questions. This helps keep them engaged. Remember, your talk is really more about them than it is about you, so gauging the audience and adjusting accordingly can help maximize the value of your message to them.
  • Should you encounter an audience member who wants to challenge you and argue with you, just politely decline to engage by saying you'll be happy to discuss the issue with them after the talk. Back-and-forth arguments with an audience member lose and annoy most of the rest of the audience almost immediately, and since you're probably not repeating every statement the arguer makes, anyone watching a recording of the argument hears only half of it and you lose them immediately.
  • Above all, respect your audience and they'll respect you. Except in extremely unusual circumstances, they want you to succeed because that way they'll get the most out of your talk. If you're a new or nervous speaker, keeping that in mind can help put you at ease.

Tuesday, November 03, 2009

Polyglot World

At QCon 2008 Steve Vinoski told me he uses at least 4 languages pretty much every day. At the time I thought 4 seemed like a lot of languages to use. Are we ready for a world where programmers need to know so many languages?

If you think about building a web application, you probably need to know a server-side language, HTML, Javascript, CSS, SQL, etc. Of course, there's no easy way to draw a line and say that those are, or are not all languages. I'm not sure the distinction matters, what does matter is having effective tools to get your job done. Maybe 4 languages isn't surprising.

I've worked on projects where C# and SQL were all we used; however, I think those days are coming to an end.

As an example, let's start with books. I'm currently reviewing Martin Fowler's upcoming DSL book. For his examples, Martin chose Java and C# where possible, and Ruby where a dynamic language was necessary. I think his language choices are pragmatic and wise. It's easy to agree and not give the idea another thought. However, his choice is a departure from his traditional usage of Java and C# exclusively.

Martin didn't add a new language because he changed his mind about dynamic languages, he added a new language because our industry changed it's mind about dynamic languages. Dynamic languages are now an acceptable choice for many projects, and an appropriate language addition for authors looking to appeal to the widest audience.

If Martin ever publishes another version of Refactoring, I expect it will have examples in several different languages. Refactoring: Ruby Edition contains several refactorings that are impossible to do in Java and C#. I have no idea what languages will be popular at the time of another Refactoring release; however, I think we will see a diverse set of languages and refactorings that target specific languages.

However, the polyglot movement can be found in the industry even more so than in books. Twitter is known to use both Ruby and Scala. Google uses C++, Java, Python, and Javascript. At DRW Trading we use any language that will help us get to market faster. Any given day, working solely on my project, I could be working with Java, C#, Clojure, Ruby or other even more interesting options. Steve's "4 language" statement doesn't surprise me at all these days.

You can also look at the multiple languages on the CLR and the JVM as further proof that as an industry we are willing to look to multiple languages to solve individual problems. The interoperability allows us to use the languages and paradigms we prefer for specific tasks, while working toward a greater solution. From personal experience, using Java and Clojure together has been a big productivity boost on several occasions.

As I already mentioned, in the web world you often need to master several languages to be effective. As a young developer, learning each language is probably a daunting task. However, I think having several targeted languages is part of the reason that web application development has been so successful. Targeted languages often give you the power and simplicity that allow you to get your job done without thinking about overly complex abstractions.

People often forget that "one language to rule them all" also implies that the language will attempt normalize everything. However, there are obviously efficiency gains to be had if you choose languages that play to the strengths of a paradigm or platform. The web proves this by having languages that target and solve specific problems. I wouldn't want to write CSS or Javascript in another language, even if it allowed me to solve all my problems with only 1 language. I prefer languages that increase my effectiveness to languages that reduce my learning requirements.

Ruby took a bold and productive step by introducing features that worked exclusively on Linux. As a result, several tasks are very simple to do on Linux and impossible on Windows.I applaud the choice. It makes my life easier when I'm on Linux, and I know I have to find another solution when I'm working on Windows. I'll take those options over some poor abstraction that feels painful on both platforms.

And, that's where I see our industry moving. Languages targeted at specific problems and run on specific platforms. The languages will be easier to create and use. There's been a movement in our industry towards simplicity for some time. This is just another logical step in that direction.

The days of one language for all problems and platforms are dwindling, which is nice. I prefer the polygot world.