I’ve been teaching version control for more than a decade. The largest percentage of the folks who attend my in-person workshops are dealing with political issues, not technical ones. The issues vary, of course. Perhaps they are struggling to get their coworkers to see the light on how important version control is; perhaps they want to force accountability; or perhaps they have been nominated by the team to go figure out how to make sense of the mess that’s become the team’s workflow. No matter what the issue, understanding and dealing with the underlying social problems first can make learning and using Git a lot easier.
By the end of this chapter, you will be able to:
Identify roles within a complete team
Structure meetings so they have useful outcomes
Recognize key phrases from people who are working in an opposing state from what the team should be working on
Apply strategies to cultivate empathy and trust within your team
You must begin by understanding your team and the requirements for your software. By beginning from a place of trust and compassion, you will almost always find it easier to map out the Git commands necessary to accomplish your goals. By working with a trusting team, you’ll be able to help one another out when people get stuck with commands (and people will be more honest when they need help). And when people feel supported, and they understand the reasons why they need to use specific commands in Git, they will be that much more likely to make Git work for them, rather than simply committing a few commands to memory and hoping they’re all right.
On small teams you may have one person who performs many roles. It’s relatively easy to stay in touch with all of the daily activities of everyone on a small team. On large teams, however, you may have roles segregated into different departments. Those performing the user acceptance testing for your code base might never talk to the designers and developers who designed and built the product that’s being tested. Both types of teams can have their own challenges: someone who’s being asked to do too much without the right amount of context is definitely going to miss something, eventually. Having artificial barriers between teams will always increase tension between them. Fences do not make good neighbors in the development of code.
Have you heard the expression “begin with the end in mind”? When I build software, I am always building it for someone. Even if I think really hard, I can’t think of a product I’ve built that was just me tinkering. I’m not a hacker by nature. I was drawn to software because of what it could do for others. Every time I sit down to work on a problem, I want to be making a better experience for the user. I want to avoid regressions, and I want to keep my users safe. I want them to feel clever, and not stupid. If there are clients between myself and the users, I sometimes need to help shape how they think about the problem in order to accomplish their business goals, while maintaining the integrity of the experience for the end user. Each time we sit down to work, we should be starting with a description of a problem we want to solve for a user—literally a user story.
Next, in test-driven development, you will write the acceptance test so that you have a definition of how you will know the problem has been solved. Depending on how these statements are written, they may be used by an automated testing suite, a quality assurance (QA) team, or a peer reviewer. Working with the testing team ahead of time to determine the acceptance test makes it much easier for developers to know what the outcome of their work should be. Usually the test should be descriptive of the problem to be solved, not prescriptive of the technology that should be used.
Part of your testing process should include a security review. Larger organizations are very lucky to have dedicated security specialists. Bring these experts on as early as you can in the process and get them to teach you how to write secure code. If you have segregated QA, security, and development teams, bringing the teams together at the beginning can make the testing process that much more fun as the developers strive to provide perfect code, and the testing teams strive to break it.
If you are not responsible for your deployments, bring the operations team on board as early as you can as well. Ensure your development environment is as close as it can be to the final production environment. Ideally, you will have build scripts that can be used to automatically duplicate as much as possible. You may even choose to work with Docker and/or Vagrant to create an exact replica of your environment. Work with your operations team to create a configuration management infrastructure with something like Chef, Puppet, or Ansible.
Moving along the development stack, if you are using open source software, get to know the community that built the products you will be working with. We rarely encounter new problems. Someone, somewhere, has probably seen what you’re dealing with at this moment. Find mentors from within your code community, and offer to mentor others. Extending your team beyond the walls of your office building can make scary problems a lot less stressful.
Wherever you can increase collaboration between departments that have been isolated in larger corporations, you can reduce the time code spends sitting around doing nothing. Idle code costs you money in several ways: it may be preventing you from earning more money if it’s a new feature, or it may be preventing you from not losing money if it’s a bug fix. It’s also getting stale. The longer code has to wait for a review, the more likely it has deviated from the main branch of work. To bring the work up to date so that it can be released is an increasingly difficult task the more it deviates.
Finally, we look inward to our own team. A technical architect will be responsible for planning how a solution will be implemented. The architecture decisions should be documented, and shared wherever possible. The architect may also be part of your coding team. The coding team may be comprised of frontend and backend developers, a designer, and a project manager. I’ve occasionally worked with business analysts as well. If you are working in an Agile environment, you may also have a ScrumMaster and a Product Owner.
I prefer working in an environment where everyone is willing to roll up their sleeves and pitch in where necessary. Self-managing teams are often filled with trust and respect for one another. It’s a state that you need to build toward, though. Consensus-driven development works best for smaller, internal projects, but that doesn’t mean you can’t do your best to collaborate where possible. When I’m managing projects, I like for developers to choose the tickets they’re going to work on. It increases the sense of autonomy, and lets the developers take a break from specific tasks if they need to. I’ve also found, however, that some people actually prefer to have their tickets picked for them.
There is no single right way to structure every team or manage every project. The trick to a motivated, cohesive team is to respect each of the individuals on the team and, where possible, to optimize the process to suit their preferences.
Everyone on your team will have a preferred way to work. Different ways of working can be perfect for different situations. There’s no right way to do things, and being able to accommodate differences will actually make your team more robust, if you can share the strategies of what makes each person productive. I know I’m always looking for little ways to work in a more efficient manner, and I love to hear about what makes people able to really sink their teeth into a problem.
Several years ago, I was exposed to a leadership training program, Lead and Succeed in 4 Dimensions, by Bob Wiele, which described a series of thinking strategies. This program helped me to identify why I enjoyed some types of activities so much, while others left me drained. It also taught me a lot about how to structure meetings and interactions to get what I needed to proceed with my own work. The system works best if everyone on the team is aware of the language, but it’s something you can take advantage of without having to convince others to participate. It breaks thinking into three dimensions: creative thinking, understanding thinking, and decision thinking. A fourth dimension, personal spirit, is used to indicate how likely a person is to engage—I think of it as a volume control, or modifier for those of you who are into role-playing games.
Individual preferences for different thinking strategies can derail teams quickly. If I’m trying to brainstorm how to solve a merge conflict in Git, and you tell me I shouldn’t have used rebase, we’re at odds in the conversation. I’m trying to use my “green” thinking to go through a problem, and you’ve just used your “red” thinking to stop the conversation. Being aware of these preferences can help us to have stronger collaboration while building new features, more productive code reviews, and overall, a healthier, happier team.
One of the easiest places to introduce the concept of playing into and setting aside preferences is in meetings that explicitly take advantage of these three dimensions. Focusing on the outcomes of the meeting can help identify to people which thinking strategies to employ during the meeting, which can then carry over into code reviews, and supporting teammates who have procedural questions about how to use Git, or more general implementation questions about the product you’re working on together.
Let’s review each of these thinking strategies in a little more detail.
A creative thinker’s greatest asset is the ability to find unpredictable solutions to problems. Left unchecked, a creative thinker can sometimes spend too much time thinking about different ways to do something, instead of just committing to one idea and getting the work done. Creative thinkers:
To see an alternative future (whether it’s good or bad). This is useful for long-term strategy work.
To pivot a little bit away from the current situation, or to see the current situation from a different perspective.
This is useful for muscling through a problem. Brainstorming is almost the ability to doodle through a problem. It includes a constant action without self-censorship.
Where brainstorming takes “muscle,” flash of insight thinking happens when you’re not thinking about the problem. It happens when you’re out for a walk, or in the shower.
To question the status quo. The rebel; the child who points out that the king is not wearing clothes.
To ignore distractions and focus wholly on a given task. From this uninterrupted flow, you are able to get deeper into a problem and understand it more fully.
You can recognize creative thinkers from their key phrases:
“Can we try …”
“I know we’re done, but what about …?”
“OMG! I just had this great idea …”
“Have you thought about doing it like this instead?”
By developing creative thinking on your team, you can generate entirely new ways of approaching problems, allowing you to improve your workflow and solve bigger problems.
The next type of thinking is understanding thinking. It can be broken into two sub-categories: understanding information (analytic), and understanding people (compassion). The analytic thinker’s greatest asset is the ability to see patterns and bring clarity to a situation. The tech industry tends to attract people who enjoy working with these thinking strategies. Analytic thinkers:
Survey the environment to gather as much information as possible.
Sharpen the understanding of a situation by gathering information and asking questions.
Organize data, people, resources, and processes in meaningful and systematic ways.
Sense and connect with the emotional dimensions in a situation.
Show compassion for another’s thoughts, emotions, and situations.
Select the appropriate emotional and verbal language to get the true message across to the receiver.
You can recognize analytic thinkers from their key phrases:
“So what you’re saying is …?”
“Just to clarify …”
“Can you tell me how …?”
“Is this related to …?”
“So I made this spreadsheet …”
“That must feel horrible!”
Finally, we have the “buck stops here” thinking strategy: decision thinking. Someone who favors “red” thinking hates talking around in circles forever. They want a quick decision so they can move on to the action! Decision-making skills help teams get to the real root of the problem, and then decide how to proceed. A decision thinker’s weakest point is lack of patience. They often want to jump ahead before the creative thinkers have had the necessary time to suggest the best possible solution, or before a careful analysis has been completed. Decision thinkers can often be misinterpreted as being negative. They aren’t. Using their ability to cut through the weeds to find the best solution is invaluable. Decision thinkers:
Determine the essence, or most critical part, of a problem.
Reach a logical decision, or resolution, about the best way to proceed.
Pose questions to eliminate inferior options and poor quality information in order to critically assess and ensure the best decision.
Rely on experience to guide decision making and problem solving.
Rely on personal core beliefs about what is good or bad, right or wrong.
Rely, not on information, but on a hunch and deep instincts as a guide.
You can recognize decision thinkers from their key phrases:
Nearly my entire career has been spent working on a distributed team where my co-workers were not in the same office as me. It is a rare treat when people are at least in the same time zone as me. This has given me some excellent communication habits that I often take for granted. If you are already working with a prescribed methodology, you may have an established pattern of meetings that you use to move your project forward.
Your project, and each of the component parts within the project, should have an opening sequence, the bulk of the activity, and a wrap-up. This open-engage-close sequence is also described in great detail in the excellent book Gamestorming by Dave Gray, Sunni Brown, and James Macanufo (O’Reilly). It’s also used by teachers in the classroom: a teacher will first tell you what you’re going to learn, engage you in the learning, and then provide you with a summary of what you’ve learned.
All the way down to the planning of meetings, you should have this pattern in mind: start, engage, conclude. This becomes most apparent in meetings. Too often I see meetings with a general outline of topics, but not the intended outcome for the meeting. For example, if you are at the beginning of your project, the team might engage in ideation meetings, where your creative thinkers will be most engaged and productive:
Agenda: Ideation Total time: 45 minutes
Identify the crux of the problem (10 minutes)
Brainstorm solutions (25 minutes)
Structure ideas (5 minutes)
Identify top three ideas to test (5 minutes)
Identifying the outcome for a meeting ahead of time can be as simple as needing some free-flow time to discuss a problem.
The beginning of a project is a chaotic time, especially if you are bringing together a new group of people who wouldn’t normally work together. If at all possible, have a collocated kickoff meeting with everyone present. This can be incredibly expensive from both a time and money perspective if you are a distributed team.
Ideally a kickoff meeting is conducted face-to-face. If this is not possible, try to have people in as few places as possible, and connected through a video call.
By having everyone in the same place at the same time, you can take advantage of a shared experience. You can engage in kinetic (motion-based) processing of the information through whiteboards, flip charts, and sticky notes. There’s something really gratifying about being able to see your collective decisions, which helps motivate the team into working on the project.
Once the project has begun, you will want to continue meeting with your team regularly. It is very easy to hide when you are working on a distributed team. Falling behind can be an embarrassing and often compounding problem. Over-communicating is a great habit to get into, but that doesn’t mean wasting all of your time in meetings. A successful team will only meet to achieve very specific outcomes. I like working in very tiny increments of one-week sprints. It’s very hard to hide problems with such a small unit of time. It’s not about micromanaging, though. It’s about trying to achieve a consistent velocity—or flow. Each of these meetings has a specific project-focused outcome:
As a project manager, I’ve found there are two types of workers: those who are ready to jump in and take accountability for the work that is being done, and those who prefer to have work assigned to them. Those who prefer having work assigned to them are often looking for help in identifying which tasks they can succeed at, and which tasks have the highest business value to be completed in the context of the project as a whole. You may choose to do your sprint planning as a group, or you may find that sprint planning is less time wasteful if it is done among a smaller group of client-facing team members and senior developers.
These meetings should happen several times a week at the same time each day. The outcome of this meeting is a list of “promises” that team members are making regarding their work. People should not just answer “what are you working on today?” but “what are you expecting to hand in before the next time we meet?” This should be a “no shame; no blame” round robin with each person taking not longer than three minutes for their update. Larger, specific problems can be discussed in a follow-up meeting. In Scrum parlance, these commitment meetings are referred to as “stand-ups” and are conducted with the participants physically standing up. I find the term “stand up” doesn’t push enough accountability onto a team that isn’t trained in Scrum. Use whatever term works for your team, but make sure you are extracting valuable information from the meeting.
Any problems that need further discussion than the commitment meeting will allow should have a follow-up deep dive. Ideally your team will use a calendaring system, such as Google Calendar, where people who need help can review the schedules of their coworkers and simply book an available time to have a follow-up conversation. Generally I have blocked off one or two deep dive time slots of 45 minutes each week immediately following two of the 15 minute commitment meetings. Only the affected people need to attend to the deep dives, although everyone is welcome.
Once a week, the team should get together to show off their work. During the demo, each person who completed work should list the ticket number he or she was working on, and show the outcome of that work. Having this demo once a week encourages an “always be finishing” culture, which breaks work into small, doable chunks. This meeting can also be a great opportunity to see the site with fresh ideas and identify bugs that might need to be documented for fixing later, as well as discuss any necessary refinements to the process for the upcoming work sprint. Depending on the cohesion of the team, and the level of communication throughout the week, you may find these meetings to be unnecessary. If, however, you are seeing an increase in incomplete features passing through code review, or you find great work going unrecognized, or you find your team isn’t reaching out for help often enough, it may be appropriate to introduce weekly demos to your team. Google Hangouts and GoToMeeting work well for this type of meeting.
At the end of each sprint, you should assemble with your team to discuss the process of working together. Identify things that are working well, and parts of the process that could be improved. One set of questions I have seen used effectively has each participant answer the following prompts about the project: I wish; I want; I wonder. This meeting should be restricted to the core team. Its length may vary, but plan to spend about an hour for a small team.
If you are a distributed team, you may also want to have a few scheduled social calls. Lullabot, a wholly distributed company of approximately 50 people, adds the following nonproject calls to its schedule. The aim of these additional meetings is to develop a greater empathy between staff members:
A weekly one-hour call where a lottery of staff members are given up to two minutes each to talk about what’s happening in their personal and work life. When the company was smaller, each person was asked to speak on this call. As the company grew in size, the lottery system was implemented and the one-on-one calls were added.
For the most part, these calls are conducted over a voice-only line, which also allows staff to use the call time to multitask (loading the dishwasher; or even time outdoors for those with good cell phone service).
When you are working in a distributed team, it becomes much easier to think of people on your code team as “resources” and not as human beings. It takes a very conscious effort to cultivate relationships and to develop trust among the team. A team that is able to trust one another, that is not fearful, is a team that will be able to play more with ideas, and will have greater capacity for finding appropriate and creative solutions to tough problems.
The first step to improving the empathy on your team is to care just enough about the people you work with. You don’t need to become everyone’s therapist, but taking the time to talk to people about nonwork things is a good investment of your time. If you are perceived as being a caring person, people will also like you more, which will improve the trust between you and the other person. As a technical project manager, I’ve often been asked to lend an ear to someone as they talk through a problem. My naive understanding of the problem as they bring me up to speed can force the focus back onto the basics, where the solution often lies. But those conversations are rare with a new team—I must first earn the trust of the individuals on the team (that I won’t judge if they don’t know the answer; and that I can help to focus attention instead of just typing while they talk).
There are a few key tips to caring “just enough”:
Ask people questions about what’s happening in their life; about interesting challenges they’re working on; about what they’re enjoying (or hating) about the project you’re working on together. This isn’t a gossip session! This is about connecting with the people you’re speaking with about their lives.
When you talk with people, listen wholly. Do not multitask. Listen to what the person is saying, and listen completely. Do not cut in, unless you are confused and need to clarify. Some people are natural storytellers and have the capacity to go on. And on. For these folks, you might want to schedule a time so that you have a predetermined finishing point.
If someone tells you about their life, circle back with them to see how that story has progressed. Is their daughter still teething? How’s that cold doing; feeling better today?
I like to think of this list as “Empathy for Beginners”. Everyone can, and should, manage this small amount of connection with the people they’re working with.
These meetings can be a prime time to talk about what worked, and what can be refined. They should also be used to clean up any templates that have been used during the project to make them reusable in future projects. The closing activity for a period of work should always be a no-shame, no-blame event where people are able to talk about things that didn’t go well. Only very rarely do I regret my decisions as a project manager. I rely on my team to help me to make the best possible decision with the available information. So in retrospect, I find it quite easy to avoid the “shoulda coulda” temptation. What I do try to do, though, is to identify the patterns to watch out for in the future. In other words, to discover ways we could have altered what we asked in meetings to get a different set of information available to us (which might have caused us to make better decisions for that type of project in the future).
From a version control perspective, the end of the project is also a great opportunity to find your favorite tickets and document the characteristics of what made them excellent. Perhaps there was a new way of structuring the information that you’d like to be able to reuse. Take a peek in your Git repository as well, and look for especially good commit messages that you can have as examples in your documentation for future projects.
If you are absolutely brand new to distributed version control, there is a set of terms you will see throughout the rest of the book. These terms are easiest to understand in the context of a simple developer workflow.
Each developer has a local copy of a repository. This is, at its core, a standalone copy of the history of changes made in the project. In order to share changes, developers will typically publish a copy of the repository to a centralized code hosting system, such as GitHub. Although, as you will see later in this chapter, there are other ways to share code.
From the central copy of the repository, developers will create a copy of the repository that they can make changes to. In Git parlance, this process is referred to as creating a clone, although this process can also be referred to as forking.
When cloning a repository, software developers may choose to make their copy of the project private or public. A private repository makes a quiet decision to not encourage people to look directly at this copy of the repository, and instead only look to the main project for officially accepted changes. A public copy of a developer’s repository, on the other hand, is available for individuals to contribute to directly. This is a more open approach to software development, but may cause confusion about which copy of a repository ought to be the starting point.
It’s only through project governance that one repository for a project is decided to be the most important version. This is because every repository can accept changes, and share its changes with others. The relationships between projects are not fixed in stone. You can create a web of relationships between different copies of the repositories, or a more linear chain. Generally, though, the official version of a software product is referred to as being upstream of the current repository. For example, my blog is created with Sculpin. I cloned the official release of the software and make changes directly to the repository to write blog posts. If I wanted to incorporate the latest changes to the software, I would be incorporating the upstream changes.
For long-time open source software developers, the term fork is loaded with the frustrations of a split community where a group of developers decided to “fork the project” and take it in a different direction. Forks are simply a divergence, like a path in the woods, or like my Great Granny Austin’s butter tart recipe. Each branch on a forked path leads in a different direction. Or, in the case of the butter tarts, the addition or omission of currants. You can read my family’s version of a forked recipe in Appendix A.
Within a single repository, I can store different versions of the project. These in-repository changes are tracked via branches. To switch from my current branch to another one, I will check out the branch I want to switch to. (In my head I say, “This is really cool! Check! It! Out!”) Before switching, Git will force me to deal with the uncommitted changes by either committing them, stashing them, or discarding them. The commit process will permanently store my changes to the repository, whereas stash will temporarily shelve the changes, allowing me to pull them off the shelf and reapply them later.
Knitters, quilters, and other fiber artists will often refer to having a stash of yarn or fabric. When starting a new project, we might “shop the stash” instead of going to the store. Those of us who have a lot of stashed supplies may talk about having “achieved SABLE” (Stash Amassed Beyond Life Expectancy). I think this analogy works well for Git’s stash, and just like in crafting, I recommend pruning the stash regularly to look for moth damage. If you are a knitter, you may enjoy Git for Knitters.
The process of incorporating and publishing changes uses the following set of commands. I pull my changes from the remote repository to automatically incorporate them into the repository. This procedure fetches the new changes and then merges them into the tracked copy of the local branch. At any given time, I work on a local branch within my repository. If I want to share my changes with other developers, I commit my work to the repository, and then push my branch to the remote repository.
One of my favorite things to do is to work with a broken-down, burnt-out team, to help them find a new way of working together in a fun and creative way. It’s not always easy, because broken teams always have at least some degree of mistrust. Sometimes there are tears. But the rewards are huge when it can come together:
A trusting, empathetic team is more likely to help its coworkers with the specific Git commands necessary to get the job done.
Preferences for different thinking strategies can derail progress. Ensuring the right strategies are being used at the right time can reduce friction, and make work faster and more fun.
By having transparency around your work, and by including relevant stakeholders at key points, you may be able to gain faster deployments by reducing the time needed to test code, and by reducing the number of bugs found.
In the next chapter, you will begin to sketch out the governance for your project repositories.