DEV Community

Cover image for Software engineering culture: mindset, teams, and action
Vincent Burckhardt
Vincent Burckhardt

Posted on • Originally published at bitsofrandomness.com

Software engineering culture: mindset, teams, and action

How anticipation, empathy, and team structure shape engineering culture, and how AI amplifies it.

This year, more than most, made me think about team structure, and through that lens, about engineers and people more holistically. The patterns I've observed over the years keep sharpening as I see them repeat: anticipation and empathy distinguish how engineers approach problems, team structures affect delivery speed, alignment with user needs, and ultimately project success. These facets of culture matter more than most realize.

The mindset difference

A pattern I've seen across engineering teams: certain engineers deliver multiples more value. The multiplier isn't in features they ship. It's in how their work compounds: making future development easier for other contributors, improving overall quality, preparing the codebase for future needs. When I recently came across the term "10x engineer", it resonated with my experience, though not in the way the term is commonly discussed. The multiplier isn't about lines of code or features shipped. It's about the cumulative effect of fewer bugs, maintainable code, and solutions that serve the team long after the initial commit.

An engineer implementing a capability as a reusable library rather than a one-off solution. Someone building a more generic implementation that others can extend later. These contributions are often subtle to non-technical stakeholders, who frequently end up in management positions, but fairly obvious to other engineers who think similarly. The real differentiator is how these engineers make their whole team more effective.

Anticipation as core skill

In my experience, anticipation is the key differentiator. Anticipating bugs, future needs, usage patterns, performance bottlenecks. Coding accordingly, not just to improve their own output but for other engineers working on the same codebase. For some engineers, this becomes intuition rather than a checklist.

What does anticipation look like in practice? An engineer sees a configuration pattern that will likely need to support multiple environments. Instead of hardcoding values, they design the configuration structure to accommodate that from the start. Not because a requirement exists, but because experience suggests it will. Another engineer implements error handling that captures enough context to debug production issues, because they've been on the other end of vague error messages at 2am.

This extends to anticipating consumer needs. When writing documentation or tutorials, engineers who excel at this consider what their readers already know and what they don't, adjusting the level of detail accordingly. They anticipate the questions someone will have before they ask them.

This anticipatory thinking extends to how code communicates intent. Variable names that clarify purpose. Functions broken down in ways that make the next change obvious. Comments that explain why, not what, for decisions that might seem arbitrary six months later. These aren't cosmetic choices. They directly affect how quickly other engineers can understand, modify, and extend the code.

This isn't about building features you might need someday. It's about subtle choices that cost little extra: error handling that captures context, naming that communicates intent, structures flexible enough for likely next steps. Sometimes it also means building something reusable instead of a one-off solution. Not because requirements demand it, but because experience signals reuse is coming. The cost is minimal. The payoff compounds.

Empathy and user perspective

The ability to put themselves in the shoes of the end user is important. This comes naturally to some engineers, but others need to develop it deliberately. I've noticed this gap doesn't correlate with seniority. Experience in one domain doesn't automatically translate to understanding users in another. Direct interaction with users helps developers understand confusing features and behavior, making it easier to see confusion from the user's perspective.

This form of empathy manifests in small decisions that accumulate into user experience. An engineer who tests the error states, not just the happy path. Someone who questions whether a feature that makes technical sense actually solves the user's problem. A developer who considers what happens when the system is under load, when network is flaky, when inputs are unexpected. A UI developer who uses their interface from the user's perspective, testing usability rather than just building what was specified.

The lack of this perspective is equally visible. Features that work perfectly in development but fail in production because real-world usage wasn't considered. Interfaces that make sense to the person who built them but confuse everyone else. Error messages that are technically accurate but give users no path forward.

Some engineers develop this naturally. Others need direct exposure to users and production systems. Empathy has both innate and learned components. Training can help, and the software industry generally values such initiatives. For engineers where this doesn't come naturally, checklists and processes provide a pragmatic approach. I've introduced these in some teams I've worked with. Those checklists help, but they never cover everything. For some, user empathy remains a deliberate effort rather than intuition.

Pride and proactivity

Having pride in one's work, caring about what gets delivered. This is mindset rather than skills. Being proactive rather than reactive. Not just fixing issues when they happen, but building in ways that make future needs easier to address.

Pride in work shows up in details. Code that's clean not because someone will review it, but because it matters to the person writing it. Tests that are comprehensive because the engineer cares about correctness. Documentation that exists because the author wants others to succeed.

This connects to proactivity. Engineers with this mindset don't wait for issues to be reported. They monitor production systems. They notice patterns in support tickets. They fix problems before they escalate. They refactor code that works but is fragile, because they know it will cause issues later.

There's also the opposite pattern. Engineers who do exactly what's asked, nothing more. Code that meets requirements but ignores obvious edge cases. Work that's technically complete but requires constant follow-up to actually function in production. This isn't malicious or lazy. It's just a different approach to the work.

The other side of the spectrum

Some engineers have net negative contribution overall. This is uncomfortable to discuss, but it's a real phenomenon. I first noticed this pattern in teams I was part of early in my career. Back then, it felt almost taboo to acknowledge. Over the years, as I saw the pattern repeat and found others discussing the same observation, it became clearer. Engineers who seem to deliver on the surface, but when you examine technical details and overall output, other engineers are fixing their issues in the background. The problems compound over time.

This isn't primarily about team friction. It's about bugs, subtle regressions, convoluted code that takes hours to understand. One developer spends five hours writing unclear code, four other developers each spend ten hours trying to figure out how it works. Developers waste significant time dealing with poor code quality.

The pattern is recognizable once you know to look for it. Code that works initially in production but starts breaking as usage grows or edge cases emerge. Code that passes review but becomes a maintenance burden weeks later. Changes that fix one issue but introduce two others. The engineer appears productive by conventional metrics. Tickets closed, code committed, features delivered. The cost shows up elsewhere.

Subtle regressions are especially insidious. A change that works for the immediate use case but breaks edge cases that were previously handled. An optimization that improves one scenario but degrades others. A refactoring that simplifies the code the engineer understands but makes other parts more fragile. These issues often surface long after the original work, making the connection difficult to trace.

The DevOps model where developers write their own tests has a downside here. When engineers lack this anticipatory perspective, they tend to write happy-path tests that don't cover edge cases. A dedicated QA team with fresh eyes might catch what the original author missed. The efficiency gains from integrated testing can mask this gap.

The long-term effect compounds. Code review becomes more intensive, not because standards changed, but because trust eroded. What should be a straightforward feature takes longer because the foundation is unreliable.

AI as amplifier

AI-assisted development compounds these traits. Engineers with strong anticipation and user empathy know what to look for in generated code. They ask the right questions: does this handle the edge cases? Will this be maintainable? Does this actually solve the user's problem? They spot when something doesn't fit, when the generated solution misses context that wasn't in the prompt. They use AI to move faster while maintaining the same judgment that made them effective in the first place. Their impact multiplies.

Engineers lacking these traits just produce more. More code, faster, with the same blind spots. Code that doesn't align with real needs. Edge cases ignored. Subtle bugs introduced because generated code was accepted without critical review. The maintenance burden grows faster. More code to debug, more regressions to trace. The cleanup may never happen. Instead, the team slows down: new features take longer to build on a fragile foundation.

The variance between effective and ineffective engineers widens. What was a 10x difference becomes larger. Net negative contribution scales faster too.

Team organization matters

Individual mindset matters, but how teams are structured determines whether those individuals can be effective. I've seen projects with strong engineers struggle because of how work flows between teams.

End-to-end ownership

What I've seen work: end-to-end squads responsible for delivering full capabilities or missions. A capability often spans multiple services, libraries, and products. The squad implements across all of them, rather than waiting for each component team to prioritize and deliver their piece.

This requires engineers with curious mindsets willing to learn and adapt. They work across codebases they don't fully own. They understand enough of each component to make meaningful contributions, even if they're not the experts.

The ownership question still matters. Each component has owners: engineers who maintain long-term responsibility, review contributions, and ensure quality. Similar to open source, where maintainers accept pull requests from contributors. The end-to-end squad contributes, the component owners review and merge. Both roles are necessary.

This model creates velocity. The squad doesn't wait for five different teams to schedule their piece of the work. They implement, get reviews from component owners, and ship. Context stays intact because the same people carry the capability from start to finish.

When a customer complains about a feature, the squad that built it hears the feedback directly. They can adjust quickly because they understand the full picture, even across component boundaries.

The handoff problem

The alternative pattern: four or more development teams plus separate design teams. This leads to endless debates, handoff issues, lack of overall ownership. Each transition point becomes friction. Specifications get misinterpreted. Context gets lost.

The cost of handoffs is underestimated. When one development team builds a component, another team integrates it, and a third team extends it, each handoff loses context. The first team doesn't know how their code will be used. The second team doesn't understand the original design decisions. The third team inherits assumptions they can't see. Each handoff makes the codebase more fragile and harder to evolve.

Each handoff also diffuses responsibility. When something goes wrong, finger-pointing replaces problem-solving. No single person or team feels accountable for the end-to-end outcome. Handoff-heavy organizations develop defensive behaviors: extensive documentation to protect themselves, meetings to coordinate, rigid processes to prevent miscommunication. The bureaucracy is a rational response to dysfunctional structure, but it makes the dysfunction worse.

The debate trap

Too many teams also means endless debates. When four development teams need to align on an approach, each has different constraints, priorities, and contexts. The discussions become about finding consensus rather than finding the best solution.

Many architectural questions don't have clear answers in the abstract. The right choice depends on specific requirements, team skills, operational capabilities, and a dozen other factors that are hard to reason about theoretically. Building something surfaces these factors quickly.

This doesn't mean building without thinking. It means recognizing when discussion has diminishing returns. When the same points are being rehashed, when debates become theoretical or religious, when decisions are blocked on hypothetical future requirements, it's time to build something and learn from reality. The teams that shipped features while others debated usually ended up with more refined solutions, improved through actual usage rather than speculation.

Different facets of culture

Mindset, team structure, and bias toward action are different aspects of software engineering culture. They don't neatly cause each other, but they're part of the same picture. AI makes the mindset gap more visible, widening the difference between engineers who anticipate and those who don't.

Some engineers bring anticipation and empathy regardless of how teams are organized. Some team structures work despite individual gaps in mindset. When teams struggle to deliver, it's usually one of these human factors: engineers who don't think beyond the immediate task, structures that diffuse responsibility, or processes that reward debate over delivery.

As AI tools become more common, these fundamentals seem to matter more than they used to. Teams with strong foundations can use them to move faster without sacrificing quality. Teams without those foundations tend to just accumulate technical debt faster.

Top comments (0)