14 February 2026
When I started my first job as an Android engineer, I thought the hard part was writing code. I knew Kotlin, I understood Activities and Fragments, and I could build features. What I didnât know was how to actually work in a team. How to write a good pull request description. How to ask questions without annoying people. How to communicate when I was stuck. How to unblock myself. How to run a sprint. How to handle disagreements in code review. How to estimate work. How to not silently struggle for three days on something a teammate could have helped me solve in twenty minutes.
The truth is, nobody teaches you this stuff. University teaches you algorithms and data structures. Tutorials teach you how to use libraries. But nobody sits you down and explains how an engineering team actually operates day to day. And this is the part that makes or breaks your career. Iâve seen brilliant engineers fail because they couldnât collaborate, and Iâve seen average engineers thrive because they communicated well, shipped consistently, and made everyone around them more productive. Googleâs own research (Project Aristotle) confirmed this â the number one factor in high-performing teams isnât individual talent. Itâs psychological safety. The ability to take risks, ask questions, and admit mistakes without fear of judgment.
This post is everything I wish someone had told me on my first day. It covers how engineering teams are structured, how work flows from idea to production, how to communicate effectively, how to write pull requests that get reviewed quickly, how to handle code review without ego, how to run sprints, how to deal with being stuck, and how to grow from a junior engineer into someone the team relies on. Itâs long. I meant it to be. Bookmark it and come back when you need a specific section.
Most engineering teams follow some variation of a squad model. A squad is a small, cross-functional team â typically 4 to 8 engineers â that owns a specific area of the product. Youâll usually have a mix of Android engineers, iOS engineers, backend engineers, a product manager (PM), a designer, and a QA engineer. The exact composition varies by company, but the principle is the same: a squad has everything it needs to ship features independently without waiting on other teams.
Within the squad, youâll encounter a few key roles. The Product Manager defines what to build and why. They own the roadmap, prioritize features, write requirements, and are your primary source for âwhat does the user actually need?â The Tech Lead (or Principal Engineer) makes architectural decisions, sets technical direction, and is usually the person whoâs been on the team longest. The Engineering Manager handles people â career growth, 1:1s, hiring, performance reviews. In some companies, the EM and Tech Lead are the same person. The QA Engineer tests your work before it reaches users. The Scrum Master (or Agile Coach) runs ceremonies and removes blockers.
Understanding these roles matters because it changes who you talk to and when. Got a question about what a feature should do? Ask the PM. Confused about the architecture of a module? Ask the Tech Lead. Need to discuss your career growth? Talk to your EM. Donât go to your EM with architecture questions or your Tech Lead with career concerns â it wastes everyoneâs time and signals that you donât understand the team structure.
Beyond your squad, larger organizations have chapters (or guilds) â groups of engineers with the same specialty (all Android engineers, for example) across different squads. Chapters share knowledge, maintain coding standards, and ensure consistency across the product. If your squadâs Android app handles navigation differently from another squadâs, the Android chapter is where that gets resolved. Spotify pioneered this model publicly, and many companies have adapted it since.
Understanding the flow of work is fundamental. Hereâs how a feature typically moves through an engineering team:
1. Product defines the problem. The PM writes a product requirement document (PRD) or a brief that explains what the user needs, why it matters, and what success looks like. Good PMs include acceptance criteria â specific conditions that must be true for the feature to be considered done. If you get a vague brief, ask for acceptance criteria before you start writing code. âBuild a search featureâ is not a specification. âSearch should support minimum 3-character queries, show results within 500ms, display up to 20 results, and show an empty state when no results matchâ â thatâs something you can build and test against.
2. Design creates the experience. The designer produces mockups, user flows, and sometimes interactive prototypes. As an engineer, review these early. Donât wait until the design is âfinalâ to raise technical concerns. If a design requires an API that doesnât exist, or if an animation would tank performance on low-end devices, say so now. The cost of changing a Figma file is near zero. The cost of rewriting a feature after three weeks of implementation is enormous.
3. Engineering breaks it down. This is where you come in. The Tech Lead (or the squad collectively) breaks the feature into technical tasks. Each task becomes a ticket â a Jira ticket, a Linear issue, a GitHub issue, whatever your team uses. Good tickets are small, specific, and independently shippable. âImplement searchâ is a bad ticket. âAdd search text field with debounceâ and âImplement search API repositoryâ and âBuild search results LazyColumnâ â those are good tickets. A good rule of thumb: each ticket should be completable in 1-3 days. If itâs bigger than that, break it down further.
4. Sprint planning. The team picks which tickets to work on in the upcoming sprint (usually a 1-2 week cycle). Engineers estimate effort (story points, t-shirt sizes, or just time estimates â the format varies). The key here: be honest about estimates. Padding estimates to look safe is just as bad as underestimating to look fast. Over time, your estimates will get more accurate as you learn the codebase and your own pace.
5. Implementation. You pick a ticket, create a branch, write code, write tests, and raise a pull request. More on this process below.
6. Code review. Teammates review your PR. You address feedback, iterate, and merge.
7. QA testing. The QA engineer tests the feature against the acceptance criteria. Theyâll file bugs if anything is wrong. Fix them.
8. Release. The feature ships to users, either through a regular release cycle or a feature flag. Monitor crash reports and user feedback.
This flow isnât always linear. Youâll often be doing steps 5-8 for multiple tickets simultaneously while step 4 is happening for the next sprint. The key is understanding where your work fits in the bigger picture.
Communication is where most engineers underperform, not because they lack skills, but because nobody taught them the norms. Hereâs what good engineering communication looks like.
GitHubâs engineering team published their internal communication guide publicly (github/how-engineering-communicates), and their number one principle is âbe asynchronous first.â Asynchronous communication means you send a message and the other person responds when they can â no expectation of an immediate reply. This is the opposite of tapping someone on the shoulder or sending âhey, got a sec?â on Slack.
Why async-first? Because engineers need deep focus time. Research shows that knowledge workers are most productive with large blocks of uninterrupted time. A two-hour block is not the same as four 30-minute blocks. Every interruption â a Slack ping, a âquick question,â a last-minute meeting â costs 10-15 minutes of context-switching time to get back to where you were. Multiply that across a team, and you lose hours of productivity daily.
In practice, async-first means:
@here and @channel sparingly. These are the equivalent of shouting in a crowded room. Reserve them for genuinely urgent situations.The second principle from GitHubâs guide: âwrite things down.â Especially the âwhyâ behind decisions. When you make a technical decision â choosing Room over SQLDelight, or picking MVI over MVVM for a new module â write down why. Not just the what. A year from now, someone (possibly you) will look at that code and wonder why it was done that way. If the reasoning is documented, they can build on it. If itâs not, they might undo your work without understanding the context.
Google calls this the âChestertonâs Fenceâ principle â from the book âSoftware Engineering at Googleâ â before removing or changing something, first understand why itâs there. Documentation makes this possible.
Where to write things down:
The daily standup (or daily scrum) is a short meeting â ideally 10-15 minutes â where each team member shares three things: what they did yesterday, what theyâre doing today, and whether anything is blocking them. The purpose is coordination, not status reporting. Youâre not reporting to your manager. Youâre synchronizing with your teammates so that everyone knows whatâs happening and can offer help or flag conflicts.
Common standup mistakes:
Not everything can be resolved asynchronously. GitHubâs guide recommends treating meetings as a âpoint of escalationâ â you start with async (a Slack message, a ticket comment, a PR review), and if you canât resolve it there, you escalate to a synchronous call. If a PR review goes back and forth for more than 3-4 rounds without consensus, jump on a 15-minute call. Youâll resolve it faster, and youâll avoid the frustration of misinterpreted text.
The escalation ladder looks like this: ticket comment â Slack message â quick call â scheduled meeting â bring in the Tech Lead. Most issues resolve at the first or second level. If youâre regularly escalating to meetings, something is wrong with your teamâs written communication.
Every engineer gets stuck. The difference between a junior and a senior isnât that seniors never get stuck â itâs that they get unstuck faster because they have better strategies. Hereâs my framework:
1. Define the problem clearly. Before asking anyone for help, write down exactly what youâre trying to do, what you expected to happen, whatâs actually happening, and what youâve already tried. Half the time, the act of writing this down helps you find the answer yourself. This is rubber duck debugging.
2. Time-box your solo debugging. Give yourself 30-60 minutes. If you canât figure it out in that time, stop and ask for help. The old advice of âtry harderâ is wrong. Struggling silently for a full day is not impressive â itâs wasteful.
3. Search before asking. Check the codebase for similar implementations. Search Slack history. Check the official documentation. Search your teamâs ADRs and wiki.
4. Ask smart questions. When you do ask, provide context. âThis doesnât workâ is a useless question. âIâm trying to observe a StateFlow from the repository in my ViewModel, but collectAsStateWithLifecycle is recomposing on every emission even when the value hasnât changed. Hereâs my code [link]. Iâve verified the Flow is emitting distinct values with a log. I suspect the issue is that my data class doesnât implement equals correctly, but Iâm not sure. Can someone take a look?â â thatâs a great question. It shows effort, provides context, and even includes a hypothesis.
5. Share your solution. When you figure it out â whether alone or with help â share the solution in the channel where you asked. This builds a searchable knowledge base for the team.
Pull requests are where individual work becomes team work. A PR is not just a code delivery mechanism â itâs a communication artifact, a knowledge-sharing tool, and a quality gate all in one. Googleâs engineering practices guide emphasizes that âthe primary purpose of code review is to make sure that the overall code health of the codebase is improving over time.â Hereâs how to do PRs well.
Keep them small. The single biggest factor in PR quality is size. Googleâs eng-practices guide has an entire page on âSmall CLsâ (their term for changesets). A PR with 50-100 lines of changes gets reviewed in minutes and gets high-quality feedback. A PR with 800 lines sits in the queue for days, gets rubber-stamped, and bugs sneak through because no reviewer has the stamina to carefully read 800 lines of code.
If your feature requires 800 lines, break it into multiple PRs. Ship the data layer first (models, repository, data source). Then the domain layer (use cases if you have them). Then the UI. Each PR is independently reviewable and independently testable.
Write descriptive titles and descriptions. Googleâs guide says a CL description should answer two questions: what change is being made, and why. The title should be a short summary that stands alone â someone scanning the git history should understand what this PR did without opening it. âFix bugâ is never an acceptable title. âFix crash when search query is empty on API 28 devicesâ is.
The description should include:
Link to the ticket. Always. Every PR should reference the Jira/Linear ticket it addresses. This creates a bidirectional trail â from ticket to code and from code to ticket.
Self-review before requesting review. Read your own diff. I catch 20-30% of my mistakes this way. Look for: leftover debug logs, TODOs you forgot to address, hardcoded strings that should be resources, missing null checks, functions that are too long, naming inconsistencies.
Code review is a skill. Itâs not about finding every possible improvement â itâs about ensuring the PR improves the overall health of the codebase.
Review promptly. Googleâs standard is to respond to a code review request within one business day. Ideally, within a few hours. Slow reviews block your teammates and kill team velocity. If you canât review it today, say so â âIâm heads-down on the search feature today, Iâll review this tomorrow morning.â
Focus on what matters. Donât leave 30 comments about formatting when thereâs a concurrency bug in the ViewModel. Prioritize: correctness first, then design, then readability, then style. If something is a minor preference rather than a real issue, prefix it with ânit:â to signal itâs not a blocker.
Be constructive, not adversarial. âThis is wrongâ is not helpful. âI think there might be a race condition here because the StateFlow could emit before the coroutine scope is active. What if we used SharingStarted.WhileSubscribed(5000) instead?â â thatâs constructive. Youâre explaining the problem, showing you understand the code, and offering a specific alternative.
Googleâs reviewer guide has a principle I love: âIn general, reviewers should favor approving a PR once it is in a state where it definitely improves the overall code health of the system, even if the PR isnât perfect.â There is no such thing as perfect code â there is only better code. Donât hold up a PR for days over style preferences.
Donât take it personally. And donât make it personal. You are not your code. When someone suggests a change, theyâre improving the codebase, not attacking your competence. If you disagree with feedback, explain your reasoning. Have a technical discussion. But donât dig in your heels because of ego â be open to influence. Googleâs âSoftware Engineering at Googleâ book puts it this way: âThe more open you are to influence, the more you are able to influence.â
Most engineering teams use some form of Agile, usually Scrum or Kanban. Hereâs what actually matters in practice.
Happens at the start of each sprint (1-2 weeks). The team looks at the prioritized backlog and commits to a set of tickets. Key principles:
Happens at the end of each sprint. The team discusses: what went well, what didnât go well, and what should change. This is the most underrated ceremony. Good retrospectives create a feedback loop that continuously improves how the team works.
Common retro formats:
The most important thing about retros: follow through on action items. If the team agrees to âimprove PR review timeâ but nobody does anything about it, retros become performative and people stop engaging. Assign owners to each action item and track them.
At the end of each sprint, the team demos what they built to stakeholders (PM, designer, sometimes leadership). This is your chance to show your work. Keep demos focused â show the feature working, explain any notable technical decisions, and flag any open issues. Donât read your slide deck word for word. Show the actual running app.
Every team has a branching strategy. The most common ones:
Trunk-based development â Everyone works on short-lived feature branches off main and merges back quickly (within 1-2 days). This is what Google and most high-performing teams use. It requires good CI/CD and feature flags, but it minimizes merge conflicts and keeps the codebase integrated.
Git Flow â Long-lived develop and main branches, with feature branches, release branches, and hotfix branches. More complex, but useful for teams that need to manage multiple release versions simultaneously. Less common in mobile development.
GitHub Flow â A simplified version: branch off main, make changes, open a PR, get reviewed, merge to main. This is what most smaller teams use and it works well for mobile apps with a single release track.
Regardless of which strategy you use, some git practices are universal:
.gitignored local properties file.main and resolve conflicts locally before pushing your branch. Donât let your PR have merge conflicts â it signals to reviewers that youâre not keeping up with the codebase.Most engineers hate writing documentation. But documentation is what keeps a team functional as people join, leave, and forget things. The âSoftware Engineering at Googleâ book dedicates an entire chapter to this topic and makes the case that documentation is one of the highest-leverage activities an engineer can do.
/docs/adr/ directory in the repository.git blame and finds a confusing line, the PR description should explain the context.Hereâs the part nobody talks about: documentation rots. If you change how a module works but donât update the documentation, youâve made the documentation worse than useless â itâs now actively misleading. GitHubâs engineering guide says to âplace as much importance on documentation maintenance as we do on creating good documentation.â When you change code, check if any documentation references that code and update it.
Technical disagreements are healthy. They mean people care about the code quality. But they can also escalate into ego battles that waste time and damage relationships. Hereâs how to handle them productively.
Lead with data, not opinions. âI think we should use Xâ is weak. âI benchmarked X and Y. X handles 10K items in 4ms, Y takes 12ms. X also has better memory characteristics because of Zâ is convincing. Googleâs code review guidelines state it clearly: âTechnical facts and data overrule opinions and personal preferences.â
Disagree and commit. Amazon popularized this phrase, but the principle is universal. Once a decision is made â even if you disagree â commit to it fully. Donât passively undermine a technical direction you lost the argument on. If you were wrong, learn from it. If you were right and the decision fails, help fix it instead of saying âI told you so.â
Escalate, donât stalemate. If two engineers canât agree after 2-3 rounds of discussion, bring in the Tech Lead or a senior engineer as a tiebreaker. Donât let a PR sit for a week while two people argue about architecture in the comments. Thatâs not productive â thatâs a process failure.
Separate preferences from principles. âI prefer putting the repository interface in the domain layerâ is a preference. âHaving the data layer depend on the domain layer creates a circular dependency that breaks the dependency ruleâ is a principle. Fight for principles. Be flexible on preferences.
Googleâs Project Aristotle research found that psychological safety is the single most important factor in team effectiveness â more important than individual talent, team structure, or tools. Psychological safety means team members feel safe to take risks, ask questions, make mistakes, and challenge ideas without fear of punishment or humiliation.
What this looks like in practice:
If youâre joining a new team, hereâs what to prioritize in your first three months:
Week 1-2: Learn the landscape.
Week 3-6: Start contributing.
Week 7-12: Build ownership.
I want to emphasize: the 6-month ramp-up is normal. Google tells new employees (they call them âNooglersâ) that ramping up takes about six months. If youâre four weeks in and feel overwhelmed, thatâs not a sign of inadequacy â itâs a sign that youâre learning. The engineers who struggle are the ones who pretend they understand everything and silently drown.
The bus factor is the number of people who need to get hit by a bus before a project is doomed. If only one person understands the payments module, and that person leaves, your team is in serious trouble. The âSoftware Engineering at Googleâ book calls this a âSingle Point of Failureâ and explicitly warns against it.
How to improve bus factor:
Engineering is a career of perpetual learning. The technology changes fast, but the principles of working well in a team stay the same. Hereâs how to keep growing:
The best engineers Iâve worked with arenât the ones who know the most. Theyâre the ones who communicate clearly, ship consistently, help their teammates, and never stop learning. Technical skills get you hired. Team skills get you promoted.
Thanks for reading through all of this :), Happy Coding!