Engineering Manager · hands-on, staff/principal-level IC background

Andrew
Cratty

I lead engineering teams day to day, and I still write code, review architecture, and build tooling alongside them. This page is about how I actually do that: how I think about leading people, how requirements turn into shipped software, what I hold engineers to, how releases move through the pipeline, and how production gets supported once real users are on it.

The other side of this site, CO Tech Underground, is a personal project I design and build entirely on my own time, completely separate from my employer, with no shared codebase, systems, or team. It's not evidence of how I run a team; it's evidence that I stay sharp as an individual engineer on the same kinds of systems and architecture (CI/CD, auth, real-time infrastructure) that engineering work in general demands.

Leadership

Clarity, above everything else

The best thing a manager can give a team is clarity: about what we're building, how work actually gets done, and what doing it right looks like in practice.

I learned how much that matters by watching its absence do real damage. When priorities shift constantly and everything gets labeled top priority, teams sprint hard on work that gets discarded a week later. The cost isn't just wasted effort, it's burnout and eventually trust. I've watched good people, including people above me, leave over exactly this. It made me determined to filter that noise out before it reaches my team instead of passing it straight through.

In practice, that means building systems that make clarity durable instead of relying on repetition alone. I've redefined release cadences, branching strategy, and CI/CD workflows from the ground up, working alongside the team to implement them, not just documenting them from a distance. I did the same on the project management side, restructuring how we used Jira for epics, stories, and releases so the roadmap, what's in flight, and what's shipping next were visible to everyone instead of tribal knowledge held by a few people. When it comes to defining what to build in the first place, I run point between product owners, customers, and leadership, gathering the ask from each separately and working with a BA to translate that into requirements a team can actually execute against. Bridging that gap only works because I know the business side and the engineering side well enough to speak both.

Team Building

Hiring for skill, fit, and drive

When I'm hiring, the first question is simple: can this person actually do the job, today or after getting up to speed quickly. After that it's fit. Everyone's worked with someone they dreaded dealing with, and I've seen that kind of dysfunction get bad enough to push good people to quit. A team only works if people actually want to work with each other day to day. Last is drive, because skills and fit only go so far if someone isn't motivated to grow.

Once someone's on the team, my job shifts to supporting them in whatever way actually helps. That looks different for everyone. Some people want frequent 1:1s and regular check-ins. Others do their best work when they're handed clear requirements and left alone to execute. I try to read which one each person needs instead of managing everyone the same way.

Building the right team isn't just about hiring. I've moved people into different roles to better match their strengths, brought in new hires to fill real gaps, and made the call to let someone go when it was the right thing for the team. All three are part of the job.

Requirements

Requirements start with listening

I start by listening, separately, to each group involved. Leadership, product, and customers all have their own version of what matters, and the real priority is often buried under whatever the current buzzword happens to be. I dig past that to find out what leadership actually needs, then do the same with product and customers to understand their asks, and look for where those actually line up and where they don't.

From there I work with product and the BAs to turn that alignment into actual requirements. Before anything is finalized, I bring it to the engineering team for a readout, because their input at this stage catches problems that are far cheaper to fix on paper than after work has started. Once the team has weighed in, we finalize the requirements and hand them off.

My involvement doesn't stop at handoff. I stay with the feature through build, release, and production, and after it ships too. The point of gathering requirements in the first place is a feature that actually works for real users, and I want to be around to support it or adjust course once it's live.

Along the way I keep regular touchpoints going with each group, whether that's giving leadership and product a status update, clearing a roadblock for the team, or giving engineering more clarity as questions come up mid-build. A lot of that roadblock work is cross-team: plenty of features depend on data or functionality that another team owns, and I drive those conversations directly so my team isn't stuck waiting on a dependency they have no way to unblock themselves.

Engineering Standards

Review, automation, and who's actually accountable

Every change needs review from at least two peers before it merges, on top of automated gates for security and code quality using tools like SonarQube, Copilot, Claude, and Wiz. Peers catch design and logic issues a tool can't. Automation, especially test coverage across the important functional areas, is what gives high confidence in a release without someone having to manually run a full regression every time something ships.

The only time I've had to step in on a team's review culture is when pushback in reviews came down to personal preference rather than an actual issue. That's not what review is for.

AI-assisted coding hasn't changed where ownership sits. Engineers are using AI tools to write code now more than ever, but they're still responsible for what they ship. If a bug makes it to production, it's on the engineer who committed it, not the tool that helped write it. For anything that's a bigger architectural change, the expectation is to bring a spike or proof of concept to the team first, before it gets built out and committed for real.

I still write code every day myself. I generally leave product development to my engineers and only step in there when the team doesn't have the resource to cover it. The code I write day to day is aimed at the team itself, tooling and process work that helps manage the team, surface bottlenecks, and find areas to improve. This platform is an example of that kind of work.

The fast-versus-right tradeoff used to be a real tension, but AI has largely closed that gap. Writing the code fast isn't the hard part anymore. What matters now is the same thing that matters everywhere else in how I lead: clarity on what we're actually building and why, so speed doesn't get spent on the wrong thing.

DevOps & CI/CD

Three branches, one clear path from code to production

The pipeline runs on three main branches: develop, release, and master. Most work starts as a branch off develop, goes through the normal development process, and gets opened as a PR back into develop. Once merged, it's pushed to the Dev environment for development and QA testing.

After that passes, the build promotes to the release branch and moves to the Integration environment for further testing. Once integration testing passes, that same build promotes to production. Only after it's live and validated as working correctly does the code get merged into master, which represents what's actually running in production right now.

That structure also defines how fixes flow depending on urgency. A fix or enhancement needed within the current two-week cadence goes against the release branch and follows the same integration-then-production path. An actual production incident skips that cadence entirely: the fix goes against master directly, gets validated in Integration, and pushes straight to production, so an incident doesn't have to wait behind whatever else happens to be in flight on release.

Production Support

Catching issues before someone has to report them

I get paged for production issues, with response driven by severity. We've built alerting and dashboards that continuously monitor the databases and application logs, watching for things like the database not responding, high load causing slowness, or exceptions starting to spike in the application. That means we're already working an issue as it starts, instead of waiting for a user to notice and report it.

For anything that isn't urgent, there's a ticketing system where users can submit observations for us to investigate on a normal, less time-critical cadence, plus an internal Slack help channel for faster back-and-forth on active issues. We also run a standup over open tickets specifically so nothing sits untouched and falls through the cracks.

The Full Cycle

Staying with it end to end

A lot of this work depends on other teams, and part of my job is driving those cross-team conversations directly so a dependency never turns into something my team is just stuck waiting on. It's also not a one-way handoff. I stay with a feature from the first conversation about what's needed through to production, and after it ships too, fixing what needs fixing and feeding what we learn back into how the next thing gets built.

Resume

15+ years building and leading engineering teams

15+ years in software engineering 5 years in engineering management 70+ engineers led 99.8% system availability 49% team velocity improvement

Resume download requires a free account, same login used across the platform.