How to Build a Software Engineering Culture Where Everyone Can Thrive
The media loves to tell war stories about sexism, racism, and other forms of prejudice in the tech world. While shedding light on systemic problems is good journalism, for people interested in tech careers, reading story after story about the culture problems in tech can feel at best like the familiar sting of stereotype threat, and at worst like a menacing professional liability. But the good news is that tech industry culture is not inherently bad- some of it is great, and it is both possible and straightforward to create a software engineering culture where everyone can thrive.
Bad software engineering culture is inefficient — in addition to pushing out the 75% of humans who couldn’t ever fit the techbro stereotype, thus making the industry artificially less competitive — bad software engineering culture is also often a culture where only a few dominant engineers are actually productive while the rest feel confused or minimized, and a culture where huge teams can spend years and millions of dollars accidentally solving the wrong problems or building the wrong products. The more visible problem of a hostile workplace is just easy to measure evidence of the co-morbid problems of bad organizational culture and organizational inefficiency.
Fortunately, workplace culture is very malleable, and you can impact it in big and small ways. If you find ways to improve software engineering culture at your place of work, chances are you’re not just improving the environment for yourself, you’re improving it for everyone. And as a result, everyone will not only be happier, but also more productive.
Tech at MoveOn powers organizing at scale. The work we do is important, and how we do this work is just as important. My tech team is not only building tools to mobilize millions of Americans, amplify people power, and hold our government accountable, but we’re doing this with a team recruited via equitable hiring processes, and we’re constantly auditing and improving our software engineering practices and processes to make sure everyone on the team has a voice, and everyone is set up for success. This is difficult work that is absolutely worth it, and when we get our team processes right, we reap huge rewards as we efficiently and nimbly build the right tech at the right time, scale our systems and processes, and work together with the rest of the organization as technical thought partners. We reject the idea that the current tech stereotypes and cultural expectations are inevitable, and we are a better team as a result.
So how do you actually build a good software engineering culture?
Key Ingredients of a Good Culture
Equitable and efficient software team culture takes into consideration the composition of your team, operationalizes processes and makes norms explicit, sets all team members up for success, and holds the team accountable to its stated goals.
Here are five key values for making this happen:
- Acknowledge the team’s diversity of experience
- Clearly state communication and collaboration norms
- Create safe spaces for learning and asking questions
- Explicitly onboard all team members into new projects
- Create a culture of accountability
Any combination of processes that implement these values will likely work for your team, but not all strategies are the right fit for every team and every project and every organizational context, so it’s important to both try different strategies and also regularly debrief with your team about what’s working and not working. Let team members negotiate for process changes, and stay flexible.
Next we’ll break down what each value really means, and I’ll share a sample of strategies I’ve used that implement each value.
Acknowledge the team’s diversity of experience
Most software engineering environments will include people with different experience levels, and experience will vary across many dimensions: actual amount of time spent coding, years of experience in a particular language or framework, experience with a particular company size, type, and industry. Each language, framework, platform, industry comes with a set of expectations about what the order of operations for a project should be, which problems should be easy vs hard, which architectural patterns are considered standard, and what norms exist around documentation, debugging, and deployment. Every single difference here matters, and should be considered when setting communication and collaboration norms. Unpacking each team member’s experience and assumptions will make decision making clearer, and will smooth over potential misunderstandings.
Strategies for acknowledging your team’s diversity of experience:
- Team Retreats: when your team’s composition changes, it’s helpful to carve out a day or two for everyone to meet each other, share experiences, and reset norms
- Team Constitution: craft a set of values and norms together that you ratify as your team’s constitution. It’s helpful to keep the language direct, keep the list short, and stay focused on values vs specific projects. Prompt each team member to share stories about why each value is important based on their experience.
- Facilitated opportunities to share experiences: you can do this as a part of a team retreat or a regular team building meeting. The prompt doesn’t matter as much as the facilitation. Facilitation is key so everyone (both introverts and extroverts, both junior and senior engineers) has a chance to speak and be heard. Some example prompts I’ve found to be generative: “What was the hardest project launch you were ever a part of?” “What were the best and worst management experiences you’ve ever had?” The facilitator should call on everyone in the meeting and give them each the same number of minutes to speak, and to answer questions about their experience.
- Unpack software estimation reasoning: your team will invariably get into discussions about how long a task will take, and will sometimes disagree. When this happens, it’s helpful to explicitly unpack assumptions about what parts of the task or problem are believed to be complex, why, and what past experience this is based on.
- Software engineering learning plans: create a learning plan for software engineers who wish to broaden their software engineering skills, in a supported and structured way.
Clearly state communication and collaboration norms
Write down and formally agree to how team members will work together on a project, how tasks will be managed, and how finished work is approved and incorporated. If you don’t explicitly state these norms, your team and project will develop norms anyway, but these implicit norms may work for some engineers and not others, and the norms may be more clear and accessible to those who identify as your organization’s dominant culture, and more confusing to those who don’t. It’s better to just be explicit.
Strategies for setting communication and collaboration norms:
- Project kickoff meetings: Team Constitutions help teams decide how to work together in general, but it’s also helpful to have project kickoff meetings where teams decide how to work together on this specific project. This should cover how tasks are managed, how tasks will be ordered, who picks up which kinds of tasks, how and when to ask for help, when to work together, how changes and finished work should be approved an incorporated.
- Daily Standup Meetings: this is a basic tenet of most Agile software management strategies. Prompt each team member to report on what they did yesterday, what they will do today, and whether they need help with anything. Keep the meeting short- under 15min if possible. It’s important to do this in person or in a video meeting (vs phone) so team members can be aware of visual feedback and associated social dynamics that are a part of team members holding each other accountable to team goals. I’ve found it invaluable to also have a Daily Standup agenda doc where everyone writes their updates in reverse chronological order ahead of this daily meeting, and this doc accrues all the updates over time. This helps introverts gather their thoughts ahead of the actual meeting, and creates a scannable papertrail of work done that comes in handy when preparing for evals or catching up a team member who missed a meeting.
- Regular opportunities to check in on process: sometimes engineers get left behind or frustrated with other engineers or a process or the way a project is going. It’s better to head off these frustrations directly with clear communication that includes the whole team, and create low stress opportunities for sharing this feedback. At times, I’ve found it helpful to include “Process Check” to the list of items each team member reports on in Daily Standup Meetings. At other times, I’ve found it helpful to do this “Process Check” step in sprint planning meetings every few weeks. Whenever the “Process Check” happens, it’s helpful to not just talk about but also write down proposed process changes so there’s a shared agreement to refer to if there is future confusion.
- POPs for meetings longer than 15min: It’s easy to fall into the trap of Death By Meetings when there are big decisions to make as a team or a chaotic situation to navigate. One way to avoid excessive meetings is to allow anyone to propose a team meeting, but make sure the meeting has a POP: Purpose, Outcome, Process with an agenda that has been set at least a day before the proposed meeting. This helps keep the meeting focused and actionable, and sharing the agenda ahead of time allows folks who are interested to prepare to attend and folks who are not to opt out.
Create safe spaces for learning and asking questions.
Everyone learns by making mistakes and getting it wrong a thousand times before getting it right. You could call this “tinkering.” The beauty of coding is that you can get stuff wrong and then eventually right at the speed you can think, with little or no physical cost. But as you explore a new problem space, different people (based on experience and personal preference) may be searching the tree of possible solutions more broadly or more deeply, and may have developed mental models that allow them to have a more compact search space than others for particular problem spaces. Engineers start to make each other smarter and faster when they feel comfortable sharing their problem solving processes and steps. This naturally involves a whole lot of feeling dumb and asking “dumb questions” (none of which are actually dumb), and so being able to do this at all requires a significant amount of trust. Trust can be hard to come by in high stakes jobs where ego or reputation is at stake and everyone is trying to live up to some kind of “genius engineer” archetype. Managers should explicitly create safe spaces by declaring there are no dumb questions, model this by asking the “dumb” questions, make structured space for collaboration, and reward those who proactively collaborate. If you don’t do this explicitly, probably some engineers on your team will create these safe spaces, but not everyone will automatically be included.
Strategies for creating safe spaces
- Regular 1–1s: Managers should have regular 1–1s with staff, preferably a half hour once a week. Managers should encourage staff to drive the agenda of these meetings. It’s helpful to maintain a shared 1–1 agenda doc for this meeting where staff can add items ahead of time as issues come up. This agenda doc also serves as a helpful papertrail when writing evals or reflecting on past challenges and opportunities.
- Regular 2x2 feedback: The Manager and the staff member each write down and share two things the staff member is doing well, two things the staff member could do better, two things the manager is doing well, and two things that could be better. This can be a helpful check-in point on staff performance, and also a safe space for staff to give managers feedback. No matter how friendly or approachable you may be as a manager, most staff will hesitate to give you negative feedback at all unless you invite them to.
- Unpack Jargon: normalize the practice of flagging jargon when an engineer throws out an unfamiliar term or acronym not shared by the rest of the team, and prompt them to explain what the term means to the whole team.
- Planned Pair Programming: pair programming is a great productivity booster, and a great way for engineers to learn from each other. Instead of waiting for pair programming to happen organically between engineers who are already comfortable with each other, prompt team members to explicitly plan this on their calendars, and make sure all engineers have access to the pairing time they want. Also prompt engineers to negotiate the right unit of focus time for them (for some it’s 60 minutes, others 90 minutes, others 120 minutes), and the most productive time of day to pair.
- Explicit Mentoring Opportunities: give every junior engineer on the team the opportunity to have a senior engineer mentor, and explicitly include effective mentoring into the performance goals of the senior engineer. Encourage mentors to set up weekly meetings with their mentees and create safe spaces for asking “dumb” questions or clarifying processes or norms with a senior ally.
- Practice regular repeat-backs: when one engineer is teaching others a new framework, walking everyone through a proposed architecture, or onboarding members of the team into a new system, sometimes it’s easy for the listeners to shut down or get distracted. To keep the discussion active, after every 5 minutes of talking, regularly prompt listeners to verbally repeat back what was just explained. The performative nature of the verbal repeat-back forces the listener to prove to themselves they understand the concept, OR to articulate what additional info they need to understand. Normalize this when onboarding or doing project kickoff meetings and call on people randomly to do the repeat-backs to keep everyone paying attention.
- Encourage and model asking “stupid” questions: as a manager, people will carefully watch your behavior and tone, and model their behavior and social norms against this. So it’s important to model the above values in how you interact with the rest of your team, and in particular to model the ability to ask direct questions when you don’t fully understand something. This shows that efficient problem solving is always more important than ego or the perception of always being right.
Explicitly onboard all team members into new projects.
When kicking off a new project it’s important to unpack not just what work will be done, but why this work is important, and who this work is important to. Making sure engineering teams understand the “why” as well as the “what” can guide decision making when unexpected choice points emerge, and minimize the risk of spending time solving the wrong problems. And after kicking off a new project, it’s important to make sure everyone has what they need to pick up a task and immediately become productive on this task. If you don’t do this explicitly, some engineers on your team will hit the ground running and others will struggle with bootstrapping steps like setting up local development environments. Making these steps a prerequisite for starting a project ensures everyone will be able to hit the ground running.
Strategies for explicit onboarding
- Development Environments: make sure everyone on the team has a functional development environment before calling a project ready to start. Engineers young and old all struggle from time to time to get local development environments up and running, and this becomes a hidden cost in software project timelines. When this happens, engineers feel embarrassed and often avoid admitting they need help, by staying in a role that is peripheral to coding, or only doing pair programming with engineers who have working development environments. It’s best just to remove the potential struggle and shame and call this the work that it is, and then plan for front-loading this work by making development environment setup explicit and supported — something everyone does together, that isn’t marked off as “done” until everyone on the project has a working local environment.
- Guided tour of codebases: when starting or restarting a project, the engineer who knows the codebase the best should give a guided tour of the codebase, pausing for periodic “repeat-backs” from less familiar team members, rotating between members so that everyone is accountable for learning the codebase structure well enough to be able to explain it back.
- Debuggers: Once everyone has a development environment and a conceptual understanding of how the system works, everyone should install a debugger, and be able to trace execution through the system for a sample request or input. Being able to work locally and debug will ensure that when engineers start picking up tasks, they’ll at minimum be able to start these task on their own. This reduces frustration, and increases productivity and ownership.
Create a culture of accountability
The critical work of software engineering management is making sure your team is doing the right work at the right time in the right order, and a critical part of focusing on the right work is being connected to stakeholders in the right ways. Software teams have several stakeholders: each other, the larger organization, and users of the software they are building. Software team management processes should create accountability with all of these stakeholders.
Strategies for creating accountability culture
- Project debrief meetings: After a project is completed and launched, it’s important to hold space for a debrief meeting, and facilitate this so that everyone on the team has a chance to share their feedback. One helpful prompt I use for this is “SaMoLo: what would you do the Same of / More of / Less of next time?” Encourage team members to share feedback on both technical and process areas. This lets team members hold each other accountable to whether processes negotiated as a part of the Project Kickoff Meeting were followed.
- Software Process Accountability: code review and release processes, determined in Project Kickoff Meetings, also create accountability within the team, as do the Daily Standup meetings.
- Regular Demo Meetings: regular demos of project progress create accountability to the larger organization. We like to hold space for weekly demos open to all interested staff. This is motivating for the team because they get to show off their work, it creates a forum for capturing early stakeholder feedback, and keeps project work focused on iterative demoable deliverables when possible.
- User-centric metrics: create accountability to users of your software by doing user testing, and defining and tracking success metrics based on user engagement.
Why This Matters
Despite massive profits, the world of software engineering is currently pretty inefficient. 90% of software startups fail, and I believe this is in large part due to avoidable software project execution problems. 50% of big company software projects fail to launch on time, on budget, or at all. Being a year late or a million dollars over budget isn’t news to anyone who has ever worked at a big software company. Software engineering culture often labels managers as overhead or lower status than software engineers, which leads software engineers who could be effective managers to avoid this promotion path, and current software managers to have difficulty negotiating with and reigning in their own teams. Sometimes even openly caring about software engineering process can be stigmatized, in environments where cowboy coders are admired.
It’s demoralizing to work on a big software project only to see the deadline keep getting pushed back or the project cancelled. In the for-profit world, this is an inefficient waste of time and money. In the non-profit world, I’d argue it’s an unethical use of member donations. For software engineers, this is a waste of our valuable time, energy, and attention.
For both intellectual and financial reasons, it’s important to audit the culture of your work environment and look for ways to optimize and improve it. If you start by making your work culture more equitable, accountable, and fair, and a place where everyone can succeed, you’ll not only make software engineers happier, and software engineering more efficient, you’ll make the world more fair, by driving down the cost of software development, and removing discriminatory barriers.
Building a software engineering culture where everyone can thrive is not hard to do, but right now in a tech culture flooded with hubris, greed, ego, and ethical quandaries, this is a radical idea. I consider intentionally building an effective and supportive team culture to be an act of activism. Let’s make fair and effective software team culture the norm!