Modern software is too big for lone heroes. We touch databases, APIs, frontends, infra, security, observability, UX, compliance… and then we're surprised we can't keep the full stack in our head at once. The reality is simple: we can't know it all, so we need each other.
Being a good team member isn't "being nice." It's practicing habits that let a group of imperfect humans reliably deliver a quality product, learn fast, and be better tomorrow.
1) Listen like you're trying to be wrong (in a useful way)
Listening in engineering isn't passive. It's active error-correction.
- Ask: "What problem are we solving?" before "What solution do I prefer?"
- Repeat back: "So the risk is X, and you're proposing Y because… correct?"
- Look for constraints: time, scope, legacy decisions, compliance, performance, support burden.
Teams get stuck not because people are stupid, but because they're solving different problems without realising it. Seen it happen more times than I can count.
2) Many ways to solve a problem, one team way
In software, there are usually dozens of ways to solve the same problem. Some are clearly wrong (unsafe, untestable, fragile). Some are clearly strong (simple, secure, maintainable). And then there's a big middle zone where multiple approaches are technically valid.
Engineers love the idea that there is "one good technical way." Sometimes that's true, especially for fundamentals like security, correctness, and reliability. But most of the time, the "best" solution isn't the one that wins a theoretical debate. The best solution is the one that:
- solves the real problem,
- respects the constraints (time, complexity, risk),
- meets the team's quality bar,
- and is understood and supported by the people who will maintain it.
Because you're not just building code, you're building a shared responsibility. A technically brilliant approach that only one person understands is a liability. A slightly less "perfect" approach that the whole team can read, review, extend, and debug together often wins in the real world. Because the system survives.
A practical rule of thumb:
- Hard rules (must follow): security, correctness, agreed standards, compliance, critical architecture constraints
- Soft rules (choose together): structure, naming conventions, patterns, libraries, stylistic preferences
When you're arguing in the soft-rule zone, the right question isn't "Which is smartest?" It's: "Which option will our team be happiest to live with six months from now?"
3) Bring ideas, but don't treat them as identity
Presenting ideas is good. Welding your ego to them is how teams rot. I've had to unlearn this one myself.
Healthy posture:
- "Here's an approach. Trade-offs: A, B, C."
- "I'm not sure, can we sanity-check this together?"
- "What would make this fail in production?"
Unhealthy posture:
- "This is obviously the right way."
- "We always do it like this."
- "If you disagree, you're wrong."
In good teams, ideas are inputs, not personal territory.
4) Disagree respectfully, and focus on trade-offs
Disagreement is not the problem. Unclear decision-making and disrespect are the problems.
Good disagreement looks like:
- address the code/design, not the person
- state the concern and the impact ("This might break idempotency under retries")
- propose an alternative or mitigation
- accept constraints ("If we must ship today, let's add a follow-up ticket + guardrails")
A team that can't disagree becomes fragile. A team that can't disagree respectfully becomes toxic. Both are bad. The second is worse.
5) Decision-making: discuss widely, decide clearly
Discuss as a team, then let the right role decide (depending on what kind of decision it is). This avoids endless debate while still using the team's brainpower.
A simple model:
- Product decisions (scope, priority, user impact): PO decides, informed by the team
- Technical decisions (architecture, approach, quality bar): Tech Lead decides, informed by the team
- Team process decisions (ways of working): Team Lead facilitates, team aligns
Key rule: once a decision is made, the team commits. Not because it's perfect, but because moving together beats being right alone.
6) Feedback: give it fairly, receive it like a pro
Giving feedback well:
- Be specific: "This method name hides side effects" beats "This is bad."
- Explain why: "Future readers won't see it performs IO."
- Keep it actionable: propose a rename, extraction, test, or guardrail.
- Praise is allowed when it's real: "Nice decomposition here, easy to follow."
Receiving feedback well:
- Assume positive intent until proven otherwise.
- Ask: "What risk are you seeing?" instead of defending instantly.
- Separate taste from standards:
- Standards: must follow (security, correctness, agreed conventions)
- Taste: discuss, but don't block progress endlessly
The goal isn't to "win the PR." The goal is quality, learning, shared ownership.
7) We can't know everything, so we need shared practices
Different preferences and backgrounds are normal. What matters is turning that diversity into a coherent system.
You need two layers of agreement:
Layer A: Project-specific conventions
- naming patterns for services/handlers/controllers
- folder structure
- DTO naming conventions
- error handling strategy
- logging conventions
- testing approach
These are project-specific. A good convention is one that reduces friction for this codebase and is consistently applied.
Layer B: Company-wide standards (agnostic across teams and tech)
This is where the company should step up:
- secure coding baseline (auth, secrets, injection prevention, dependency policy)
- review expectations (what must be checked before merge)
- incident response expectations
- data handling expectations (privacy, retention, access)
- definition of done (minimum quality bar)
Company standards should be technology-agnostic: principles and outcomes first, then team-specific implementations.
8) Make decisions visible (because memory is not a system)
If a decision is only in someone's head or buried in one chat thread, it will be re-litigated forever.
Make decisions visible:
- short message to the whole team (Teams/Slack) summarising:
- what was decided
- why
- what changes (conventions, architecture, process)
- date + owner
- link to a lightweight "Decision Log" (ADR-lite)
- pin it, tag it, store it somewhere findable
Visibility prevents tribal knowledge and makes onboarding far easier.
9) Other good practices that make teamwork actually work
- Own outcomes together: no "your code broke prod." It's our system.
- Keep PRs small: smaller PRs = better reviews and fewer regressions.
- Prefer async for non-urgent: threads beat meetings for many topics.
- Clarify escalation paths: who decides, how fast, and what's the fallback when blocked.
- Rotate responsibilities: bug triage, on-call, release captain, "support dev" builds empathy and system knowledge.
- Document the weird stuff: every codebase has gotchas, write them down.
- Respect focus time: batch questions, use statuses, agree review windows.
- Celebrate learning, not perfection: postmortems should improve the system, not punish humans. (If people are scared to report issues, you'll never hear about them until it's too late.)
The real point
A good team member helps the team do three things:
- Deliver value
- Maintain quality
- Learn and improve continuously
You don't need everyone to agree on everything. You need shared principles, clear decisions, and a culture where people can speak, disagree, and commit. Together.
