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. The patterns I've observed over the years keep sharpening as I see them repeat: anticipation and empathy change how engineers approach problems, team structures affect delivery speed and alignment with user needs. Culture shapes outcomes more than tooling or process.
The mindset difference
A pattern I've seen across engineering teams: you typically have one or two engineers who 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. I actually heard the term "10x engineer" only recently, but reflecting back across 20 years, it resonates, though not in the way the term is commonly discussed. The multiplier isn't about lines of code or features shipped. It's about fewer bugs, maintainable code, and solutions that serve the team long after the initial commit.
What this looks like in practice: 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. The line between this and overengineering is thin. The difference is judgment: solving for the next likely step, not for every hypothetical future. These contributions have real business impact, but they're hard to see without looking at the technical details. Other engineers with the right mindset spot them immediately. What actually sets them apart is how they make their whole team more effective.
Anticipation as core skill
Anticipation is the biggest factor. Anticipating bugs, future needs, usage patterns, performance bottlenecks. Coding accordingly, not just for their own output but for other engineers working on the same codebase. For some, this becomes intuition rather than a checklist.
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.
The same applies when writing documentation or tutorials: considering what readers already know and what they don't, adjusting the level of detail accordingly. Anticipating the questions someone will have before they ask them.
It also shapes 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. The cost is minimal. The payoff compounds.
Empathy and user perspective
Seeing the product from the user's perspective comes naturally to some engineers. For many, it needs to be developed deliberately. 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 shows up in small decisions that shape 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 absence is just as 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. Some of this is innate, some learned. Training helps. 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
Caring about your stuff. Having pride in 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.
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. It's a different approach to the work.
The other side of the spectrum
Some engineers have net negative contribution overall. This is uncomfortable territory, but real. I first noticed this in teams I was part of early in my career. Back then, it felt almost taboo to say it out loud. 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, though I may have been lucky on that front. It's about bugs, subtle regressions, convoluted code that takes hours to understand. One developer writes unclear code in an afternoon, and several others spend far longer trying to figure out how it works.
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 the worst part. 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 struggle not because of technology, but because of team organization.
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 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 circular, 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 sides 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 where alignment takes longer than building.
As AI tools become more common, these fundamentals matter more, not less. Design, build, test, deploy. Or debate endlessly. Teams with strong foundations use AI to move faster without sacrificing quality. Teams without those foundations just accumulate technical debt faster.
Top comments (0)