Infusing Empathy and Humanity into Code Reviews

As software developers, our work is constantly exposed to our teammates for review. This is a good thing! Code reviews (also known as pull requests) enable us to ship high-quality software. They also provide a real opportunity to teach and to learn from each other.

Sometimes code reviews aren’t so positive. Negativity starts to color our way of approaching feedback, and the same people we love working with can start to seem like antagonists and disgruntled critics. This is not so great. It can get to a point where we feel exasperated, apprehensive, and resentful whenever we’re facing the prospect of a new code review.

To engage positively in code reviews, it’s incredibly important to keep our empathy for our coworkers and our humanity at the forefront. We all care about learning and helping our teammates grow, and the words we use to facilitate that growth matter. If we can use the right words, the person we’re communicating with will see our true intent. The empathy and humanity we already have inside of us will come across loud and clear.

We asked Engineers at Textio for ideas about how we can improve our code reviews, both from the perspective of the reviewer and the submitter. The ideas are collected below.

As a Reviewer

As a reviewer, think about what it feels like to submit a code review. You’re excited to have found a solution, and maybe a little apprehensive of what your teammates will think! As you engage with the code, keep the following things in mind:

Understand what the submitter is looking for

Sometimes the person who submitted the code review is looking for a quick sanity check of their logic. Other times, the submitter is asking for a check for how their code connects with the code around it. Sometimes, the submitter is interested in general feedback, and sometimes they’d like help with a specific area of code. Understanding what the submitter is looking for can help guide your response – if they’ve already gotten the perspectives they need, you don’t need to cover that ground again! If you’re not sure what the submitter is looking for, just ask!

In-person is better

When there’s something complex, challenging, or difficult that you’d like to work through with the submitter, an in-person discussion is often better than a wall of text on the code review. Speaking in-person reminds everyone involved that there’s a human on the other side of our communications and gives us the chance to have a real-time back-and-forth about an idea. If you find yourself taking more than a minute to express an idea in a code review, usually that’s a good sign that you should just pull the submitter aside.

Don’t block unnecessarily

This one is simple – if the comments you have don’t block the code from being merged, go ahead and approve the code review. Approving the code review communicates that your comments are non-blocking and shows your trust for the submitter’s ability to make their own decisions. Remember to block a code review only when you feel it’s truly important for the submitter to address your comments. In larger reviews, it can be helpful to focus mostly on the critical aspects to avoid overwhelming the submitter with feedback at various levels of importance.

Explain the why

If there is something you feel is important to address before the code review is merged, take the time to explain why. What thought process got you to your suggestion? Why will addressing your suggestion make the code better? How could the submitter think about writing similar code into the future? If you’re just telling the submitter what to do without explaining why, your suggestion can seem arbitrary or just a reflection of your personal taste. Explaining why can also uncover the times when your suggestion is a personal preference!

Talk about what you love

As you’re reviewing a code review, remember to talk about the parts of the code you love. In general, most of the code you review will be good! When we focus on only the negative aspects it can have the effect of making the submitter feel unappreciated because they think that’s all you care about. The reality is you do care about their great code, so be sure to let them know.

As a Submitter

As a submitter, having empathy for your reviewers can help quite a bit. Your reviewer wants to get up to speed with your code quickly and give you the input you need to get your code merged! As you start to write code to be reviewed, keep the following things in mind:

Start the discussion well before submitting the code review

Most complex code takes some architectural thinking or planning before we write the first line. Sometimes there’s a difficult decision midway through as well. We’re careful to think of everything, but the reality is that usually no one person can hold all the context to make great decisions in their heads. When you start to gain a point of view on a difficult decision or architectural plan, often it can be a good idea to consult briefly with the people who will be reviewing your code. Bring them into a room and share your plan with them. Your reviewers will appreciate being consulted! Often they’ll have ideas that will change how you think about the problem. These ideas will result in your solution being better, and you’ll all walk out of the room agreed to the plan. Gaining alignment on your approach to the problem early will set you up for success and a smooth review process later down the line.

Give your reviewer the context they need

It’s 9AM on a Monday and you’ve spent the weekend away from work. You open up a new code review and you’re greeted by a wall of code. There’s no description or comments, so you sigh to yourself and start to parse through what the code is doing. We’ve all been here. As a submitter, giving your reviewer the context they need to do their job well can make a huge difference both to the quality of the review and the quality of their lives. As you put together a code review for submission, try to make the answers to the following questions clear to your reviewers by adding comments in the code or on the review itself:

  • What problem does this code solve? If there’s an issue page tracking the problem, link to that issue in the code review.
  • What kind of feedback are you looking for from your reviewers? Is there a particularly tricky area you’d like to get extra attention? Are you looking for something high-level or something detailed and thorough?
  • What alternatives to this solution have you considered? Why did you choose this path?
  • What have you already planned to do into the future in this area of code?
  • How have you tested your solution? What do you expect from your reviewers in terms of manual testing?
  • What, if any, documentation have you updated to reflect the changes you’re making in this solution?

Generally we like to have a template for our code reviews that summarizes these areas and helps us remember to include the right context in our submission.

For larger reviews, give an in-person overview

Even with all the context, sometimes a code review is just too large to quickly understand by yourself. As a submitter if you’re submitting a particularly complex or important code review it’s usually a good idea to preemptively set up a meeting to walk your reviewers through your code yourself. In this overview meeting, talk about how the code is structured, difficult decisions you made along the way, things you’re proud of, and things you’re interested in getting feedback on. Your reviewers will ask questions along the way and you’ll have the opportunity to answer them real-time rather than over the course of a few days via an extended textual back-and-forth. An in-person overview is a fantastic way to quickly get a room of people up-to-speed and ready to give you the information you need to get your solution shipped!

Conclusion

The ideas and guidance above really boil down to one clear idea: take care of your teammates in code reviews. Taking the time to think about setting our teammates up for success in their jobs as submitters and reviewers of code is something that helps all of us write faster, smarter software. By infusing empathy and humanity into our code review practices, we can make all of our lives a little more wonderful.

A Guide to Working with Max

Here are some honest, unfiltered things about me:

  • I have a high tolerance for conflict, and I’m not easily offended. You can say pretty much anything to me and I’ll take it in stride.
  • If I’m working with you, I hold you in the highest positive regard, always. I trust by default and I know I need to give you respect to get it back. At core, I deeply believe in you and your potential.
  • I’m driven primarily by growth and I’m obsessive about discovering things I could do better. I’m constantly thinking about my blind spots, and if you let me know about an area I could improve I’ll appreciate it (really!).
  • I grew up with three parental figures who were entrepreneurs and I started my own business early on in my career, so I value an enterprising, scrappy attitude in the people I work with.
  • I have a terrible memory that’s only supported by my rigorous list-keeping. If I forget something we’ve talked about, it’s likely because I didn’t write it down.
  • I have a weird/dark/sarcastic sense of humor, which can rub people the wrong way. If that’s not your thing, just let me know and I’ll turn it down.
  • Forgiveness is a core strength of mine. I’ll always forgive and legitimately assume the best intentions from people I work with.

What makes me grumpy:

  • I get grumpy when people I work with are indecisive for a long time. I’m deeply oriented around the question “what do we do now?” and I start to feel stuck if we can’t make forward progress after a while.
  • I get grumpy when someone I’m talking to has trouble going from abstract ideas to concrete actions for similar reasons. I’ll do my best to steer the conversation into next steps when this happens.
  • I hate being interrupted. It makes me feel like you don’t respect what I have to say and I shut down if it happens frequently.

What I’m working on:

  • I’m working on being more patient. I can get impatient sometimes, which usually gets triggered when I perceive there’s a risk to something I really care about. If you see me start to get impatient, please call me out on it and I’ll take a breath so we can refocus on solving the problem (saying something like “can we take a breath for a second?” usually helps a lot).
  • I’m working on getting better at taking complements. If you say something nice about me I’ll probably grimace, but I’ll feel good about it later.

I really appreciate it when my teammates do this:

  • Are open and honest with me about how you’re feeling. I see deep, two-way communication as the way we can learn to work together. Just try me.
  • If you hear me say something that sounds odd or wrong, give me the benefit of the doubt. Say, “When you say X, I hear Y. Is that what you meant to say?”. A lot of the time there’s a communication problem in a way I hadn’t anticipated and I’ll be able to rephrase in a better way.

Qualities I particularly value in people who work with me:

  • A deep commitment to openness and honesty in our work relationship.
  • The ability to break down large, ambiguous problems into chunks and display them visually. I’m a very visual person and this helps me understand solutions!
  • An entrepreneurial attitude of ownership of results, not just for your personal work or your team, but for the company’s success as a whole. The desire and ability to fix things when they’re wrong, even if it’s outside your normal work purview.

Some things that people might misunderstand about me that I should clarify:

  • I have an exploratory brainstorming style and I like to throw ideas out there and see what sticks. Sometimes people take these half-formed ideas as something I strongly believe in, but that’s usually not the case. I’m interested in your opinion and pushback regarding what I’m saying because I’m legitimately interested in working with you to find the best solution to whatever problem we’re discussing!

How I encourage people to do their best work and develop their talents:

  • I encourage ownership over all the results in your world.
  • I listen intently to where you want to grow and try my best to open up opportunities for you in those areas.
  • I try to strike the balance of getting you the right amount of ambiguity and autonomy for the things you work on. I want for you to feel challenged, creative, and empowered while we’re working together.

The best way to communicate with me:

  • I’m an extremely visual person. Charts, graphs, pictures, and lists are my preferred methods of communication. If we’re having trouble communicating, taking it to a whiteboard will help me a lot.

The best way to get to a shared understanding of something with me:

  • Start by listening to me and understanding where I’m coming from. Try to re-express my position so clearly, vividly, and fairly that I say, “Thanks, I wish I’d thought of putting it that way.” I’ll do the same for you! (For more on this idea I’d recommend checking out Rappoport’s Rules)
  • I have a strong aversion to Arguments from Authority – if you take the time to walk me through your decision-making journey from start to finish I’m extremely likely to engage constructively with your idea!

How I like to give feedback:

  • I like to give feedback in-person and as soon as possible. I like to get your unfiltered reaction to what I’m saying because it’s my goal that feedback I give you shouldn’t be a surprise. If I’m surprising you with feedback then that’s a flag to me that I need to do a better job of being open and honest with you.

How I like to get feedback:

  • I like to get feedback in-person and as soon as possible. There’s one exception to this rule: if you don’t have time to dive into the feedback with me at the time, please wait until we have the time to break it down together.

How we build at Textio

When’s the last time you had a chill-inducing, unforgettable idea? Ideas are fragile things, and good ones are incredibly rare. Ideas also have power – the right idea can be the catalyst to change our lives, our company, and our world.

At Textio, our teammates bring unique, fresh ideas to their work every single day. A big part of what we do on the engineering team is build out those ideas, collaborate across the company, and create something that’s as true as possible to each idea’s spirit. Here are some of the principles we believe make Textio one of the best places to build as an an engineer.

We value people over process

Processes exist to serve people. At Textio, we work diligently to ensure all our processes are both valuable and flexible. If a process is tedious, dehumanizing, or is taking more time that it’s worth (see: granular time tracking) we replace it with something lighter that gets us a similar benefit. We believe that no process can replace human conversation, and we build our processes to encourage more discussion and collaboration in-person.

We know small, empowered teams build better

At Textio we hire people who are great at something, give them hard problems to work on, and trust them to be outstanding. To facilitate this, work at Textio is done in Squads. Squads are small teams of fewer than 9 people from across the organization that are empowered to solve a hard problem. Each squad starts with a specific idea that grows and evolves as the squad builds. Squads decide on a meeting cadence and a tracking system that works for them internally, which varies quite a bit based on the size and scale of their idea. Each squad has ownership of the results of their idea across the company, and they work to create the best overall results together.

Every week on Fridays, we give Squad Updates (or “squpdates”). Each squad takes the time to write a short summary of their week, which goals they’ve completed, and what they’re planning on starting next week. This lightweight process helps the entire company understand what’s being worked on and where we are along each idea’s journey.

We get lots of perspectives early

Ideas at Textio start small. Usually they’ll look something like a thumbnail and a few bullet points. This is the perfect time to get varied perspectives: when there’s still lots of ambiguity and things are easily moldable. At this early stage we start with a meeting between a business advocate, who is the person who knows the most about the spirit of the idea, and the technical lead of the squad, who can be any developer. These two collaborators work together to discover what kinds of people they’ll need to make the idea a reality. Who can help them see more viewpoints on the idea? What does the architecture of the solution likely look like? How can they execute in a way that plays well with how the rest of our offering works? What development talents will be particularly useful in building the idea? The technical lead and the business advocate work together to answer these questions and more.

As the solution for the idea comes into focus, more people join the squad according to what its members determine it needs to grow and thrive. Textio’s managers work hard to ensure all running squads have the people they need (and to give everyone the growth opportunities they’re looking for in their career). In this way, squads grow organically and develop in as broad a frame of reference as possible.

We aren’t afraid to change our minds

Despite our best efforts, sometimes we make a decision or build something that doesn’t work out. It can be as blatant as the code we’ve written not being flexible enough to fully realize the idea. It can also be subtle – sometimes we’ll build something and it doesn’t feel right yet. There’ll be too much friction in our user’s experience or what we’ve built won’t solve people’s problems as fully as we’d hoped. In these situations it’s important to be able to take a step back, rethink, rework, and rebuild.

Making the decision to scrap work, go back and rethink is incredibly hard. It’s hard because everyone believed we were doing the right thing – everyone was bought in and excited about what we were doing, and acknowledging we were wrong isn’t something that comes easily. Ultimately it takes everyone on the squad having the ability to set aside their ego and break through the sunk cost fallacy in order to value creating something awesome for our customers. I’ve witnessed squads do this again and again at Textio, and the level of patience, grit, and dedication to quality displayed by my teammates is a constant source of inspriation to me.

We make tradeoffs together

At Textio we talk a lot about tradeoffs. What can we deliver to our customers if we simplify this feature? What would it take to add an extra flourish to an experience? Could we take on some responsible tech debt to ship this idea faster and pay it down afterward? Questions like these are asked throughout the product lifecycle here, and we answer them as a team.

We use dates as a tool to help drive tradeoffs as we build. I’ve worked at organizations that use deadlines as a means to pressure developers to get more done or work overtime. This is an incorrect and incredibly harmful use of dates not just because our teammates get burned out but because the focus of deadlines is on the date instead of the idea. We think about dates much differently here.

We’ll start with a thought experiment asking, “what would it mean to deliver this idea by this date?”. Usually the answer involves a lot of collaboration between everyone on the squad, business advocates and developers alike. Are there features our customers don’t need immediately? Are there ways of building that might be faster? What would we be able to likely deliver by the proposed date? This thought experiment around dates isn’t a strict deadline but rather a way to focus us around delivering the most value quickly. No one needs to burn themselves out, and if we discover something we didn’t take into account initially we’ll just do the exercise again. We know estimates are difficult and by their nature can’t take into account everything that’s needed to deliver a project! Our ultimate focus is on quality, and we treat dates as a way to help us deliver the high-value pieces sooner.

Summing up

I love being an engineer at Textio. Building here is infused with cross-functional collaboration, focus on realizing an idea, and treating people like human beings. I believe our principles for how we build show up directly in the quality of our product. I’m incredibly proud of what we build every day, and how we work together to bring our best ideas to life.

What I Champion in Software Development

This post serves as a living collection of ideas. Some ideas, I agree with. I bring up these ideas in meetings and advocate for them, but I understand if a decision gets made the other way. The ideas I’m talking about in this post have grown far beyond that point.  I believe the ideas below are so crucially important to the success of a software development team that fighting for them daily is an obligation. These are ideas I champion.

Fail Early and Often

Teams can’t avoid trying new things because they’re afraid they might not work – it’s a philosophy that directly causes stagnation and stifles innovation. By making it OK to fail and by realizing that lessons learned from failure actively improve future work, teams can be opened up to creative and iterative change.

Spread the Knowledge Around

Siloing developers based on their perceived strengths and weaknesses is a terrible idea. The more I know about what my teammates are doing, the better I can do my job and integrate with theirs. Modern practices like code reviews, pair programming and lunch and learns help break up organizational silos and encourage teammates to obtain a wider view of the big picture.

Delegate Expertise

Having everyone know something about everything is great, but there is unmistakable value in having each person know a lot about one thing. Asking teammates to focus part of their time on small areas of knowledge that are critical to the team’s success means that each person feels ownership and responsibility over being an expert in their chosen field.

Iterate, Analyze, Change

Performing clearly-defined work in time-boxed increments, then empirically examining the outcome of that work and improving the process for the next increment is something that is fundamental to software development. The fact is, we as developers are not great at estimating more than a few weeks into the future. By building in constant re-evaluation we can make sure our plans are constantly in sync with reality. Scrum and Kanban are excellent tools developed through years of iteration, analysis and change that give teams a great starting framework for implementing this idea.

Don’t Go Backwards

Once a team has completed an iteration of clearly-defined work, the “done” status of that work should not change. If “done” work can suddenly become “undone”, then the entire understanding of what it means to be “done” is put in jeopardy. There is no way I know of to pin down done-ness other than writing good tests around the agreed-upon functionality. By continuously running those tests while adding new features, teams can guarantee their work stays done. The plethora of reasons testing is great could fill an entire post, which I intend to write at a later date.

Build Your Team Right

Hiring and firing are the two most critical actions of building a great team. We’ve all seen the impact one person can make on a team’s success, both positively and negatively. Taking the extra time to hire and fire right is the most face-slappingly obvious thing I’ve seen many teams gloss over.

Always be Hiring

In software development, the market is always tight. Talented developers are rare, and it can take a very long time to find someone when they’re needed. To counteract this effect, always be hiring. Have job descriptions for critical positions listed at all times, even when you don’t plan on hiring someone soon. This practice ensures you’ll always have the best chance of finding talent, with the worst-case scenario being that a good candidate doesn’t get hired. The cost of hiring the right person is minuscule compared to the potential loss of mis-hiring.

Communicate Reasons for Firing

When someone isn’t working well with your team, covertly letting them go under the veil of darkness sends a message that anyone could be next. Instead, openly communicate exactly why that person isn’t working out and make sure teammates understand that the team’s values are at stake if the person were to stay on. By getting buy-in from teammates on someone who isn’t working out, you can strengthen your core values and build trust with those who are doing a great job.

Row Together

This is a cliché saying, but no one can avoid the fact that teams who work together and communicate openly will always out-perform teams that don’t. I recommend The 5 Dysfunctions of a Team as a resource for anyone who is interested in understanding how to drive healthy collaboration in their own team.

Build Together

Nothing bolsters a culture of innovation quite like hosting regular events that encourage everyone to make their ideas a reality. Everyone at your company has great ideas (that’s why you hired them!), and spending a few days exploring those ideas tends to result in an explosion of creativity and benefit to the company as a whole. Here’s how I like to run these events:

  • People bring their own ideas, which must relate to the success of the company. Teams should be kept small.
  • Teams work on their ideas for somewhere between one and three days.
  • On the final day, there is a demo where teams present their work to a panel of judges who have been selected from across the company.
  • The winning team receives fabulous prizes and a small trophy.

These rules allow for a time-restricted, open-ended sandbox for everyone to implement their own ideas while still being asked to think about the impact of those ideas on the company as a whole. In addition, the team size restriction means people of varying specialties are more likely to work together (see: Spread the Knowledge Around).

Establish Standards

Making a documented set of standards for your team, be it for code styles, minimum test coverage, or something as simple as how decisions are communicated, helps bring your team together and make goals more clear. Newer teammates will use the standards to get up to speed quicker. The important thing to keep in mind is that standards are living – they must be adaptable according to the iterate/analyze/change cycle. When standards become stale teammates start to ignore them. Keep standards relevant and up-to-date.

Why I Work for Startups

In the tech industry, a “unicorn” is a company that has raised a round of funding that values the company at over a billion dollars. Every ambitious techie with an entrepreneurial spirit looks to these companies with a gleam of respect and envy in their eyes. In Y Combinator’s How to Start a Startup series, founders of unicorn tech companies warn potential founders against joining a startup for the wrong reasons. Movies like “The Social Network” represent startups as glamorous vessels of infinite potential and success, but in reality working for a startup usually boils down to a lot of hard work and stress.

Dustin Moskovitz, a co-founder at Facebook, lists four misconceptions about working for startups:

  • It’s glamorous
  • You’ll be the boss
  • You’ll make a lot of money and have more global impact
  • You’ll have more work flexibility

Dustin then moves on to dismantle the validity of these ideas one at a time (I’d highly recommend watching the video for the full explanation). Basically, if you’re looking for any combination of these ideas you’d be better off working for an established company. In the end, Dustin concludes that the best reason to join a startup is because there’s an idea so compelling, so utterly fascinating to you that you must work on it. To use Moskovitz’ words, the idea has to be “beating itself out of [your] chest, forcing itself into the world”.

While Dustin is absolutely right, I believe there are other good reasons to work at a startup. Many of these reasons are the same reasons someone would decide against taking the plunge, but they’re exactly what I’m looking for in my career.

Influence Over the Company’s Direction

While working for a larger company might net me more influence on the direction of the world, I can’t beat the direct influence I have on the direction of my startup. At a startup, things are in general much more fluid and open to change, from technological tools to the sales process. I crave responsibility in my work and having a significant effect on the success or failure of my company matters a lot to me.

Lots of Ownership

Working for a startup makes me feel responsible for the success of not only the projects I’m working on, but the company as a whole. At a startup I can craft (and take pride in) something I believe in. Realizing that no one’s going to make things work if I don’t rise to the challenge motivates me to push myself every day.

You Matter a Lot to Your Teammates

In a startup, I rely heavily on the dedication of my team, and vice versa. In larger companies it’s acceptable to have people who aren’t contributing or who aren’t a good fit. In a startup there is simply no room for anything other than a collaborative, ego-less, “leave nothing behind” attitude, and I can see that attitude reflected in everyone I’m working with. The feedback loop of passion and energy I get from my teammates at a startup is incredible.

It’s Hard

Simply put – I want to be challenged, and there’s no challenge quite like joining a startup. Living a comfortable life is not my goal. I want to be constantly striving to be better in everything I do. For me, working for a startup provides a strong impetus to improve myself and my company every day.