Archives
All the articles I've archived.
Your Custom Lint Rule Works. Will Ten Teams Accept It?
A custom Android Lint rule takes an afternoon. Rolling it out to ten teams takes an owner, tests, a stable message, a baseline ratchet and a kill switch.
Android Lint, Detekt or ktlint? Ask What the Rule Needs
Stop asking which Android linter is best. Ask what each team rule needs — types, a quick fix, resources, KMP — and pick the tool that can enforce it.
CI Says Green — So Why Did the Module Boundary Just Break?
Compiling isn't enough to protect a Flutter/Kotlin/Swift/Rust E2EE module's architecture. Five CI gates that catch boundary breaks before they ship.
How Do I Test an E2EE Chat Between Two Devices Without a UI?
A headless two-device harness for E2EE chat: real keys, real store, real backend, no screen: reproducing exhausted one-time keys and a lost session on demand.
Which Mobile Testing Tool Do I Need? Ask the Boundary, Not the Platform
JUnit, Espresso, XCUITest, Maestro, Appium: a map of mobile test tools by the boundary they verify and the realism they need, with what Google and Apple say.
The Agent Says All Tests Pass. So Why Does QC Still Reject the Build?
A green build and a rejected QA build answer different questions. One verification contract, invariants to impact scope, serves agent, reviewer, and QC alike.
Prompt Engineering Got You Here. So Why Doesn't It Scale?
Coding agents got strong; the bottleneck moved from the prompt to the workflow around it. Eight practices big tech converged on, mapped onto one 7-stage loop.
Copilot, Then Codex, Then Claude — So Why Does My Workflow Still Look Like 2022?
Three tool migrations, zero workflow changes. What METR, DORA 2025, and my E2EE work taught me about using AI vs. redesigning around it.
MethodChannel Feels Too Slow. Should Flutter Call Kotlin Directly?
MethodChannel has a real cost model, a fake mythology, and a serious rival. What the ecosystem actually ships today, which calls deserve a Dart→FFI→JNI fast path — and the memory, threading, and lifetime rules you sign up for when you take it.
Realm Runs My Whole Chat App — So Why Does It Die in a 24 MB Notification Extension?
Realm crashes at init inside the iOS Notification Service Extension's 24 MB budget. The real causes — schema discovery, an encrypted page cache, cross-process sharing Realm only added in 2023 — and what Signal does instead.
Uploading a Photo Is One POST Request. So Why Do Chat Apps Engineer It So Hard?
A 45 MB video, a moving taxi, a connection that dies at 93% — media upload is five problems wearing one trench coat. The full map: resumable chunks, optimistic UX, dedup, async pipelines, and the resilience layer nobody blogs about.
Still Debugging Flutter With print()?
Why log-grepping wastes your debugging time in Flutter — and the tools (DevTools, Crashlytics, the official MCP server) that answer each question better.
Ten Teams, One Hybrid App: Where Do You Draw the Module Boundaries?
Grab runs 1,000+ modules in one app, Reddit's Android app ~800. The rules that make that survivable — contracts over imports, CI-enforced graphs — and why a Flutter module must hide behind a native boundary.
iOS Has Six Ways to Run in the Background — Which One Actually Delivers My Message?
beginBackgroundTask, BGTaskScheduler, URLSession, silent push, PushKit, NSE — a decision guide to iOS background execution, tested against an E2EE messaging core.
The App Went to the Background — Is My Code Still Running?
A background queue is not background execution. Building the iOS lifecycle mental model — foreground, background, suspended — from an E2EE core that persists sessions to SQLCipher.
The Rust Core Is Done — So How Do Kotlin and Swift Actually Call It?
UniFFI, cbindgen, or hand-written FFI? Choosing the binding layer that lets Kotlin and Swift call a Rust library — with Firefox, Element X, and Signal as evidence.
Two Frameworks Need SQLCipher, So Does the Extension — How Many Copies Does the iPhone End Up With?
E2EE and Feature X both need SQLCipher. The app links both, the notification extension links one. Counting the copies — in the graph, the bundle, and at runtime — is three different questions.
The App Links CryptoCore Fine — So Why Can't the Notification Extension Call It?
An iOS app and its Notification Service Extension are two executables. What sharing one Rust library really takes: ABI, packaging, linking, and shared state.
One Flutter Engine or Two? What Really Happens When Native Sits Between Two Flutter Screens
A FlutterEngine has one seat. Why one cached engine can't serve two Flutter segments split by native, what FlutterBoost really does, and what two engines cost.
Half Flutter, Half Native: Who Owns Navigation Mid-Migration?
Migrating Flutter to native screen by screen leaves two back stacks. A destination contract, a host router, one stack owner — and why back is the hard part.
How Does a Flutter Module Get a Token From the Native Host When the App Has Many Modules?
A Flutter package needs the host app's auth token. Every obvious answer — a MethodChannel, importing AppCore — points the dependency the wrong way. The fix is to stop passing the token.
My App Needs Realtime: WebSocket, MQTT, SSE or Push — Which Channel Should I Choose?
WebSocket, MQTT, SSE or push? The question sounds like a protocol benchmark. Messenger, Discord, Uber and Grab's own engineering posts say the channel is the smallest part of the answer.
What Should a Mobile App Use for Local Storage? How Telegram, Messenger and Signal Store Millions of Messages
Key-value, SQLite, Realm, files, secure storage — the choice looks like a benchmark question. The apps that store millions of messages say it's an architecture question.
Telegram Doesn't Load Your Chat History. So Why Do Thousands of Messages Appear Instantly?
Telegram clients don't fetch history to render a chat — they render what they already know. A source-verified tour of pts, getDifference, known ranges, and the sync engine behind instant-feeling chats.
WhatsApp, Signal, Messenger, Telegram: How Do They Really Encrypt Your Messages?
One tap on Send, four very different journeys. What E2EE actually changes in WhatsApp, Signal, Messenger and Telegram — and what it can't protect.
I Made Messages Load Fast. So Why Does Scrolling Still Stutter?
My messages loaded in double-digit milliseconds and scrolling still stuttered. A frame-pipeline deep dive, with measured numbers from a real chat workload.
What Architecture Layers Does a Mobile App Need to Survive Years of Development?
Messenger deleted 84% of its code to get fast. Telegram serves hundreds of millions from one module. Module graphs I extracted from three chat apps show which layers actually pay rent.
Flutter, React Native or Native: Is the Framework Really Why Your App Is Slow?
Snapchat was slow in native. Discord is fast on React Native. Evidence from a dozen engineering teams — plus my own A/B experiment — on what actually makes apps slow.
From Idea to Website: How to Choose Your Tech Stack
How to choose a tech stack for any website: a simple decision framework with tables, a decision matrix, and a decision tree — from blog to e-commerce.