Developer experience is what building software feels like from the inside. I think of it like UX, except the engineer is the user. The codebase, tools, workflows, and team habits all shape that experience.
The shortest path to a safe change
My test for code quality is pretty simple: can another engineer understand the intent, make a change, and trust what happens next? Can they find where the work belongs? Can they verify it without asking three different people for help?
Clean structure helps. In a Python repo, folders named ingestion, normalization, and publishing give me more direction than a large collection of utils, helpers, and services. The names will change with the product, but the structure should follow responsibilities people can recognize.
market_data/
├── ingestion/
├── normalization/
└── publishing/
The workflow around the code matters too. I want setup instructions I can trust, errors that tell me what to do next, and focused tests that run quickly. The checks on my laptop should match what CI expects. Ideally, one command can answer a simple question: is this change ready?
Quick feedback makes experiments cheaper, refactoring less intimidating, and mistakes easier to catch.
Better defaults, one file at a time
At LinkedIn, I worked in a codebase with years of JavaScript behind it. Important product entities sometimes reached the frontend as loosely shaped objects without a complete contract. Even when I understood a campaign conceptually, I still needed to log the object to see which fields and states were actually present. That guesswork made complex workflows harder to reason about and left room for bugs around the edges.
I helped lead our feature group's move toward TypeScript and GraphQL while regular product work continued. A full rewrite was never practical. When feature work took us into a legacy JavaScript file, we often converted it along the way. New features started with typed props, state, and API contracts from day one.
We also documented the patterns and kept reinforcing them in review. TypeScript moved assumptions into the code and made API changes easier to trace. GraphQL gave frontend and backend engineers a contract they could both inspect. Engineers spent less time rediscovering how a feature worked, and new work had a cleaner place to begin.
That incremental approach mattered. The codebase improved through normal product work, and each change left a slightly better default for the next engineer.
The codebase should explain itself
Code is good at showing what happens today. It rarely explains why a decision was made. I use design docs to keep the problem, constraints, existing services, and tradeoffs from disappearing into meetings and pull requests.
The useful ones are direct. They name the services involved, explain the contracts and ownership, and record the options we considered. That gives debugging a place to start and helps the next engineer reuse an existing boundary instead of creating another path that almost does the same thing.
Code review and onboarding show where context is missing. If the same explanation keeps coming up, it probably belongs near the code.
Coding agents expose the same gaps quickly. Clear naming, current design docs, and reliable checks help an agent reuse what exists instead of confidently inventing a second version. The guidance I give an agent is close to what I would tell an experienced teammate: understand the boundary, keep the change within scope, follow established patterns, and run the expected checks.
A codebase that works well for agents usually works well for people too. The engineer still owns the decision and what happens after it ships.