Skip to content
All posts
July 3, 20263 min read

How QA Thinking Makes Me a Better Developer

13 years in QA before switching to product development changed how I write code. Not the testing part — the failure-mode thinking that happens before a line is written.

QAEngineeringSolo DevArchitecture
Share:

When developers ask what 13 years in QA brought to my development work, they expect an answer about testing. That's not the main thing.

The main thing is how I think about code before I write it.

Failure modes are a design input, not an afterthought

QA engineers spend most of their time thinking about what breaks, not what works. After enough years, this becomes automatic. Before I write any function, I've already thought through:

  • What's the empty state?
  • What's the null state?
  • What happens if the network call takes 30 seconds?
  • What happens if it never returns?
  • What if the user does this operation twice in rapid succession?

These aren't afterthoughts that go in a "TODO: handle error" comment. They're design inputs that shape the function signature, the return type, and the state model.

A developer who hasn't done QA typically thinks: "I'll write the happy path and handle errors later." A QA engineer thinks: "What are the five ways this fails and which ones need to be handled now?"

Edge cases are the real spec

Requirements describe what should happen. Edge cases describe what will happen.

"The user logs in" is a happy path. The real spec includes:

  • User enters wrong password three times
  • User enters correct password but server is down
  • User is already logged in on another device
  • User's session expires mid-operation
  • Network drops between authentication and profile fetch

After enough time in QA, you stop waiting for requirements to cover these. You assume they're unspecified and make decisions about them yourself — because they will happen, and the app needs to handle them somehow.

Cross-platform validation changes architecture decisions

Working across 18 device environments (Fire OS, Android TV, Tizen, webOS, dedicated signage players) taught me that the reference device is a lie. Every platform has different behavior for network timeouts, background process restrictions, screen density handling, and system font scaling.

This changes how I write code:

  • I don't assume fonts scale linearly — I test with system large text enabled
  • I don't assume background tasks complete — I verify with WorkManager's status APIs
  • I don't assume network state is binary — I handle degraded connections, not just connected/disconnected

Code written assuming the reference device fails in the field. Code written assuming every environment is slightly different survives.

Release gates as architecture

QA engineers own release gates — the criteria that determine whether software ships. After years of owning that responsibility, I build release confidence into the code itself rather than bolting it on at the end.

Concretely:

  • Error states are first-class UI states, not
    code
    null
    checks
  • Logging is structured and queryable, not
    code
    println()
  • Critical paths have fallbacks, not just error messages
  • Version migrations are tested explicitly, not assumed to work

This isn't extra work. It's the same code — just written with the question "how would I debug this in production?" in mind from the start.

The most useful QA skill: asking "what could go wrong?"

There's a specific mental mode that QA engineers develop — a persistent background process that's always asking "what could go wrong with this?" while they're doing anything else.

In development, this means:

  • Before merging a PR: "What does this break that I haven't tested?"
  • Before shipping: "What user behavior haven't I considered?"
  • Before adding a dependency: "What breaks if this library has a bug?"

Most bugs aren't from code that was written wrong. They're from code that was written for a case that wasn't considered. The QA mindset is about expanding what you consider.

What it doesn't do

QA thinking doesn't replace unit tests, integration tests, or user research. It doesn't guarantee bug-free code. It doesn't make you write slower — the edge cases you think about before writing are faster to handle than bugs you discover after shipping.

It's a frame, not a methodology. The code looks the same. The decisions behind it are different.

Share:
S

Sudarshan Chaudhari

AI Systems Builder / Product Engineer

Bangkok, Thailand

Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.

Stay updated

Get new posts on Android, Kotlin, and solo dev straight to your inbox.

Newsletter preferences

Building something? Available for Android dev and QA consulting.

Work with me

Comments — powered by Giscus