Working in Teams
In some classes, you may need to work on projects in pairs or in teams. This is not a gratuitous decision: in practically all contexts, software development is a team sport, and you will develop many useful skills by doing these projects with others rather than by working on them individually.
However, working with others can be as challenging as it is rewarding. In this page, we provide a number of suggestions and tips that can help you make the most out of working on a software project with others, particularly in the context of a university course.
Choosing your project partner(s)
If you are allowed to choose your own project partner(s), then the first thing you will need to do is find those project partner(s). For simplicity, we will describe what this involves from the perspective of choosing one project partner (given that pair projects tend to be the most common), but everything we say here is also applicable to finding multiple project partners.
Choosing a project partner is not something to take lightly, nor should you just pair up with the first person who happens to be available. You and your project partner will be depending on each other throughout the quarter, and you want to make sure you work well together as a team before you commit to spending a fair amount of your time working together.
Ideally, there is someone in the class that you’ve worked with before (this doesn’t have to be on a course project; maybe you’ve worked together in a student organization, in an on-campus job, etc.). If you know that the two of you already work well together and, more importantly, feel like you can rely on each other, then you’ll likely work well together in your class, although you may nonetheless want to have a discussion on some of the issues we discuss below.
What if you don’t know anyone in the class? This is perfectly normal! (and there will usually be a lot of other students in that same situation) However, you may want to consider the following before pairing up with someone:
Preferred means of communication: As we’ll discuss below, communication is a key aspect of succeeding as a team. The two of you will need to be able to easily reach each other (sometimes frequently and on short notice); make sure the two of you have at least one messaging platform (Messenger, Slack, texting, etc.) that you already use and where you can be easily reached.
Work schedules: Make sure you have compatible work schedules. If you’re a night owl, and your project partner is a morning person, or if you expect to do most of your work on weekends but your partner doesn’t, then you may find it difficult to meet and to communicate throughout the quarter.
Level of experience: You will usually want to pair up with someone that is at roughly your same level. If you’re a fourth year who is almost done with the CS major, and you pair up with a second year who is fresh out of the intro sequence, you may get frustrated by the fact that your partner progresses more slowly through the projects.
There is one notable exception to this: pairing up with someone less experienced than you for the express purpose of having a mentorship relationship can be a very fulfilling experience for the both of you. However, you need to make sure you’re both on board with this, and understand that the less experienced partner may need some hand-holding throughout the project.
Good communication is essential to working productively in a team. We suggest that, at the very least, you meet in person at the start of each assignment or project to decide on a plan for completing the work (we provide some pointers on this below), and then plan to check in with each other at least every 1-2 days. Take into account that this doesn’t have to be an in-person meeting: you could simply chat online or have a quick call. These check-ins can also be pretty informal: in fact, instead of setting a specific time to meet every 1-2 days, you may simply settle into a routine of regularly chatting online about your work.
Regardless of how or when you check in with each other, here are a few things you may want to discuss:
What are you each working on? Provide a quick overview of what you’re working on at the moment, and what you expect to work on in the next few days. It can be specially useful to discuss what (if anything) has changed since your last check-in, and what you expect to get done by the next check-in.
Are we on track? We encourage you not to frame your check-in in terms of “what work have you done?” and, instead, in terms of holistically assessing whether you are on track to complete the project.
Most notably, it can be perfectly normal to not get any work done from one check-in to another! This may be something you already expected (e.g., at your previous check-in, you may have told your partner that you had a midterm coming up in another class, and that you had to focus on that), or something unexpected (your dog got sick and you had to spend all day at the vet). In any case, a frequent check-in can allow you to frequently reassess whether you are still on track, and whether you need to make any adjustments to your plan.
Do you need help with anything? Even if you’ve taken responsibility for one part of the project, that doesn’t mean that your partner can’t help you with it. If you’re stuck on something, this is a good moment to bring it up.
Sometimes, you will make a somewhat firm commitment to get something done by an agreed upon deadline, specially as the actual deadline for a project gets closer. Some of those times, you may not be able to get that work done (for any number of reasons) and it is important that you communicate this to your project partner as soon as possible (ideally as soon as it becomes clear you won’t be able to meet the deadline you agreed on, instead of waiting for that deadline to pass). While it can be tough to admit you may not be able to do something you committed to doing, having an early and frank discussion about it gives the two of you an opportunity to regroup and figure out how to stay on track.
Take into account that correctly estimating the time and effort required for a task is challenging even for seasoned software developers, and missing the mark happens more frequently than you’d imagine in many software projects. If it happens to you, don’t think of it as having done something wrong: you’re simply getting the hang of figuring out how long it takes to do something, particularly in a collaborative setting. This is another reason why frequent check-ins are important: they can help you catch these issues sooner rather than later. It is better to identify this issue (and reassess the way forward with your project partner) once you realize it’s going to take you longer than expected, instead of plowing through and then revealing to your partner that you didn’t get to other tasks because you spent so much extra time on another task.
Some project management basics
If this is your first time working on a complex programming project with another person, you will find it a very different experience from working individually on a programming assignment, and will have to spend some of your time on project management activities. While these may instinctively feel like a waste of time (because it’s time you’re not spending coding and making tangible progress on the project), they can pay off handsomely in the long run. While we can’t teach you all about project management in this guide, we provide below a few essential tips that you may find useful.
We’re sure you’re told in all your classes that you shouldn’t wait until right before the deadline to start working on an assignment. We realize this is not always possible (given all the demands on your time) but we encourage you, if possible, to get an early start in any complex project, specially if it spans multiple weeks. This is when you will start working with your project partner, and will likely have to iron out the ways in which you collaborate best, and this will take time. You want to allow plenty of time before the deadline to figure our how to work effectively together, and you will find this much easier to do outside of the context of a pre-deadline time crunch.
Once you’ve settled into a good working relationship, it may be a bit easier to live on the razor’s edge but, even so, we will reiterate that the best way to have a productive and fun experience with a complex project is to start early and to spread the work before the deadline, instead of planning on a pre-deadline coding marathon.
Software Design involves specifying the structure of the software to be implemented, the data models and structures used by the system, the interfaces between system components and, sometimes, the algorithms used. In many software projects, this involves writing a design document containing this information.
Before you write a single line of code, we strongly encourage you to sit together and draft a design document for the project you are about to start working on. This doesn’t have to be a formal document, but it can help you think through how you will structure your code which, in turn, will make it easier for you to divide the work in concrete ways.
Here are some of the things you may want to specify in your design document:
What data structures will you be defining?
Will you need any additional data structures? (lists, hash tables, etc.)
What functions will you be defining? What will their parameters and return values be?
In a C project, what C modules will you define? (i.e., what C files will you add to the projects, and what functions will go in each of them?) What are the dependencies between each module? (i.e., what functions from one module are needed in another?)
If there are any complex operations you need to perform in your code, sketch out the algorithm for them.
Spending time on this may feel like you’re not making tangible progress. Why write something in a document when you could just start coding? In a short programming assignment, you can often get away with coding right away, and making adjustments to your code when you hit a dead end, realize you chose the wrong data structure, etc. However, that approach doesn’t really scale to a large multi-week project, where making even small changes to your design could have ripple effects throughout your entire code.
Not just that, the design document can be an invaluable piece of documentation: in a large project, you won’t always be 100% familiar with every single piece of code, and it can be helpful to have a document you can refer to when you need to find out what a given struct does, or why you decided to define some function in a particular way, etc.
(Not) Dividing the work
Team projects are typically designed to be very challenging to complete individually. To complete the work in the project, you will need to divide up the work and make some progress in parallel.
So, you may be tempted to just look at all the work you have to do and say “you do this half, I do this other half, let’s put everything together before we submit”. This is a generally unproductive strategy, and one that will invariably lead to “integration hell” (when you try to integrate together the work you each did). It also means that each of you will only be familiar with half the project (and remember that, on the exams, we will be asking you about all aspects of the project).
On the other hand, you could do all your work sitting together on the same computer, but this can be logistically complicated: you need to find time to physically meet together, and you lose the ability to parallelize your progress (since you’re limited to making progress only when the two of you are physically sitting together at the same computer).
What you need to do is find a balance between these two extremes: when you identify parts of the project that you can each work on individually, you can each work on them on your own, but it is important that you communicate your progress to each other (as noted earlier, communication is key, and this is why having a regular check-in can be invaluable). Below we discuss one mechanism, issue tracking, that you may find useful to keep track of your progress (and to have a more structured communication around specific goals in the project)
Since it is important that you each have total awareness of what is done in the project, you should get into the habit of reviewing each other’s code. Not only can this be helpful to understand parts of the project you’re not directly working on, it can also help catch bugs early. Below we discuss code reviews in more detail.
Finally, when you’re faced with a particularly challenging part of the project, it can really pay off to work on that part together, on the same computer, by doing Pair Programming. Some times, you can already anticipate that some parts will be tricky and can benefit from Pair Programming; however, if you’re working on a part of the project individually, and realize you’re getting stuck, you should ask your project partner whether you can do an improptu Pair Programming session to see if you can get un-stuck.
Using Git effectively
In most classes, you will be using Git as a version control system. However, you should not treat it as a glorified homework submission system, where you just push your code right before submitting. Instead, it can be an invaluable tool for developing code collaboratively. We encourage you to familiarize yourself with using branches in Git, as these will be necessary for doing issue tracking and code reviews.
We do have one caveat about branches: avoid having per-person branches (i.e., you do all your work on all the projects in one branch, and your project partner does all their work on all the projects in another branch). Below we suggest a better way to manage branches, where each branch corresponds to a specific task or issue you’re working on (and, while these will often be worked upon by just one person, that isn’t always the case).
Let’s say you’ve divided up the work in one of the projects. For example, one of you may have claimed responsibility for implementing a specific task in a project. Even if you understand that it is important to communicate your progress, it can be helpful to use a concrete mechanism to track and document that progress. A common way of doing this is by using an issue tracking system, where you create a new “issue” for each concrete task that needs to be completed. The issue tracker then allows you to add comments to that issue, and have a single location to discuss anything surrounding that task.
Both GitLab and GitHub helpfully provide a built-in issue tracker in each repository. We explain below how to do this with GitLab, since that is the system used by most classes (we will include GitHub instructions in the future, but it should not be hard to figure out the steps on GitHub starting from the steps below).
Now, let’s say we wanted to create an issue to track the implementation of “Task 4” in a project. You would do something like this:
Create a new issue titled “Implement Task 4”: click on “Issues” in the left sidebar, and then on “New issue”. While it is tempting to leave the Description blank, it can be helpful to describe in a few sentences what you will do in this task, including a high-level description of the changes you expect to make to the code. Make sure you add yourself as the “Assignee” of that issue. You can also create “Milestones” to easily categorize issues by project (e.g., “Project 1”, “Project 2”, etc.)
Create a new branch in your Git repository to do the work for this task. You may end up with many such branches (for each issue), so you may want to decide on a reasonable naming scheme (e.g.,
Notice how the issue allows you to add comments. You should use these to log your progress in this task. For example, let’s say you push a commit that passes some, but not all, of the tests for “Task 4”. You should add a comment that specifies what progress you’ve made, what tests are passing, and what remains to be done for the remaining tests to pass.
Similarly, you can reference issues from a commit message, simply by using the
#symbol (e.g., to reference Issue 42 in a commit message, just include
#42somewhere in your commit message). This will make the commit show up automatically in the issue, which is very helpful to easily access the exact code associated with a task.
Once a task is completed, close the issue. While you can then merge the code into your
masterbranch, we suggest you do a code review before doing so.
Let’s say you just finished implementing “Task 4”, and have, by way of doing so, become an expert on everything involved in implementing that task. Your partner, unfortunately, will know nothing about it, except at a very high level. One way to ensure that you are both familiar with the entire implementation of the project is to systematically review each others code. More importantly, doing this can help you catch bugs that you may have missed and will also help you get comfortable with giving and receiving feedback.
A common mechanism to handle this process is to take the code you produced
as part of an issue and create a pull request or merge request (GitHub uses
the former term, while GitLab uses the latter). A merge request is a request
to merge a branch into the
master branch, typically requiring a
code review from another person (in this case, your project partner) before
the code can be merged to
master. Ideally, this will ensure that
master branch stays relatively “clean”, in the sense of never containing
any work in progress or any broken code.
Once a branch is ready for review by your project partner, you can create a merge request by doing the following:
Click on “Merge Requests” on the left sidebar, and then on “New merge request” Note: If you recently push a branch, GitLab will helpfully suggest that specific branch, and you can just click the “Create merge request” button for that branch instead.
If you clicked “New merge request”, you will need to choose the source branch (the branch you created for a specific task) and your target branch (typically the
Once you do this (or if you clicked “Create merge request”) you will be shown a form similar to the one when you created an issue: you need to provide a title and description, but you should assign the merge request to your partner, not to yourself.
When reviewing a merge request, here are some things to look out for:
Read through the code, and make sure you understand what it does. If anything is unclear, add a comment in the merge request.
Is the code adequately documented, and does it follow the style guide? If not, add a comment with a list of the things that should be changed.
Does the code pass all the tests it’s supposed to?
Don’t shy away from asking for changes in the code you’re asked to review! As a reviewer, you’re not supposed to just rubberstamp your partner’s code. If you see something that should be changed, point it out in a positive and constructive way.
Once you’re happy with the code you’ve been asked to review, click on “Close merge request”. This will merge your code into the target branch.
When things go wrong
While the suggestions and tips in this page may help you have a productive and rewarding collaborative experience in the course projects, you may still hit some bumps in the road. A common issue is feeling like your project partner may not be as invested in the project as you are, or having your project partner miss specific goals you both agreed upon.
While it is easy to think your partner is being lazy or unengaged, and that you’re the one who’s doing most of the work, we encourage you to avoid that mindset. More often than not, when two people don’t work well together, it turns out that no single individual is to blame: maybe it turned out you each had different working styles and did not work through how to harmonize them, or you were not checking in with each other often enough and did not catch potential issues early on (and those issues instead blew up right before the deadline, which can generate a sense of resentment as you deal with both finishing the project and dealing with what you perceive to be a sub-par project partner).
In fact, if this is your first time working in a team, it is perfectly normal to not get it completely right on your first try! So, if you feel like your collaboration is not being as productive as it could be, approach it as an opportunity to learn how you could improve the way that you work as a team. Here are a few things you may want to discuss if you feel like your work together isn’t going as smoothly as you hoped:
In general, keep the discussion positive and start by going over the aspects that worked well. For example, try to make statements like “I really enjoyed when we did X” or “It was really helpful when you did Y”. If you can identify aspects of your partnership that worked well, you will want to nurture those aspects as you move forward.
If one of you did not meet a goal you agreed upon, don’t try to figure out who is to blame. Discuss why that goal wasn’t met: was the goal too ambitious? was it not clear what exactly you had to accomplish? did you get stuck at some point and didn’t ask for help? All of these can help you improve your goal-setting in future projects.
If you feel like you’re not communicating enough, see if there is a root cause, instead of just making blanket statements like “You need to reply to my messages sooner!” For example, did you both agree to use a given messaging platform to stay in touch when it turned out that one or both of you don’t actually use it that much? Have your schedules changed since the start of the quarter? Did you agree to have in-person meetings, and find yourselves having trouble sticking to specific times?
Of course, they may sometimes be situations when your project partner is really not doing any work. If you feel like you’ve made a good faith effort to address the issue with your partner, and they are unresponsive to your concerns, you should then bring this to the attention of the instructor.
Learning more about working in teams
This page aims to provide some concrete tips and suggestions on how to successfully work with others in a software project, but it really only scratches the surface of this subject. Working in teams is something you could write an entire book on… and someone did! If you’d like to learn about other ways to work effectively as part of a team, we strongly encourage you to read Debugging Teams: Better Productivity through Collaboration, written by Brian Fitzpatrick and Ben Collins-Sussman (SB’94)