CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

Pair Programming

  • Week 2: Scheduling and Coordinating the Work

    Continuing the "Getting Started" series.  My team just finished our second week.  Luckily enough we were able to get through release planning quickly and start Iteration #1 on Tuesday.  CruiseControl.Net is up and running.  I kept a list of the topics that came up this past week that I might want to talk about in the blog, and a single theme pops out:  how to schedule and divide the work.

    First, some little things:

    • Check in code often.  Constant check-in's should keep the overhead of merging to a minimum.  Continuous Integration is an attitude, not just a tool.
    • Work in small steps.  That means write a unit test's worth of code at a time.  The TDD red bar should be a short phase and there really shouldn't be many times when the code can't compile for more than a few minutes.  Working in big chunks without verification is what brings out the inefficient, marathon debugger sessions.
    • If you're helping a team learn TDD from scratch, don't let them start early with dynamic mocks.  Let them get a handle on TDD with work that leads to state based testing first.
    • When you're doing TDD, try to break the work into small tasks.  From that task breakdown, think about how each task or step could be tested.  Your low-level design pretty well follows from testing one task at a time and building up to the whole.  Code from the bottom up!
    • Build business functionality first, and let the infrastructure come second to enable the business functionality.  I tried to avoid this, but it happened anyway.  We got a bit caught up in UI infrastructure and didn't get much functionality built.  The danger of focusing on infrastructure solely upfront is the risk of getting tied down in purely speculative coding that doesn't deliver any value in the end.
    • Check in comments!!!

     

    Iteration #1 Work

    I think the real goal of iteration #1 is to create knowledge more so than code.  You will never produce as much functionality in iteration #1 as you should in later iterations.  The first iteration almost has to be concerned with creating a common vision of how you're going to build the software, especially if the team hasn't worked together before.  You could lay your ears back and code away at full speed, but you'll pay for it later with either technical debt or longish design sessions with the rest of the team explaining (and arguing about after the fact) the technical approach.  I sincerely believe that people understand design strategies far better when they have been present for the formulation of that design strategy.

    I say this mostly to try to alleviate the stress from first iterations when the code isn't flying off your fingers into the IDE.  When you're loading up the first iteration you really shouldn't count on doing as much "work" as you will later on.  I think this is in line with Eric Evan's idea of Knowledge Crunching.

    Splitting the Work

    I've seen two real issues this past week:

    • The beginning of the project is much rougher for merge conflicts than it will be later on in a bigger code base.  Strive to find stories that can keep the multiple pairs out of each other's way.  Even so, it still takes a lot of communication around work on shared or foundational classes.  A simple "hey, we're about to rename this class.  Is that okay with you?" goes a long, long way to alleviating the worst of the merging issues.
    • Rotating people through different areas of the work.  Like I said in the previous section, I'm more concerned about creating the shared understanding upfront than cranking out code right now (on the theory that this shared understanding will pay off immediately in the following iterations).  We're just trying to be cognizant about rotating people through different kinds of story work.  It's a bit incumbent upon each developer to speak up when they think they're getting siloed.

    Serialize the Work

    For best results, you should focus your efforts on completely finishing active stories before starting any coding work on new stories.  You should only start coding work on a new user story if you're completely blocked or out of work on the previous stories.  First you really do have to internalize the idea that the development team as a whole can only take credit for production ready code.  Once you do that, which outcome at the end of an iteration below is better?

    1. 5 out of 10 user stories scheduled for the iteration are production ready.  3 of the others have not been started. 
    2. All 10 stories for the iteration are in some sort of intermediate state. 

    Even though both outcomes may reflect the same amount of effort by the developers, only outcome #1 provides any real business value.

    You also need to get something in the hands of the testers or reviewers by at least mid-iteration if you're going to make your iteration.  Besides, the human mind just doesn't handle context switching all that well.

    Ordering Stories

    XP dogma states that you order the user stories in terms of business value.  In practice I've never found that to be enough.  There's always constraints of some sort that have to be accounted for in your schedule:

    • What stories are understood well enough to work on?  You're going to need to look ahead a bit to make sure you always have enough stories ready to go at the start of each iteration.
    • Does one story depend on some infrastructure that's built in a different story?
    • What stories can be worked in parallel?  If having two or more stories involve the same area of code, you may want to serialize these stories to prevent some nasty merges.
    • Eliminating risk.  This might be technical risk of some sort, but it could also be business risk.  Our project is user interface-intensive.  One of our best ways to reduce risk is to get the user interface in front of the client as soon as possible to make sure the UI is acceptable and meets the business needs.
    • External constraints.  You're almost always dependent upon external groups or even external companies.  You simply cannot do work that depends on a different team without coordinating with them first.  We're going to try to get some representation from the server side team in our iteration planning meetings to deal with this coordination.

    Breaking up Stories

    Don't hesitate to break stories into small units.  For example, there isn't any rule that says you have a one to one relationship between a screen (especially a complicated screen) and a user story.  As long as a user story provides some amount of business value and can be tested by itself, it's fine.  Smaller stories are easier to estimate and drive to completion.  Dividing the work into smaller chunks helps to get working code in front of the users and testers earlier in the iteration to make their jobs easier.

    What I don't feel good about are stories like "Capture the information in the screen" paired with "Persist the information to the database."  Capturing the information in the screen is just a task.  It doesn't really provide any value until it really works from end to end.  Dividing the work into "Capture header information" and "Capture details" and maybe even "Validate the user inputs" into separate stories is much more acceptable to me.

    Can You Have Technical Stories?

    I say preferably not, but it's not the end of the world.  As long as the stories are very focused into a specific technical task to enable the following business stories, I'm fine with technical user stories.  I've often found it easier to pull out a shared technical dependency of multiple stories into a technical story for easier tracking.  What's definitely bad are stories like:  "Create the Data Access Layer" or "Create the Model View Controller Framework."  Those stories are black holes.

  • Important Tips for Pairing Etiquette

    1.)  If your a backseater, wait until the driver gets off the line of code to yell at him for a typo

    2.)  When you're pairing, change your IM status to "Pairing with Bob" so your wife doesn't IM you with embarassing terms of endearment. 

    3.)  If you want me to pair with you, I really, really want you to have ReSharper & TestDriven.Net.  VS2005 is basically naked without. 

    Luke Melia adds some more points here. 

     

  • So How do You Introduce TDD into an Organization or Team?

    There's an interesting thread going on in the Yahoo TDD group started by Jay Flowers about introducing TDD to a large organization, and an interesting spawned thread about TDD without OO.  I made a tangential post last week that's referenced - How much design before unit testing, and how much design knowledge before TDD?

    I'm not necessarily the best person to ask about this because my experiences haven't been typical.  More than anything else, the critical factor is an organization or team of developers that is open and willing to doing TDD.  Management support would be nice, but in the end it's the developers who are going to make it succeed or fail.  I had it relatively easy because my introduction to TDD came as a consultant with ThoughtWorks, one of the leaders of all things Agile.  A key factor for me joining my present employer was their desire to adopt Agile processes.  The support for TDD was there from day one, at least from development management.  Add in a group of developers who all believe in TDD, or at least willing to give it a try, and you can achieve a pretty smooth adoption rate.   

    Coming in and laying down the law, "You will do TDD starting now!" probably isn't going to fly.  Actually, I'll say it more strongly -- TDD won't take without some kind of consensus from the developers.

    You might not have it that easy, but then again, the wealth of free information and TDD lore that's available on the web and blogosphere dwarfs the information that was available way back in 2003 when I was writing hopelessly tangled tests.

    A team bootstrapping itself will probably struggle at first.  For best results, you're going to have to get some coaching to the TDD newbies.  Most people, myself included, struggle at first with TDD when you start encountering nontrivial enterprise development tasks like persistence and integration.  Brown bag sessions (especially if the team takes turns presenting) and training will help, but for my money, you want a sprinkling of people who can coach TDD and get them paired up with the folks who are new to TDD.  If you don't have anybody who can coach, it might be worth the cost of bringing in an external TDD coach to work hand in hand with the team members.  Regardless of the experience level that your team has, I'd very strongly consider adopting pair programming as a way to disseminate knowledge.  One of the advantages of pairing is the propagation of tricks -- IDE shortcuts, ReSharper features, and TDD idioms for testing code.  For example, I learned how to use NMock for unit testing with external dependencies by pairing with someone who was familiar with NMock.  As a direct result, I immediately got faster.  Even part time pairing will help. 

    Going in to TDD, you're going to want an open-minded attitude about the way you code.  In other words, start with an assumption that you will have to change the way you code and design software.  I certainly wouldn't say that TDD is the silver bullet for perfect software designs, it's more like a white glove test that finds all of the tightly coupled dirt and gunk in your design.

    Learn Unit Testing First, or Go Straight to TDD

    Jay Flowers talks about two camps in his organization, one camp who wants to concentrate on doing unit testing first before moving to TDD while a second group wants to go directly to TDD.  My vote is actually on going straight to TDD.  Most of the challenge in writing automated unit tests is writing code that can be tested.  Putting an emphasis on writing the unit tests first keeps testability (and hence a strong focus on loose coupling) in the forefront of a developer's mind.  Retrofitting unit tests to existing code is hard, period. 

    OOP as a prerequisite for TDD

    On the Yahoo thread I linked to, several folks are challenging my opinion that TDD requires OOP by sharing positive experiences of doing TDD and Continuous Integration with VB6.  I'll take their word for it, but doing TDD with VB6 reminds me of seeing an elephant fly in Dumbo.  You can write almost-OO code with VB6 (minus true inheritance), but as I recall you fight against the language quite a bit.  VB6 wants to be procedural.

    Let's pretend functional programming doesn't exist (because I don't know enough about it anyway) and that SOA is largely an orthogonal concept to OOP.  I'm on record as saying that a solid understanding of Object Oriented Programming is essential for succeeding with TDD on nontrivial applications.  I wouldn't hesitate to recommend TDD to someone who is new to OOP, but sooner or later that same newbie will be held back if they're not a strong OOP developer.  To defend that assertion, let's go back to some first causes:

    1. I want to be able to quickly write small unit tests that can be coded in rapid order to maintain flow
    2. External dependencies can make unit testing much more difficult and/or laborious, not to mention slower

    The two primary ways to create testable code is to be religious in assigning responsibilities to different parts of your code and isolating external dependencies behind swappable interfaces.  In both cases I think OOP has a far better story than purely procedural programming.  OOP allows you to use techniques like Dependency Injection and Mock objects to replace external dependencies with fake objects that behave in a known way.  Using best OO practices leads to code that is cohesive and loose coupling, exactly the kind of code that is easier to unit test.  What can you do with procedural programming?  Function pointers?  You're certainly not going to be able to do the same kind of interaction testing we use with OOP, and that's an awfully important tool to leave behind. 

    The real enabler of TDD is writing code that exposes seams to unit test in small chunks.  As long as you can accomplish that goal, you're going to be fine.  I just think that coding in an OO style gives you many more tools to create testable code.  If you can stay perfectly in the realm of state based testing and keep your functions small and relatively independent, I can see you being able to use TDD with procedural code.

    Just for background, here's an older post on State vs. Interaction Testing.  You'll want to be able to do either, and know when each is most applicable.

     

    P.S. I think doing TDD is actually a great way to learn OOP.  You get immediate feedback on your OO structure.

  • Lots of Provocative Thoughts from Sam Gentile

    Our CodeBetter-mate Sam Gentile gave a truly great talk this evening at our ADNUG meeting.  He covered a remarkable variety of topics related to Extreme Programming practices and tooling for .Net.  I had to leave early to take a sick child off my wife's hands, but even so I jotted down about a dozen things I wanted to blog about.

    Sam stated that most of his unit test cycles last no more than ten minutes from starting to write the unit test to the unit test passing.  If your unit tests are regularly taking longer than 10 minutes, you probably need to rethink your approach and look for a different way.  Long unit testing cycles and/or needing the debugger quite a bit are an indication that your code may not be cohesive or loosely coupled.  Being able to get in a rhythm where you write fine grained unit tests in tight cycles is a good sign that your code/design is on the right track.  I've started work on "Jeremy's Third Law of TDD:  Test small before testing big" that'll expound on this topic, but for now my emphatic advice is to strive for fine grained unit tests.  Both to make writing working tests easier and to enforce good coupling and cohesion.

    Sam talked a bit about his struggle to reconcile the idea of being an architect with XP and creating an architecture with Continuous Design.  While I think that book is still being written, I emphatically agree with Sam that architects should code.  I certainly feel that my ability to positively impact a project is much greater when I'm coding.  Code is important.  Even if you don't accept the XP "Code is Design" idea, we could still agree that the quality of a "design" is definitely reflected by the ease of the coding.  Good code, i.e. maintainable code that is cost effective over time, takes skill.  Bad code results in support costs and opportunity costs because of the difficulty in extending the code.  I think it's nearly insane to say that anybody is "too important to code" as one of my managers used to berate me when I was an architect.  Invariably, much of the worst overengineered code I've had to deal with originated from an architect who never had to dogfood his design (the rest came from me in my Architect Hubris stage).

    The simplest thing that could possibly work isn't a license to hack.  Someone asked a question about whether XP was more focused on business value maybe to the exclusion of technical quality (sorry if I misinterpreted the question).  The focus on delivering business value is probably the correct end, but good code/design/software backed with good build and test automation is a great means to the business value end.  I buy into the whole "doing a good job is its own reward" thing a little bit because I think the "Software Craftsman" ideal is attractive.  It's certainly more romantic than being a CMM compliant, plug compatible software engineer anyway.

    There was some talk about an overdependence on Intellisense being a barrier to TDD adoption with some reference to Rocky Lhotka's TDD comments last week.  I certainly don't like coding without Intellisense, but it's not a compelling reason to forgo TDD.  If you'll let me get away with the term, the "Reverse Intellisense" ability of ReSharper and other refactoring tools to automatically create method stubs for missing methods offsets the lack of Intellisense for new code that's being specified in a unit test.  Add in RhinoMocks to mock a brand new interface with strong typing and you have quite a bit of ability to model the interaction between classes in a unit test, then use ReSharper to generate the missing methods that are defined in the unit test.  It may not sound like a big deal or even useful, but I've found it really makes TDD easier.  I like to think of this sort of TDD design doing a UML sequence diagram in code.  Behavior Driven Development is taking this idea much, much further (but it looks like it almost requires a dynamic language like Ruby or Python).

    Refactoring is a grossly abused term.  Refactoring is improving the structure of existing code while maintaining the same functionality, hopefully in a disciplined manner backed up by automated tests.  You use refactoring to remove little code smells as you go and bigger refactorings to remove duplication and enable new changes.  Telling management that you're just doing some refactoring to cover the fact that you're really doing an architectural rewrite is just plain lying.  Shame on all of us who've ever played a shell game with "refactoring."  One more thing, the phrase, "do it quick now and you can just refactor it later" makes my blood boil.

    When the topic of Pair Programming came up, someone asked if pairing can reduce the amount of time it takes to bring new team members up to speed on a project.  Pairing doesn't negate Brook's Law by any means, but my experience in this regard has been very positive, More so when either the existing or new team members are experienced with pair programming.  Pairing is actually a bit of a skill that some of us (me) have to work on more than others. 

    All in all, it was a great session.  Thanks for coming Sam and playing through pain.

  • I thought you said NOT to cross the streams!

    We had a little snafu at work today from a lack of communication.  It didn't end up costing us any significant amount of time, but it could have.  We had two pairs (all the developers in the office) working on different tasks in essentially the same area of the code base.   My pair was adding functionality to a new class.  The other pair decided that the role of the same class should be different and moved it to a completely different project.  We got out of it pretty quickly by splitting the class into two, but that would have been a nasty merge if we hadn't caught it quickly.  Just like in Ghostbusters, crossing the streams of coding activity is a way to get a priority user story done fast, but it comes with some risk. 

    We knew they were working in code very close to us and we should have told them we were working with that class, and they most definitely should have said something to us before they moved the class to the other project.  My resolution for tomorrow morning is to make sure we all know what the separate pairs are doing until we can get the coding streams isolated from each other.

    I think the danger of pairs stepping all over each other goes down quite a bit as a code base matures.  Early on in a project the roles of classes and the project structure can vary wildly.  I certainly try to keep parallel coding streams separated as much as possible early in a project.  Of course you often don't have much of a choice, so you've just got to be talking much more often and when in doubt, broadcast any breaking changes to the rest of the room.  My preferred coding style is definitely heads down, but in the early stages of a project you just can't afford that attitude.  I think it's awfully important to get the team in front of a whiteboard several times a day until the technical direction emerges and stabilizes.

    Here's another lesson that we relearned today, but in a positive way.  Take Continuous Integration to heart.  It's more than just configuring CruiseControl.Net, it's an attitude.  We got away with working in the same area of the code today precisely because we were checking new code in at least every hour.  We were able to reign in the areas where we were diverging rapidly because we were getting constant feedback on our code from the automated builds.  Try to break the work into smaller chunks so you can check in code frequently.  Frequent, granular check-in's and updates keep the burden of merging to a minimum.  Collective code ownership means paying attention to what the other developers are doing too.  Put another way, big check-in's usually hurt -- and big check-in's at 4:45 in the afternoon are hazardous to your health.  Another reason to keep your automated build as lean and fast as possible is to enable frequent check-in's.

    Stale code gets moldy fast.  One of the worst mini-blunders in my career was not intervening or rotating someone else into a pair that was struggling with a complex WinForms navigation task.  They kept the code out for four days while the main codeline was changing rapidly around them.  When the rest of us finally did get involved we compounded the mistake by not throwing the code away and starting over.  It took two more days to get the code changes merged in, and another day to refactor that code to where we wanted to go in the first place.  All that effort for a story that had been originally estimated at only a half-day to begin with.

    Agile processes make a very conscious decision to maximize the communication between team members as a means of eliminating much of the paperwork typical of formal processes.  For this very reason, Agile teams typically work in open team rooms.  I just can't imagine going back to all of us working in isolated cubicles.  I know Joel Spolsky thinks developers do best when they're working in quiet isolated offices, but I think that's a matter of localized optimization.  This is a reminder to self -- It might optimize the individual coding productivity over the short term, but it'll probably hurt in the long run with nasty integration problems and an alarming degree of code duplication.

  • Classic Technical Lead Blunder

    A couple days ago I saw a post (EDIT:  the post was removed) relating a depressing situation that sounded sadly familiar to me and I have to respond.  The author relates a story of getting to the end of a time-constrained project and realizing that the other developer’s code is bad.  I can easily relate to the author’s plight because I’ve been in the exact situation at least twice.  My diagnosis for both the author's current project and my past experiences is simple.  The technical lead (me) failed to lead the technical effort.

     

    My problem was that my first official developer job was in a completely dysfunctional organization.  That’s actually a mixed blessing in a way.  You can get more opportunities because it’s easy to stand out, but it stinks in the long run because you don’t get to learn the right way to do things very often.  I was by far and away the most productive coder and the guy with the design vision, but I didn’t know squat about leading or coaching other developers (plenty of people will say I still don’t).  I was forced (ok, I basically seized the role when nobody else was looking) into a technical lead role on my very first significant project.  I’d never had any role model for being a technical lead, much less a good role model.  I made the typical blunder that many first-time technical leads do.  I put the headphones on and hunkered down with what I thought were the most difficult pieces of code and did them.  I gave the other developers what I thought were easier tasks and generally ignored them as much as I could. 

     

    I answered questions here and there, but I wasn’t that involved with their coding.  When I finally got around to looking at their code I often didn’t like what I saw.  I rewrote several pieces of their code behind their backs at the last moment.  I essentially wasted the efforts of the other developers.  Two of the developers was truly incompetent but the other two were bright folks that had even less experience than me.  One of the developers was so bad that I started calling him the “Canary” when the “Reduction in Force” rumors started when the tech industry crashed in 2001.  The project was very successful, but could have been much less stressful if I’d invested much more time into the other developers.  They probably would have gotten a lot more out of the project, too.  One of the reasons I think that shop was and is so bad is the complete lack of coaching for technical folks.

     

    Losing Strategies

    • Drive by shootings -- I mean code reviews.  I’m sure code reviews are useful somewhere, but I’ve never been in one that wasn’t either a complete waste of time or a source of resentment.  Relying on code reviews to catch bad code after the code is written is inefficient and just plain stupid.  Code reviews can easily turn into a case of the prosecution versus the defense.
    • Poor or infrequent communication between the technical team members.  On a couple of occasions some of the developers on my team were on the other side of a cubicle farm.  Co-locating a technical is a no-brainer.  I wonder how much inefficiency exists in large IT organizations where they don’t co-locate development teams.  Technical documentation like design specs are a poor form of documentation.  The only good thing about technical specs is that they’re more durable than a conversation.  Tossing specs over the wall to a development team and walking away doesn’t work.
    • Detailed work assignments.  My experience has been that feeling is that the more detailed work assignment you give another developer; the crappier code comes back to you because they will mechanically implement your design without thinking.  I’ve got a case of this on the system I inherited when our very bright boss gave some specific design advice to the team building the system that this team followed without question.  The advice wasn’t necessarily bad, but there were definitely simpler alternatives to what was built. 
    • I design, you just code.  Even before I had ever heard of XP I always believed that coding, design, and architecture are too interdependent to be done by separate people.  Developers can internalize a design strategy better if they contributed to making the design strategy.  Over and over again I’ve found that it just doesn’t work to give someone a detailed design without a lot of verbal and whiteboard communication.  I think there’s also an issue of developer pride and ownership.  I think coders do a better job when they feel some sort of ownership stake in what they’re coding.
    • Ignoring the other developers to concentrate on my work.  I have to constantly remind myself to focus on the team’s velocity as opposed to my velocity.  I still think that I’m most effective early in the morning when I’m heads down into code with zero interruptions, but that doesn’t help the other developers.  It’s not just a matter of trusting the other developers – but that is often an issue.  It’s also about talking over the design, looking for duplication, and creating a shared vision.

     

    Winning Strategies

    • Involve every developer in the design work.  Over and over again I’ve found that developers have a better working understanding of a system’s design when they’ve been involved with creating the design.  Many agile practitioners are hostile to design sessions because of a fear of speculative design or an assumption that it’s jus wasting time (but the agile community is also mellowing in recent years).  I think design sessions in front of a whiteboard with the team is a create way to get the team on the same page.  Most agile projects involve a “tasking” activity to break down user stories so they can be estimated in iteration planning.  The “tasking” meeting is essentially a design meeting.
    • Pair programming has been very effective in my experience for communicating design knowledge throughout a team.  It’s also a great mechanism to coach other developers.  Pairing can be used as an ongoing code review to eliminate problems more rapidly without the nastiness of a formal code review.  Bad coding practices can be caught very quickly.  On a project last year most of the other developers were Java and GUI guys that hadn’t worked with database or persistence code very much.  Because we were pairing I noticed that they weren’t attending to connection hygiene very well.  I caught the issue very early and explained why it was important to manage database connectivity.  Waiting for a formal code review a couple months into the project to read other people’s code would have allowed that problem to fester.
    • Collective code ownership.  Nobody works in a silo.  Every developer, at least in a small team, should have some visibility into the entire codebase.  Determining and enforcing best practices can be a lot easier when people are rotated through the code.
    • Think out loud.  This is purely an exhortation to me because I never do this well enough.  If you’re one of the primary people doing design on project, talk about your design thoughts all the time.  Involve your teammates as much as possible.
    • Coach the other developers.  If you’re the senior most developer your most important contribution may be the coaching you give other developers, not necessarily the code you write.  Helping other developers is an investment in your team and organization.  Besides, they undoubtedly have something to teach you too. 
    • Co-location of the developers and the rest of the team.

     

     

    You could easily argue that the ability to communicate ideas to other developers is one of the most valuable skills a lead could possibly have.  I don’t think anybody can be a technical lead without good technical skills, but not every strong developer is fit to be a lead.  Heck, I’m the veritable poster child for this.

     

    Of course, you’re always going to have trouble if the ratio of “needs coaching” to “able to coach” gets too high.  The idea that all you need is one smart guy on a project to tell everyone else what to do is a nonstarter in my book.  No process or goofy accreditation effort, be it wild-eyed XP, UML out the wazoo, Six Sigma Ninjas, or CMMI Level Umpteen, is ever going to change the fact that producing good software requires good people.  Some people want to be the bright shining star of an organization, and the easiest way to do that is work with bad people.  I’ve gotten to work on a couple of very strong teams at both my current and previous employer.  That’s been vastly more fulfilling and less stressful than being “the” guy on a weak team. 

  • Pair Programming Ergonomics

    One of the first things you need to do if you’re going to do pair programming is to get a good physical workspace.  I don’t know about you, but I’m not very effective if I have a crick in my neck or I can’t even see the code my pair partner is typing.  I know the original XP guys say to use a single keyboard and mouse, but my experience has been much better with a second monitor, keyboard, and mouse plugged into the shared workstation.  At any time both members of the pair can see the code and either can quickly take over the “driving.”  Do observe a little bit of etiquette with each other to avoid wrestling over who’s typing and moving the mouse at any time.

     

    To pull it off, you really want a place where both of you can sit shoulder to shoulder without being cramped.  In my current office space in Austin I have a pretty nice desk with drawers on either side, but it’s terrible for pairing (we have to trade seats to switch the guy at the keyboard and that sucks).  When we move to a new (larger) space, I’m insisting on getting plain tables instead of desks.  Take advantage of the new world of notebook computers and wireless connectivity to just pick up and go somewhere else to find a better physical setup.  Always let the rest of the team know where you’re going and keep an instant messenger tool up if you do go off into the cafeteria though.

     

    I would also say to have a whiteboard or notepad of some kind nearby so you can sketch things out together.  Noted methodologist Alistair Cockburn has famously described two people talking at a whiteboard to be the most efficient means of communicating ideas.  On a project last year we had 3 or 4 whiteboards on rollers that could be moved anywhere.  I promise you that we got far more bang for the buck from the couple hundred dollars we spent on the whiteboards than a typical team will get from a series of Rational Rose licenses.

  • More on Pairing

    Kicking Off a Task or Story

     

    Some people can just sit down at a keyboard and start generating unit tests.  I can’t do this myself.  Personally, I’m much more effective if I spend just a little bit of time sketching out an approach in crude UML or merely writing out a list of the changes to make in the code (new method here, new class there, etc.).  One very effective tactic I like is to do in a pairing session is to start at a whiteboard and task out the work together and make a list of the coding work.  It’s a simple and quick way to get a shared understanding of the work.  You’ll undoubtedly throw away some of the list and go a different way, but it’s the act of making the list together that’s important, not the list itself.

     

    The Backseater Must Be Engaged

     

    The person not driving has to remain actively engaged in the coding.  When you’re not the driver, you’re Goose from Top Gun watching the driver’s “Six”.  The backseater should be thinking ahead and looking for potential problems with the current approach.  According to the old folks like Steve McConnell and Robert Glass, code inspections (reviews) are one of the most valuable tools for removing defects from the code.  The backseater should be performing a code inspection in real-time. 

     

    I think it’s okay to have the backseater doing some sort of research for the next piece of work sometimes, but otherwise the backseater is focused on the coding at hand.

     

    When you’re the backseater, don’t be an ass.  Slow down on the whole “you forgot a semicolon” commentary at least until the driver has moved on to the next line of code.  Nitpicking is a great way to be a bad backseater.

     

    Switch roles often to keep both people involved in the story.  No decent developer likes to just watch someone else coding.  There was a somewhat sad incident in a stand up meeting last year when my pair from the day before listed his activity from the day before as “watching Jeremy code.”  That’s being a bad pair on both our parts.

     

    Smooth out the Worst Tendencies of any Sole Developer

     

    By having input from two coders into any coding activity, you have a sanity check that can help rein in the worst tendencies of any one developer.  As for myself, I’m filled to the brim with design pattern theory and it leads to some temptation to go off and be an Architect Astronaut.  Coding in a pair with somebody who does not share this affliction helps to keep me grounded and write code that makes sense to the rest of the team. 

     

    On the other hand, if your partner suggests implementing a task in a 1400 line stored procedure you can remind them that T-SQL is not a very good solution because it’s hard to test, debug, and read in this context than C#/VB.NET/Java (and Jeremy has implicitly threatened bodily harm to anyone who puts business logic in a stored procedure ever again).

  • Pairing is a Great Way to Learn and Teach

    Let’s be pretty clear about this.  You’re doing pairing primarily to gain in throughput, not as a training tool.  That being said, pairing can be a very effective way to transfer knowledge and mentor junior coders. 

     

    Something to keep in mind as you pair is to look at the bigger picture of the project.  Sometimes pairing with a much junior developer will make the immediate task take longer than it would if you were flying solo, but that’s not completely the point.  You (I) must be patient.  If you can use the pairing experience to improve the effectiveness of your colleagues the team as a whole will come out ahead in the end in terms of team velocity.  To employ a sports metaphor in basketball, the very best players are considered to be the ones who can make their teammates better.  I was thrown into leadership positions very early in my career when I was still struggling with improving my own personal velocity, so I never really grasped the value of improving team velocity until much later.  One of the very real advantages of agile development is the concept of collective ownership and putting the focus on a team completing working software instead of checking off your own personal deliverables.  I think it’s a subtle shift, but it’s really changed my outlook on software development.  Someday I'll even internalize that kind of thinking.

     

    One simple benefit of pairing for me has been picking up IDE tricks and learning new tools from other developers.  Don’t underestimate how much faster you can be with a good toolbox of keyboard shortcuts.  Last summer my team was a very early adopter of the original ReSharper beta (I’m gonna wait a few more builds before I try the ReSharper 2.0 beta this time though).  We had several guys that had quite a bit of experience with the IntelliJ IDE for Java.  These guys suddenly became much quicker mechanically than I and the others who weren’t IntelliJ users.  We made a new rule for a little while that the driver had to yell out the keyboard shortcut they were using to make the ReSharper magic happen.  A couple months later I was coding solo on an airplane and realized how much faster I was getting with the IDE.

     

    Other examples I can vividly remember was my first exposure to WinForms development, Subversion tricks from my “BuildMaster” guru colleague, and getting other developers to use TestDriven.Net for faster cycling between coding and unit testing with NUnit. 

  • Pairing Rotation

    The question of how often you need to rotate pairs has to be answered by the development team.  I’ve heard some teams say their pairing rotation was 90 minutes and others would rotate much less frequently.  My preference is to lean towards pair continuity on either the story or task level, having a pair work a task from start to finish.  Of course, I also think stories or tasks should be ruthlessly subdivided to fit within a day or two of coding effort (iteration management is a topic for another day), so that still leads to pair rotation at least every other day.  I think it’s convenient to define the pairs immediately after the standup meeting in the morning or right after lunch.  Don’t let any kind of schedule like this idle your developers though.  I’m a morning person and I’ve always been more effective in the early morning with a fresh mind.  Keep a backlog of non-pairing work around so no one is ever idle waiting on a pair to do something useful.

     

    I think the only constant in pair rotation is that the developers need to be self-organizing and manage themselves in this respect.  Having one person, whether the development lead or project manager, assign the pairs as a dictator doesn’t seem to be as effective as a more egalitarian approach.  What I’m really trying to drive at is not to automatically give the most challenging coding work to the most senior guys because it never affords the others a chance to learn and it can breed resentment.

     

    One thing we did on a project last summer was to designate one developer as a story owner for the duration of a user story throughout the iteration.  I thought that turned out to be a great way to balance continuity with pair rotation.

     

    I’ve heard a practice described several times is having some kind of bell or buzzer that rings to tell the developers to play musical chairs.  I think that’s obnoxious myself, but whatever floats your boat.

  • Pair Programming Braindump

    Pairing for Beginners (and Skeptics)

     

    My shop is about to introduce more pair programming into our daily development routine.  Here’s a more or less “braindump” on my pair programming experiences.  I can’t say I like everything about pairing or always enjoy it, but overall the benefits I’ve seen are real enough to make me a believer.  I’m the exact profile (introverted, used to working solo) of the guy who will have trouble doing pair programming and I can still do it, so it’ll surely be easier for you.

     

    “This is the Way We Do It”

     

    My favorite metaphor for software design these days is a fishing tackle box.  I want a place for everything and everything in its place.  When I need a top water lure, I know exactly where to look.  I put data access code here, business logic there, and hook the two things up like this.  When I’m creating new code I want to organize it along a predictable structure that anyone else on the project will instantly recognize.  When other coders are making changes I want them to follow the same basic organization so I can find and understand their code later. 

     

    Each application is a little bit different so the application’s design is always going to vary.  In any agile project you should hit an inflection point in the team’s velocity that I think of as the “This is the Way We Do It” moment.  Things become smoother.  There are fewer surprises.  Story estimates become more consistent and accurate.  When any pair starts a new story, they understand the general pattern of the system structure and can make the mechanical implementation with minimal fuss.

     

    You really want to get to this point as soon as you can.  There are two separate issues to address before you can reach this inflection point. 

     

    1. Determining the pattern and architecture for the system under development
    2. Socializing the design throughout the development team

     

    To the first point, pairing allows you bring to bear the knowledge and experience of everybody on the team to the work at hand.  It’s just not possible for any one developer to understand every technology and design pattern in the world.  By having every developer active in the project design, you can often work out a workable approach faster than a solo architect ever could.  On the one project I’ve done with theoretical 100% pairing, we had a couple of developers with a lot of heavy client experience and me with more backend and web development experience.  By pairing together with our disparate knowledge we could rapidly create a workable general design strategy for the system as a whole by bringing a wider skill set to any coding task. 

     

    As an example from my short stint on an architecture team, I saw one of my architect peers design an elaborate solution for an ETL (Extract, Transform, Load) infrastructure between several systems with an absurdly complex error handling subsystem.  We had a site license for Sql Server and every single thing he designed could have been accomplished out of the box with Data Transformation Services in Sql Server instead of his custom design.  If he’d been listening to or working with the other developers they could have solved the ETL issue quickly and spent more time on the infrastructure management aspect of the project to create a design that the developers could actually code.

     

    If you’re a senior developer or the technical lead, one of your responsibilities is fostering an understanding of the technical direction to the other developers.  Nothing else I’ve ever done as a lead (design sessions, documentation, presentations, “do this,” etc.) beats working shoulder to shoulder with other developers as a mechanism for creating a shared understanding of the project strategy.  By making every developer be involved or at least exposed to the thinking behind the design, they’ll have much more contextual information about the design. 

     

    One unpleasant fact I’ve discovered over and over again is that the more detailed instructions you give to another developer, the worse the code is that comes back to you.  I simply can’t do the thinking for someone else.  If the developer understands the “why” of the design, they always seem to do a better job and often make improvements as they go. 

     

    For example, my wife routinely organizes our large CD collection.  She promptly becomes angry with me when I put CD’s in the wrong place because I don’t understand her organization rules.  I don’t understand why the CD’s are on what shelf because I had no part in creating the organization.  After 9 years, I still don’t understand how my wife thinks either, but that’s a different problem.

     

     

    Improving Our Code vs. Defensiveness about My Code

     

    Don’t for one second discount the psychological advantages of pair programming.  Formal or even just peer code reviews can be nasty affairs.  They can often amount to a divide between the prosecution and the accused.  In my admittedly limited experience, they’ve been largely blown off or devolve into meaningless compliance checks with coding style standards.  Even worse is the fact that they are generally used as a gating process just prior to the next stage of the waterfall, eliminating the usefulness because it’s too late to make any kind of big change.  

     

    The collective ownership achieved with pair programming can turn this situation on its head.  My peers and I can now start to talk about how to improve our code instead of being defensive or sensitive to criticism about my code.  Since we’ve all got visibility now into the majority of the code, we can have informed conversations about the technical direction overall.  The in depth code review happens in real time, so problems are caught sooner.  Add in the shifting of different coders through different areas of the code and you end up with more eyes on any important piece of code.  The ability to be self-critical about existing code, without feeling defensive, helps to continuously improve the system design and code.  I think this is one of the primary ways in which agile development can lead to a better, more pleasant workplace.

More Posts

This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP