Have fun learning about Test-Driven Development with JitterTed's TDD Game

Remote Learning Ensembles

How I use Ensembles (aka Mob Programming) to help developers improve their skills in test-driven development, refactoring, design, and learning from each other.

Originally published on . Last updated on .


2023-10-09: Added “Spectator” role information, added Retrospective details

2023-03-27: Added some Driver etiquette around not blocking information, closing unneeded windows, etc.

2022-06-09: This article was originally published on Dev.to, but it’s time to bring it here, and add some updates.

2022-03-22: Updates since I first wrote this can be found as bracketed & italic remarks inline.

How I Run Remote Learning Ensembles

The Ensemble[1] sessions that I’ve been running for the past few months years are centered around improving developer skills in test-driven development (TDD), domain-driven design (DDD), and Hexagonal Architecture, with a focus on taking small, safe steps, and frequent refactoring. Since the codebase is Java, it’s turned out that all attendees are using IntelliJ IDEA, so an additional focus has been learning its shortcuts and the less common automated refactorings (such as Move Method).

Facilitate From the Outside

Since the focus is on learning skills and not necessarily getting “work” done, I stay out of the rotation, observing and providing guidance and advice along the way. I also serve as the “customer” providing direction on the features being developed. [However, if there’s only 2 attendees, I’ll participate in the rotation.]

Below you’ll find information on how I currently run the Learning Ensembles. Much of this was gathered from various sources, some adapted, and some learned by trial and error.

Handing Off

I’ve found that using GitHub-based hand-offs, using the awesome command-line tool mob.sh, to work better than other mechanisms that I’ve tried. It allows people to use their own computer and IDE, which means they’re not only comfortable using tools that they’re used to, but they’re building skills (such as shortcut keys) in their “natural” environment. The downside is that there’s a bit of disruption during the hand-off, mainly around the new Driver taking over. They may need to rearrange editor windows and open up files, though this tends to be less of a problem after a complete cycle of turns.

Roles

We call the person at the keyboard (and the one sharing their screen) the Driver and the person directing them the Navigator[2]. I’ve gone back and forth about the role names (e.g., Typist, Director), but have found that metaphor of getting to a destination using the roles of Driver and Navigator to be well-suited.

Driver

  • When starting your turn, clearly state that you’re ready for the Navigator’s instructions by saying “I’m Ready” out loud.

    This is needed because the Driver needs time to run the mob start command (to get the latest code on their machine) and arrange the IDE windows as needed.

    [We’ve standardized on having the IDE split the screen into left & right panes, with the test code on the left, and the feature code on the right. This way the test “drives” the code from left to right.]

  • The Driver’s job is to carry out the Navigator’s intent. Note: there is only one Navigator navigating at a time, otherwise the Driver can get confused by too many requests.

  • If the Driver is unsure what to do next, or how to do it, they ask the Navigator for clarification.

    • It’s often helpful for the Driver to offer choices “do you want me to extract the whole block, or just line 24?”
  • Avoid having a Runaway Driver where the Driver does more than (or different things from) what was asked.

  • Don’t scroll around, unless the Driver requests it, as it can be disorienting to the Navigator (and the rest of the ensemble).

  • Avoid leaving popups visible as they can block important information.

  • Close window panes that aren’t needed, especially the Terminal and Project windows. Give as much room to the tests and code as possible.

  • Declares intent at the highest level first, only providing more detail if the Driver asks, e.g.:

    • Start with intent: “extract the loop to a new method named Process Transactions”

    • Provide more detail: “select lines 24 through 28, use Refactor, then Extract Method.”

    • Even more detail: “click on the word ‘for’ on line 24, press the expand-selection key a few times, now click on…”

  • Avoid micro-managing (“backseat driving”) the fixing of syntax errors or typos.

  • On the other hand, it’s very important that the Navigator pay close attention to what the Driver actually did as a result of their instructions. Did they type the correct thing? Did they extract the correct lines into a new method? This is not easy, as Navigators tend to think about the next step, and assume their previous intent was carried out correctly. It’s common for the Driver to do something different from what was asked, but about 20% of the time, the Navigator didn’t notice, causing problems or confusion. As facilitator, I’ll often step in at this point, if nobody else pointed out the discrepancy.

    • Communication is hard, and the only way a Navigator knows that they were understood is if the Driver did what was desired.
  • When the turn is over, inform the next Navigator of what you had in mind. However, it’s up to the new Navigator to either continue down that road, or try something else.

Onboarding New Participants

  • Get their GitHub username

    • Add the username as collaborator to the repository that will be used for the Ensemble

    • They’ll need to accept the invite, so do this enough in advance

  • Participants will need to install and verify that these work:

    • The mob.sh tool (which requires git)

    • Zoom, especially share screen privileges

      • Do audio check, video check is optional
    • Whatever IDE they’re comfortable with

      • Increase font size of IDE to at least 16px for screen sharing readability (sometimes 18px is needed!)
    • Correct version of Java (11 or later)

    • Clone the repository via SSH if possible (this makes it easier to push)

    • Build and run all of the tests

    • Do a test mob start and mob next to ensure privileges are set up correctly

Facilitator Preparation

  • Fill out names in the Mob timer

    • We use https://mobti.me

    • Make sure to rotate so folks aren’t always in the same order or are navigating the same driver

  • Verify participants have accepted GitHub repo invitations

  • Verify repository has the latest code (all changes since last session pushed)

  • Review retrospective and Mission notes from prior sessions

    • I keep these notes in the same repository as the project code
  • Ensure goals (I called this the “Mission”) for the upcoming session are clear

  • Send a link to the Zoom that we’ll be using (even if it’s the same one, people like/need the reminder)

    • I use my Ensembler tool to handle this for me, among other things

The Session

This is based on my experience with 90-105 minute-long sessions [I’ve found 105-115 minutes—just under 2 hours—better for groups that only get together once a week, or less, in order to remember and/or understand the context]. We cap the size to 5 active participants, with turn times of 5 minutes each.

We have two main roles: Driver and Navigator (as described above). When the turn is over (after the 5-minute timer has expired), the Navigator becomes the new Driver and the Driver goes back into the general crowd. [We now go the other way: Driver becomes Navigator, and Navigator returns to the crowd, as the Driver has the code already in their head/fingers.]

The Huddle

[Added details on The Huddle]

The starting Huddle is a way for the group to sync up and understand where things are and what the next task is. This is important as people haven’t seen the code for a week or more (or never!). Once the first Navigator agrees that they have a sense of what to do, the Huddle ends.

During the Ensemble, people can get lost, can disagree on which way to go, etc., and so anyone can call for a Huddle. The timer is stopped and discussion starts. It’s important to get back to the code, so if the discussion becomes too detailed (or too abstract!), it’s time to see if there’s enough understanding to take the next step, without worrying about the steps after that. As the saying goes, “discuss in code”! In other words, trying out an idea by writing actual code, is better at demonstrating what approach is better/worse than just talking about it.

Agenda

  1. Introduce anyone who’s new

  2. Provide the mob timer link (if a separate one like mobti.me is used)

  3. Remind folks of any Code of Conduct

    • At a minimum, remind them that this is a learning experience and to be compassionate and curious
  4. Create (or update) a participants.txt file with the date, and start a list with the facilitator’s name as the 0th entry. For example:

    Session #10 - Friday, May 28, 2021
    ----------------------------------
    0. Ted
    

    [I stopped putting my name as facilitator, and now it starts with the first participant.]

  5. Do one rotation by having each participant do the steps below when it’s their turn. The purpose of this exercise it to ensure everyone can share their screen, update their local copy of the repo, and push changes to the repo, as well as a check of their audio and font size. Doing it at the beginning means that it won’t interrupt the Ensemble’s flow during the actual work:

    1. Share their screen (I make sure that Zoom allows participants to “steal” or “grab” the screen sharing from the current sharer)

    2. Execute a mob start, once it completes…

    3. Type their name in the participants.txt file (if it doesn’t show up, or is missing other participants, you know something’s not quite right), e.g.:

      Participants from Ensemble #50 on March 4, 2022
      -----------------------------------------------
      1. Hoffman
      2. Moxie
      
    4. Execute a mob next and once it completes…

    5. Announce “Ready for next DRIVER”

    6. Next driver takes over and repeats from step 1 until everyone has had a turn

  6. Explain/review the mission for the session

    • I keep this in a text file in the same repository as the project code
  7. The Team does a “huddle”, where they discuss the mission, make sure they understand it, and define the next task or two.

  8. The first Driver shares their screen, does a “mob start” and when complete declares “I’m ready”

    [Usually they’ll start by running all the tests]

  9. The Navigator provides instructions to the Driver

  10. When the turn is over (the timer has gone off), the Navigator relays their intent (what they were trying to achieve) to the next Navigator

    [If the Navigator/Driver pair are almost done with a task, I’ll usually let them finish it before moving to the next person.]

  11. Things that need to be done (delete that test, rename that class, fix that flaky test) are dropped into chat

  12. Side-comments about the work, such as naming suggestions or questions, are also dropped into chat

  13. After each full cycle (everyone has taken their turn once), the facilitator runs a “mini-retrospective”, if the ensemble feels that things are in a good flow, the mini-retro can be skipped.

    • Often the 2nd time around, folks feel the need to hold a mini-retro to regroup and gain perspective.

    [With a more experienced group, I’ve found explicitly taking time for a mini-retro unnecessary, as folks learn to call for a Huddle as needed]

  14. The final turn ends when there’s 15-20 minutes left in the scheduled ensemble time.

  15. Conclude with a retrospective, where each person in the rotation provides thoughts, observations, things they learn, etc., until everyone has run out of things to say. Then, things to do more or less of, what went well/not so well, etc., are noted in an outline or mind map.

  16. Facilitator shares observations (the more specific and concrete, the better), such as “I noticed it took 3 turns to finally get from red to green” or questions, such as “how did it feel to leave have that test continue to be flaky”, or “was anyone uncomfortable with the poor code formatting in that method?”

  17. Session ends with cleaning up of the pending tasks, collecting undone ones from chat, checking off those that are done, etc.

  18. Everyone waves goodbye!


Ch-ch-ch-ch-changes

Note that we have changed how we run the Ensembles over time, because of things brought up in our Retrospectives and the freedom to experiment. I’ll follow up with additional articles as I learn. One non-trivial change was the order of Driver-Navigator. When we swapped that order, we found less of a need to “hand-off” intentions.

Let me know about your experiences with Ensembles by joining my Discord or tweeting at me on Twitter.


  1. Like others, I prefer to use the term Ensemble instead of Mob Programming, as it’s a “friendlier” term. ↩︎

  2. These roles come from Pair Programming terminology, and we specifically follow the “strong-style” pairing method from Llewellyn Falco. ↩︎


Make Your Code More Testable™️

Don't miss out on ways to make your code more testable. Hear about new Refactoring techniques, improving the Test-Driven Development process, Hexagonal Architecture, and much more.

    We respect your privacy. Unsubscribe at any time.