MJ Stories
Mobile craftsmanship stories
Offline-First KMP · Part 10
HTTP 500 Is Not a Retry
A batch write endpoint that reports some failures per operation and others as a status code does not have a contract, it has two. A status code cannot tell the client whether you refused its data or broke while processing it, and a batch verdict is a verdict on every operation at once. The only channel that can carry a per-operation failure is the body. Get it wrong and the client does not retry slowly, it stops.

Series · 10 parts
Offline-First KMP
When your mobile app must work without internet as a standard, not an edge case, the sync layer is just the first decision. What comes after — preserving user intent offline, trusting a "success" your server never actually confirmed, resolving conflicts as a human decision — is where offline-first actually gets hard. Field notes from a production KMP winery app.
- 1Choosing an offline-first sync layer for KMP
- 2Two writes for every tap
- 3Minting IDs Before the Server
- 4The Write You Never Clean Up
- 5HTTP 200 Is Not Success
- 6Your Schema Is Not Your Payload
- 7You Cannot Fix a Generated File
- 8Every Synced Row Needs an ID
- 9Your Sync Stack Fits in Three Containers
- 10HTTP 500 Is Not a Retry
More Stories
Your API key is not a secret
We have been hiding API keys in Android apps for a decade — with BuildConfig tricks, NDK, obfuscation libraries. None of it works. The fix is not better hiding; it is treating the key as a public identifier and proving the app is genuine instead.

Share iOs string resources with Android
There might be a requirement for mobile string resources to be defined or adjusted by management or copywriters. There also might be a requirement to add localization later by those roles. And on top of that strings should be synced across platforms.










