Pair programmingPair programming is an agile software development technique in which two programmers work together at one workstation. It is a relatively controversial practice among all of the agile methods, if not the most. In fact, only a few teams that adopt it can actually benefit from it. For the rest, even if they claim they are doing agile, they will often be divided into two camps.
First, there are the advocates who support pair programming by arguing that it leads to knowledge transfer, reduction in potential defects as well as the removal of 'information islands.' The opponents, however, believe it is a waste of time. They argue that it is difficult for developers to focus on the delivery task when working in pairs and that the devs will most likely end up debating over trivial things like 'deciding which text editor to choose.'
Additionally, another common issue is that it is challenging to measure performance for each developer when a team adopts pair programming. And for some organizations, it's crucial to measure everything. Frankly, doing pair programming is the most challenging part of almost all of the projects I've worked on.
Of course, pair programming is not just about two devs sitting together and writing code in turn - it's a science and a fun-filled (well, almost) engineering practice. It has a lot of principles to follow, and if only the devs in a team can apply those principles correctly, can they benefit from it.
I'm not going to discuss how the pair programming affects productivity, or whether you should adopt it in your next project, or to what extent you should apply it in your own project. This article is for those who have already decided as a team to give it a try and are wondering how to do it, or for those who found that it is not as practical as it sounds, and want some useful guidance.
Let’s assume that you have already found your peer, and cannot wait to get started with a particular user story. Just before you start typing any fancy code, you should set up the environment first.
1. Hardware preparation
Firstly, you will need an external monitor and a height-adjustable table (ever tried making a DIY one with cardboard boxes?). This is neglected by most beginners; however, this is a fundamental step that can determine whether the practice is sustainable or not. If you have been staring at the monitor for too long with a poor posture, the pain will distract you from the coding, and you will find it more difficult to focus. So it won't last long if you’re uncomfortable.Before you start coding, make sure the screen is at an optimal height and adjust the height of your seat to make it suitable for you and your peer. If applicable, you might want dual screens.
Apart from that, here are a few more items you’ll need:
- VGA/HDMI adaptor
- Laptop battery/charger
- Keyboard/mouse adaptor
- Some A4 paper, post-it notes, and sharpies
Remember, pen and paper are your best friends. Firstly, it's crucial to split a story into S.M.A.R.T (Specific, Measurable, Achievable, Realistic, Time-related) sub-stories before you even start coding. Sometimes it's convenient to keep this posted underneath the bottom of your screen. Finally, please make sure your phone is in silent mode (this helps a lot!).
2. Software configurationNow that you have all of the hardware ready, it's time to make the software work for both you and your peer. Unfortunately, the software is more complicated than the hardware. Most professional developers have their own toolkit, from curl/wget to vim/emacs, but don't expect that you and your peer have common tools. That's something you might encounter as a coincidence, but not what you should expect.
From my experience, advanced IDE like IntelliJ / WebStorm from JetBrains has built-in predefined keymaps you can easily switch between. If you cannot agree with which keymap fits both of you, just switch to yours when it's your turn to write code and vice versa.
In IntelliJ/WebStorm, you can easily use “Ctrl+ `” to switch between different preferences, “3” for switching keymaps. You just need to press three keys, and this could help avoid any potential conflicts.
Please note that this technique only works if both of you have sophisticated keyboard (shortcut) skills. Another common scenario is when one person does not master any predefined keymap at all; this would require the ‘slower one’ to try to learn at least one keymap, and catch up with their peer.
Before you pair fluently with your peer, you should get familiar with one IDE/editor. For example, you should be able to do the following commonly used tasks without touching your mouse:
- Search file by name and navigate to that file
- Search by content
- Locate to particular function/line
- Select variable, expression and statement
- Run tests (either in the command line or in IDE)
And so on, which would improve your productivity significantly. Even better, the ROI of those tasks is pretty high, so just take some time to practice and master the basics. Trust me, it's worthwhile.
3. Dealing with a knowledge gap
So that’s enough for the setup, now let's look at pairing. Ideally, peers should have a similar level of skills, have a relatively similar level of knowledge, and can communicate fluently and effectively. They can focus on the problem itself and discuss deeply, bounce ideas off each other, and let their fingers dance when they code. In scenarios like this, they don't need any techniques and are free to work in whatever form they like.In contrast, there are scenarios where both peers have no idea of how to solve the problem, and neither of their skills fit the project's requirements (something we should avoid when staffing).
The other scenario, and the most common one, is where you have one dev who is experienced while the other is relatively new and needs to catch up. Generally speaking, one should help lead while the other observes. Together, you’ll collaborate closely, answer questions, and solve the problem together.
Different from your traditional way of teaching, pair programming requires two intelligent souls to work together, rather than one spoon-feeding the other. Hence the observer doesn't work passively, and the driver doesn’t just teach. It becomes an intensive, interactive activity.
For the driver
Sometimes it's pretty easy for a driver to become too immersed in their work to ignore the peer’s feelings. Frankly, I do it myself as well (which is terrible) and can often end up treating my peer like a ‘rubber duck.’ This can make your peer frustrated and unable to follow your pace, which would ultimately affect the outcome. As a driver, you need to be more patient, and continue engaging with your peer.
The other extreme end is where the driver is too passionate to coach, and they neglect to create an opportunity for their peers. This requires the driver to introduce more opportunities for the observer to practice. For example, after going through a complete test-driven development (TDD) cycle (red-green-refactor), suppress your pulse to continue coding (I know it’s hard), give the keyboard to your peer, and ask them to follow exactly what you just did.
When you see something go wrong, you should immediately stop your peer, and try to make a suggestion like:
- Are there any other approaches you can see?
If they hesitate or cannot quite follow, try:
- Do you think XYZ is better?
For the observer
As an observer, pairing is a great chance to learn from your peer, so you should make the most of the experience. For things such as keyboard short-cut usage, options for command line tools, or any other productive programming habits your peer has been using - keep an open mind and be curious. And when you see you peer magically delete all of the content in brackets, or pretty up the output from curl, don't hesitate to ask.
In practice, you can switch your role at every test and code cycle. For example, A writes a test, B codes to make the test pass, and A does the refactor, then B writes another test, and so on so forth.
4. Keep your focus
Once you have decided on what the problem to solve, you then need to do the tasking. This will make sure you always focus on a small chunk of work and avoid any potential waste when you have to switch between contexts.
Once a task is done, just cross it out from the sticky note. Don't underestimate the power of those cross-offs. Firstly, it can easily visualize progress. Secondly, it acts as a reminder whenever you’re interrupted by your surrounding environment. Finally, this small ritual could provide your brain with positive feedback, which can promote dopamine that can make you happy!
However, in some extreme scenarios, when the conflict between technical decisions becomes inevitable, we have to make a trade-off between some of the aspects and move on.
5. When opinions cannot be agreed
When you have to pair with a stubborn colleague, or even perhaps you are somebody that is difficult to convince, how would you handle the arguments likely to arise? Especially those arguments where you cannot determine what is right or wrong clearly, for example, which programming language suits the most in Web application (I mean, surely it's PHP, right?), or how to do TDD properly (bottom-up or top-down) and so on.
In some situations, we insist on something we genuinely believe in and treat others who don't think in the same way as pagans. Actually, it just takes a little more time to realize that they might not be so wrong, and that it may make more sense if we could see the problem rationally from another angle.
In one of my previous projects, I chose the scss module as the CSS preprocessor just because in a previous project I used it and found it pretty handy. While one of the colleagues proposed styled-component, we were unable to convince each other. So we ended up having both styles mixed in the codebase. Until one day, I found that component built on top of styled-component looks pretty neat, and after trying to refactor some of the components written by scss to styled-component, I found that the code looks more concise and doesn't have any impact on existing tests.
Suddenly I realized that the truth I had been insisting on was like a fantasy I had made up, just so I could keep on using something familiar. Having an open mind is not that easy, and I hope that you can take a step back to rethink the proposal you made when you find that it's hard to convince others or be convinced yourself.
For those hard-to-agree dilemmas, I suggest you park it and try one of the approaches, until you find out what is blocking the implementation of the business requirement. Usually, you will find some trade-off, and come up with a solution by playing to each other’s strengths.
Some tough tasks
Even for experienced developers, they will face tough problems such as dealing with a new domain with a complicated business logic or even new challenges in domains that they are already familiar with. In some cases, both peers do not have any clue on how to get the problem solved. If you insist on pairing at this stage, it actually makes it difficult and ineffective.
One viable approach is to do some ‘spikes’ separately within a limited time box, say 30 minutes. In most cases, at least one of you will come up with some direction to start with. Otherwise, you might have to raise it as a technical risk to the whole team or the whole program.
For instance, we were facing an authentication issue about Kerberos, neither my peer or myself had ever done this at all. After 20 minutes of separate studying, I found an informative article covering a lot of details about the Kerberos authentication mechanism, and my peer found some existing code in internal GitHub. We decided to copy that code instead of putting more effort into it and refactor it later on.
Attention is actually the most precious resource, normally you can hardly focus on anything more than 30 minutes. After that, your brain will find something more interesting instead. A short break could help the brain rest and refresh. Our brain has a fascinating feature: it has a super ability to handle tasks in the background (a.k.a our subconscious), which can be surprisingly more powerful than what happens in the conscious part of our brain. Chances are, you have already experienced many ‘aha moments’ when you’re going downstairs for a flat white, during a shower, or even in your dreams.
When you encounter some bugs that are difficult to understand or you’re stuck with setting up the testing suite, taking a break might give you some inspiration by looking at things at a different angle. To avoid being immersed too deeply in a particular issue, you could use tools like 'tomato timer' or similar tools:
- Fetch a task from your to-do list
- Set an uninterruptible time for 25 minutes and start working
- When the time is up, take a 5-minute break
- Repeat steps 2 and 3, and take a break for 15 minutes after 4 rounds
6. Switching pair
When you always pair with someone for a while, the pair has the risk of turning into an ‘information island’. For example, let's say A and B have been working on order modules, while C and D have been working on store management. After a certain period of time, A and B won't know what C and D are working on. This includes not only domain knowledge but also technical details/design patterns, etc. When your team grows to a size of ten or more, the problem of having an information island could get worse.
You should have some mechanism to ensure pair rotation happens, for example, rotate the pair twice a week or so, in order to enable knowledge sharing across the team.
In some cases, the team will adopt front-end and back-end separation. The tech stack in both ends may have nothing in common, which introduces potential challenges for rotation, and this can reduce productivity in the short-term. Things could also get worse when the Ops are separated as an independent team.
In practice, I found that pair rotation among different roles can help widen an individual’s knowledge and viewpoint, and as much as having a specialty is great, we need to encourage each other to learn and share as much as we can. If a front-end developer spends some time pairing with Ops, they could understand more about how the application works at the architecture level. And after the back-end devs pair with the Ops, they might be able to identify potential defects and fix it even before the defect happened (for example, externalize the session storage, cache strategy, etc).
7. Respect your peer
Learn to see things from your peer's perspective. Try not to be the person you don't want to pair with. For example, the person who is always using the mouse to navigate files and is less effective when typing or the person who is careless with their typing if they are following you - the point is, try not to be that kind of person yourself.
Apart from this, respect comes from all of the smaller details. When you have to leave during pairing for something else, make sure to let your peer know, and apologize before you leave. Don’t just vanish and show up later. No one wants to pair with someone who isn't reliable. Furthermore, when your peer comes back from a meeting, you should tell them what's happening, give an update on the progress, and what are you trying to do next. Make sure you have the same understanding on the task on hand.
Control your emotions
Emotions are an interesting thing, and it can easily propagate to others. When you have a few blockers preventing you from trying to finish the task, or you're finding it difficult to make any progress, you have to learn how to control your emotions. When your peers complain next to you, it makes you also feel frustrated and difficult to focus on solving your own problems.
It's crucial to seek help outside and visualize the blockers. Let the team understand your situation and provide support, if possible. Be proactive on the task itself and try not to influence others with your negative emotions.
Do your homework
After a full and happy day, it's your responsibility to summarise what you’ve learned - this is a perfect way to improve yourself and skill up. After applying the knowledge and experience you gained to a real-world project, you can find areas of improvement and learn how others solved similar problems, and this will have a profound impact on your learning and growth.
For example, when you are quite comfortable with using grep to do full-text search, and noticed that awk looks more effective when your peers demonstrate the advantages of using it. You can then go back home and try to use different options or compare this with the tool you are already familiar with. Another example could be you and your peer found an interesting feature about webpack when fixing an issue, but neither of you understand the mechanism under the hood - this is also a great opportunity for you both to learn and grow. Spend some time updating your technical skills by learning from others, which will help develop your skills for the next day’s pairing - and have fun!
Those principles are fundamental, subtle and might seem a little trivial. But doing it well can make you and your peer comfortable and confident during pairing, and hopefully enhance productivity into your daily work.
In this article, I summarised some common patterns and things you should do during pairing programming. Here are the seven key takeaways:
- Before you get started, make sure you have the hardware set up correctly to fit both of you. In order to be more effective and productive when coding, you can use different IDE preferences.
- And don't forget about the software setup!
- When there is a capabilities gap - and this is exactly when pairing can maximize its potential - it's not only the observer who can get the most out of the experience, but it's also the driver who can learn something new.
- During pairing, always focus on the task at hand. You might also need techniques to split a big task into smaller parts, and resolve them one after another.
- Additionally, you should have a regular break during pairing - make sure you relax and refresh!
- Avoid creating ‘information islands’, by making sure the team rotates the pairs regularly.
- Finally, respect your peer and make the small details count e.g. keep your peer updated on your schedule changes.
By applying these principles, it will be helpful for both the individual and the team in the long-run, and promote everyone to work in a healthy, and even happy, environment.
Disclaimer: The statements and opinions expressed in this article are those of the author(s) and do not necessarily reflect the positions of Thoughtworks.