Whenever I describe the agile practice of pair programming I usually get the same general reaction,which is something like “I don’t think I’d like to do that”. My usual attempt to convince someone that it could be an interesting tool to try is to suggest that verification team could do it for the complicated sections of code, or to have the designer and verification pair program to develop the drivers. While good reasons, these were never enough. This posting will be another attempt on my part to show the value of pair programming, and to provide some suggestions on where programming could be effective for you, and some reasons on why pair programming may not be effective.
First, I need to step back a bit and explain what pair programming is. Simply put, pair programming is when two engineers sit down together to design and implement a piece of code. One engineer is responsible for driving (i.e., they own the keyboard) and they are the ones that physically write the code; while the second is responsible for providing support through discussing the code as it’s being written, constructively pointing out problems, updating diagrams, looking at the other supporting or interacting classes for issues, researching solutions on the net, etc. — basically providing support and instantaneous review of what the first engineer is typing. The engineers can and should reverse the roles on a regular basis, or when the “support” engineer wants to show what they’re thinking by asking for the keyboard and putting down their ideas. Now honestly evaluate whether your first reaction to pair programming was “I don’t think I’d like to do that”. Hopefully, the rest of this posting will convince you to consider trying it.
The advantages of doing pair programming are the following:
- higher quality code: following the adage “two heads are better than one” — the code is being continuously code reviewed as it is written. The likelihood of silly “finger” troubles are less likely. As well, having someone able to sit back and take a look at the bigger picture while the code is being implemented can possibly allow the interaction errors with other supporting modules less likely. A corollary to this is that you’ll also have likely higher quality code comments — your code buddy will make suggestions for a comment that will be meaningful to more than just one person.
- team building: sharing the responsibility of design and creating something is definitely a team morale booster. It fosters confidence in the other person’s skills, and allows you to share your knowledge with someone else — making your team stronger in the process.
- common ownership of the code: ideally, everyone is responsible for the entire code base. However, what can happen is that egos get in the way and people feel that they own the code, and that no one should really be touching it without their permission. While this is not eliminated using pair programming, it can be lessened.
All good valid reasons that many folks can accept. However, to ask them to actually try it… that’s when the roadblocks are put up. Most people I work with are senior engineers who feel that that is not the best way that they develop their code, and think it will be too slow or inefficient to have two people working on the same code at the same time. The interesting factoid that I’ve noticed is that many of us do pair programming in short bursts — usually when there is a crisis, or when we’re not making progress in our design process. Our first reaction is to discuss and review the issue with another person. Whenever something breaks in the code and it’s either impacting others, or there’s time pressure, we generally grab one or two people to go to the nearest whiteboard and discuss, or get one or two people to come over and look at the code that seems to be problematic. We’ve all done it. Why? Because it’s the usually the fastest way to resolve an issue. It usually helps to describe the problem to someone else, show them what you’ve tried to resolve the program, and then ask them for their suggestions on what to do next. I have done this many, many times over my career, and I think most of of us have at one point or another.
Now my question is: if the most efficient way during a crisis is to ask a colleague for a review and provide suggestions, why is it not that efficient to do when there is no crisis and while the code is being written? In essence, pair programming follows the same principles as what happens during this crisis.
My second point on this “pair programming is inefficient” argument is that ASIC/FPGA development is similar to software in that we spend a LOT more time supporting a line of code than we actually spend writing it. That is, we spend more time analyzing, designing, documenting, reviewing, refactoring and, most importantly, debugging a piece of code than we do actually writing it. Having two people working on the same original code at the same time is simply not going to impact our productivity negatively. In fact, I’d argue, and there is anecdotal and empirical evidence to support me, that pair programming actually reduces our time to complete a piece of code [Williams] [See Wikipedia entry “Pair Programming”, section Scientific Studies”]. As with asking a buddy to help during a crisis is more efficient, asking them to help when there is no crisis is just as efficient.
However, for full disclosure there are dissenting views and studies on Pair Programming. The one I found interesting was a meta-study of all the other studies [Hannay]) that indicates there is only minimum effect on quality, and it takes longer, and requires more effort. These studies (with links below) are an easy, excellent read and I encourage you to review them so that you can make up your own mind on whether pair programming is worth a shot for you and your team.
Potential Pair Programming Problems
While I believe that pair programming has worth in many, if not all development chores, I realize that it won’t work in every situation. However, the reasons pair programming may not work are not due to the technique, but rather the people-related issues. The experiences and attitude that come with pair programming will affect both the value that is put into the effort, and the results and impressions that come out of it. Chiefly, this comes down to ego and personalities. People do get invested in the designs that they create — that’s a good thing. But for some folks, there is a limit on whether they can accept ideas from others around that design — that’s not a good thing. Or that the task is so straightforward or of medium complexity that it is really is a “waste” of time to have two people do the same job. My only counter-point is that all code has to work for the system to be reliable, tiny errors accumulate to reduce the overall quality. Similar to code reviews (but pair programming provides a much more active role for everyone), pair programming helps ensure that every line of code is of the highest quality possible.
In terms of experiences that each partner brings to the effort, there are three very coarse combinations of “skills” partners:
- novice-advanced;
- advanced-advanced;
- novice-novice.
Please note, the use of the word novice is not intended to mean someone fresh out of school, it could mean someone who is new to your company that needs to learn the ropes.
I’ll review those one at a time and discuss where value can be extracted from each of these combinations:
- novice-advanced: If the goal is to mentor the novice, then pair programming would be an excellent way to help with the mentoring. It would allow the novice to ramp up quickly and ask questions; allow the advanced user to explain historical, significant reasons for getting to where they are, as well as offer the novice an opportunity to ask questions and offer suggestions on how it could be improved.
- advanced-advanced: As above, this pairing would only work if the personalities involved were willing to give it a try. Ideally, this pairing will work on a task that is particularly complex, or some important piece of IP that will be reused many times in the current project or potentially across many project. In general, one key value of pairing is to facilitate discussion, so using pairing for any job would be valuable simply for that benefit.
- novice-novice: While this pairing would require support from the more advanced user (or where the documentation is excellent), this is another way where two heads are better than one. The novices could help each other learn more quickly by discussing the problem, potentially bringing their previous expereinces into the solution, and then coming to a consensus approach or involving an advanced designer in the formation of the solution.
The other aspect of pair programming that could make it a demotivator is if the two people don’t normally work together effectively, pair programming will likely be disastrous and ineffective. Care should also be taken when pairing a novice-advanced combination in a mentoring situation — watch to see how they play together. It would be nice to say that as a professional, everyone can rise above this — especially as your corporation is paying you to work with everyone else — but the reality is unfortunately very different. Wishing it were different is not realistic.
Good Places to Try Pair Program
Here are some areas where pair programming is especially effective (assuming that I’ve convinced you to give a try):
- Important or Complex Verification Classes: Where many people need to understand what the class is supposed to do e.g., an important or complex base class. Where the the design of API/usage model must correct, or where the algorithms implemented are complex.
- Functional Coverage Model: Verification and Design working together to design and implement the functional coverage model. Creating the coverage points ensures an understanding of what kind of stimulus will be required. This will likely be an incremental work i.e., created in short spurts as the environment is developed.
- Interface Boundaries: Either between two designers or two verification people. Creating the functional interface or verification drivers increases the likelihood of the two interfaces working together and creating a common understanding of its functionality.
- Assertion Development: Related to interface boundaries above, having two designers or a designer/verification pair create assertions around an internal interface protocol, or complex state machine would be beneficial. Pair programming helps with the both the definition and optimization of the assertion.
In conclusion, I think pair programming has a lot of merit to use regularly. I think it’s another tool to help us create higher quality code and be more productive in the long run. I believe that Pair Programming and Test Driven Development (a topic that Neil and I are currently preparing a set of blog posts about) are the two low-hanging fruits that are easy to adopt — assuming you’re willing to give them a try. I challenge you to find a willing partner and give pair programming a try. I’d welcome feedback on both where it worked well, and where it didn’t work as well.
References
- [Williams] “Strengthening the Case for Pair Programming”, Williams et al, 2000 (http://citeseerx.ist.psu.edu/viewdoc/download?oi=10.1.1.33.5248&rep=rep1&type=pdf)
- [Hannay] “The effectiveness of pair programming: A meta-analysis”, Hannay et al, February 2009 (http://www.sciencedirect.com/science/article/pii/S0950584909000123)
I’ve been novice-advanced pairing situation a lot, as the ‘advanced’ person. It has amazed me since the start how much I learn from the ‘novice’.
Advanced-advanced can be intimidating. You get to show what you know, but you also reveal your weaknesses. You can get over this pretty easily when you start to realize your partners have weaknesses too and we all have a lot more learning to do.
James
Although I have not been in a company that formally practices Agile, I have participated in pair programming on several occasions for RTL in both FPGA and ASIC (in my experience last minute small fixes close to tapeout are always done in pairs). Pair programming certainly brings you faster to compilable and maintainable code as two people naturally tend to focus on the syntax (e.g. missing wire, reg definitions, use of = or <= etc.) and readability (e.g. signal names). To what extent the code is more correctly structured at a higher level I am not so sure. It is true that design-reviews miss many structural issues, as the actual coding does not always follow the original intent. Nor is it simple to give the right level of details in a design-review. However, I cannot recall many situations in which pair programming actually brought very good results on first shot. In my opinion refactoring is the main tool to bring code and design quality up. In this respect, two or more people that know the code from first hand can better discuss the ups and downs of the current code and suggest how to improve it. Likewise, during debug two people that know the code are an obvious benefit. It is in these stages of debugging and refactoring that you should probably look for the real benefits of pair programming.
I’ve had experiences with the advanced-advanced combo in design. It was a very efficient way to review code and share best-practices. Both parties win from that. As Yaron implied, the effect isn’t so much to catch design problems as to drastically improve the maintainability and readability of the code base. In the long run, its easy to believe that it leads to a reduction in bugs found. These bugs aren’t the initial get-it-running problems but rather fall into two categories: a) bugs due to other bug fixes, and b) bugs due to incremental improvements that break complex behaviours. The effect isn’t to find problems outright but to reduce the time to fix bugs and reduce the time to add features.
After-the-fact design reviews: drawing pictures on the white board of what was (will be) implemented, talking through a “packet walk-through” (s/w land would call it “use cases”, “sequence diagrams”, etc) and the like, are much more effective at catching the design issues and potential bugs.
Another case I could foresee this being effective is when building the first of many similar units (agent/driver/monitor/et al.) where this would set a common and mutually agreeable standard. After all are on the same page, going off and doing your thing will result in much more uniformity in implementation approach and decisions. It will require less rationalization of the code at a later review stage.
I totally agree with the advantages of pair programming. One thing I am not sure if this is true or not is the following: I can imagine the management to say “Ok, if two people are going to work on this assignment, we expect it to be done in half of the time”. It is nice the code will be of higher quality, but the goal of the management is to finish the project as soon as possible, give it to the customer and move on to the next project to make more profit.
Do you think that pair programming would actually give the results in half of the time if two people are working on a certain part of the code rather than just one person?
Honza, that’s an interesting question. Unfortunately, I don’t believe the answer is that easy to quantify.
Let’s break down creating a typical workflow for creating some piece of functionality in code. In the simplest flow it’s:
1. Analysis (understand what you’re going to build i.e., what does it need to do?)
2. Design (figure out how you’re going to build it i.e., the architecture)
3. Implement it.
4. Integrate it (including some acceptance testing to ensure it works).
5. Debug It / Maintenance
If you agree that these are reasonable steps you’d need to add up all the time spent on each activity to see the total time to develop a feature — and not just the time to code it up. The problem is that some managers might look at just Steps 3 and 4 (Implement and Integrate) as the “total” time. If that happens, then I suspect the answer to your question is that pair programming does NOT cut the time in half.
However, if you consider ALL the steps, then I believe the answer is likely somewhere between half and just as long as it takes one person — but the true value is that the end-product is of higher quality with pair programming than without.
Let’s assume that you did pair programming for steps 1 through 4 (Analysis to Integration). What does it buy you?
1. Analysis: I think it would take about the same amount of time for two people to understand the problem. Likely no savings here. The key thing is having two people discuss the solution will drive out any initial ambiguities or misunderstandings in what needs to be done. So you’d end up with a higher quality output from the analysis step by driving out any “spec” bugs.
2. Design: Again, probably no real savings in time here either. Maybe even a little longer as you’d need to convince someone else that your design is correct. But again, because you need to discuss and convince someone else of your design, you’ll probably end up with a better quality design — driving out any “design” bugs.
3. Implement. I suspect there would be large margin here from taking slightly less time to significantly more. It would depend a lot on the dynamics and skills of both coders. However, I suspect that you’ll also drive out many “implementation” bugs by doing pair programming. It’s the equivalent of real-time code inspection — eliminating most bugs as you inject them!
4. Integration: Here’s where I think you’ll really start to gain time. Because you’ve driven out a lot of “spec”, “design” and “implementation” bugs, it’s likely that your integration effort (and system testing) will take significantly less time.
5. Debug: This is where there are big gains in time spent. Based on my limited experiences with pair programming and my significant experience with formal code reviews (which I look at as a good substitute, or complementary to pair programming), the end-result of the delivered code is of much higher quality than without. So my debug time is significantly reduced.
If you sum all that up, I think the answer is yes you’d ultimately spend about half the time, but only because you wouldn’t be spending as much time in integration or debug. And therein lies the problem. You have to have faith that that is where you’re going to ‘save’ time — since the only way you’d know for sure is if you did the *same* piece of code with and without pair programming to accurately gauge if you saved time.
Here’s another way to look at it: I’ve read studies where the average programmer can produce up to 10 lines of high quality code per day — once you sum up time spent writing documentation, in meetings, coding, testing, debugging, etc and divide by the number of lines of non-commented lines of code produced. So if by using pair programming you can improve your quality at the front end (analysis, design and coding) which ripples downstream to reduce your integration and debug time so that you could produce say 12 lines per day — you’ve just improved your productivity by 20%. You’ve just shrunk your schedule by 20% — that’s significant!!