/images/avatar.png

Mohamed Shalan

When Less Is More: Rebuilding Easy Analytics v2.0.0

I spent three days debugging a bug I found in 20 minutes. The bug was simple: Fragment tracking wasn’t firing correctly in ViewPagers. The fix was obvious once I located it—a timing issue with bytecode injection. But between finding it and feeling confident enough to fix it? Three days of reading through a monolithic file where everything depended on everything else. That file was the core of our analytics library. It did everything: scanned for annotations, detected class types, chose instrumentation strategies, injected bytecode, logged debug info, handled errors.

When Your Test Coverage Lies to You: A Bytecode Murder Mystery

The pull request was routine—merging some changes I’d already tested thoroughly. Then Codacy’s coverage gate blocked me: “Insufficient coverage on modified paths.” I stared at the failure message. Those paths were covered. I’d written the tests myself. Watched them pass. Green checkmarks everywhere except this one gate, claiming I’d forgotten to test code that I knew I’d tested. Fine. I’ll prove it. I ran the coverage report locally. ./gradlew jacocoTestReport and waited for the HTML output, already composing my “actually, the CI is wrong” Slack message in my head.

Stop Writing Boilerplate Analytics Code (Your Future Self Will Thank You)

We’ve all been there. You’re deep in the flow, building that perfect user experience, when suddenly you remember: “Oh right, I need to track this screen.” Then comes the familiar ritual—add the analytics call, remember the lifecycle method, serialize the parameters, and pray you didn’t miss any edge cases. Rinse and repeat for every single screen and action in your app. What if I told you there was a better way?