I joined a large, multi-year Flutter project six months ago. The team was five Flutter devs when I started; it's grown to ten since. I didn't drive most of the engineering decisions in this post; more senior teammates did that work, some of it years before I arrived. But watching it happen, and working inside the systems that came out of it, taught me more about real-world software engineering than any tutorial or side project ever did. This is that story.

The codebase I walked into
The app is a consumer health & wellness product: habit tracking, nutrition logging, workouts, a proprietary health score, the works. It had been in active development for years by the time I joined, with 20+ feature modules and a lot of accumulated history. Some of that history was clean. Some of it wasn't.
What I noticed in my first few weeks:
- One or two enormous "umbrella" feature folders that had absorbed years of unrelated functionality, because it was easier to add one more file than to figure out where things should live
- Legacy data models built on heavy code-generation tooling that people were visibly reluctant to touch
- Modules with fuzzy boundaries, where the same piece of state could get read and mutated from several unrelated screens, so a small change in one place could break something in another
- Places where the app quietly assumed a network connection was always available, so an action taken on bad signal could go missing instead of failing loudly
- Hardcoded colors and font sizes on some screens instead of theme references
- Raw platform widgets mixed in with the app's actual design components, so buttons didn't always look like buttons
What I noticed pretty quickly was that some parts of the app were much easier to work in than others, and it turned out that wasn't random.

The thing that made the biggest impression on me: a lint rule
The part of this codebase I keep thinking about is the design system, not because I built it, but because I got to see what it made possible.
The team has a canonical set of shared widgets (card, button, and semantic text components) backed by custom static-analysis lint rules. If you use a raw platform widget, a hardcoded color, or a literal string instead of the shared components, your code doesn't pass analysis. Not a style guide. Not a review comment. An actual failure.
I didn't build this system, but I've lived inside its consequences. During my time on the team, the app went through a full brand refresh: new theme tokens, new typography, new component styling, applied across an app with years of history, and it happened , without a dedicated freeze. Because most screens were already required to consume shared widgets and theme tokens, a huge amount of the visual change happened centrally, in the design-system layer, instead of screen by screen.


