Building BiblePace with Gemini: The Highs, the Lows, and the Reality of AI-Assisted Development

Building with Gemini

See here for why I decided to build BiblePace.

I'm not familiar with building iOS or macOS apps. My only prior attempt was trying to build a small macOS utility with Gemini—and calling that experience frustrating is a massive understatement. Still, BiblePace felt like the right project to give LLMs another shot. I wasn't keen on paying for a separate monthly AI subscription for what was supposed to be a personal app, but since my Google Workspace plan included Gemini—with data privacy guarantees (Google explicitly states they don't train models on Workspace data)—it was a no-brainer.

To set things up properly, I started by outlining my core requirements, which were:

  • Multi-Platform Access: Users should be able to access the app seamlessly on the web, iPhone, or iPad.
  • Privacy First (No Mandatory Accounts): You should be able to use the app without ever being forced to create an account—all data remains stored locally on your device by default.
  • Optional Cloud Sync: You can start reading on one device and pick up on another. An account is only required if you explicitly choose to sync your progress across multiple devices.
  • Clean Experience: Zero tracking, zero clutter, and zero upselling.

With these initial requirements ready, I fed them into Gemini and asked it to:

  1. Review my specs, evaluate if they made sense, and suggest revisions if necessary.
  2. Draft a complete technical plan for building all three versions of the app (web, iPhone, and iPad).

Gemini teaches patience!


Phase 1: Setting Up the "Architect"

I was advised to structure my prompt around a custom Gem (a tailored Gemini instance) to act as my virtual team. I configured its prompt to play two distinct roles: Product Manager and Software Architect.

At first, this felt like magic. We went back and forth refining the architecture, establishing data models, and mapping out the feature set across web, iOS, and iPadOS. Once we agreed on the blueprint, I asked Gemini for a step-by-step build order. It recommended starting with the web version to validate the core logic before moving on to native mobile apps.

With a clear roadmap in place, we started coding. That is when the real friction began.


Phase 2: Building the Web App (Over-Engineering and Code Drift)

Building the web version exposed several issues with how Gemini handles generating code:

  • Over-Engineering by Default: Gemini loved introducing overly complex code patterns for simple use cases—often adding features or edge-case handlers completely outside our original product requirements. I spent significant time prompting it to strip down bloated implementations.
  • The "Total Rewrite" Habit: I would spend time refining a specific function until it worked perfectly. But the moment I asked Gemini to expand that same function to support additional capability, instead of adding to the existing code, it would completely rewrite the function—changing the name, swapping variable names, and altering the layout entirely.
  • Variable & Casing Confusion: When managing multiple functions that interacted with each other, Gemini consistently struggled with variable consistency. It would swap variable names between functions or introduce subtle case-sensitivity bugs, silently breaking function calls.

After several days of micro-managing prompts and steering it back on track, I finally had a functional web app working. Next came the real test: bringing BiblePace to iOS.


Phase 3: Transitioning to iOS (Scope Drift and Ghosting Code)

Because I (we) already had defined product requirements, a technical architecture, and a working web app, the iOS implementation was supposed to be a straightforward translation into Swift and SwiftUI.

Instead, Gemini abandoned our original blueprint.

It began generating iOS code from scratch that ignored previous structural decisions, introducing patterns that made no sense for our architecture. I had to spend considerable time corralling the code back to match our existing data structures and app logic. On top of that, all the previous habits returned: rewriting functions wholesale, changing variable names, and dropping case consistency.

Then Gemini hit the weirder edge cases:

  • System Prompt Dumps: Suddenly, instead of answering coding prompts, Gemini would randomly output the raw system prompt from my original Gem setup—spitting out long blocks of text repeating the original Product Manager and Architect guidelines instead of giving me code. This happened on a lot of occasions and it became worse as the days went by (it was just maddening). In fact, it became so bad that I abandoned the Gem entirely and went back to plain prompting.
  • Confident Hallucinations During Debugging: When we ran into SwiftUI or state-management bugs, Gemini would confidently claim "X" was the cause and provide a fix. I'd try the fix, it wouldn't work, and Gemini would immediately—and with total confidence—claim "Y" was actually the root issue and offer a completely different solution. After multiple rounds of this, I had to manually debug complex issues on my own.
  • Dropping Comments & Functionality: I usually add comments to my code especially when I'm using new functionality or as a reminder to why I have a certain piece of code. These comments were even more important for me in this exercise given that I was new to Swift and SwiftUI. Whenever I needed Gemini to expand an existing function, I would explicitly instruct it to not to remove existing comments or drop surrounding logic. It would output new code, and when I asked, "Did you keep my existing comments and functionality?", it would reply: "Yes!" However when I checked the code, I would realize it had stripped out my comments and sometimes dropped existing functionality. It apologized when called out, but this happened so many times that I realized I could no longer trust its output without doing thorough line-by-line checks.

For complex code, do not trust Gemini's output. Verify the code.


The Verdict

Despite all the headaches, BiblePace exists on iOS today because of Gemini.

As someone who wasn't familiar with native Apple development, an AI coding assistant allowed me to bridge the learning gap, build working prototypes, and navigate Swift concepts that would have taken much longer to parse through standard documentation and web tutorials.

However, an AI coding assistant is not an autonomous developer. It doesn't replace the need for critical thinking, manual debugging, or strict code reviews.

Treat an AI coding assistant like an eager junior developer with severe short-term memory loss. It can generate code at incredible speed, but you—the human—still have to be the editor, inspector, and architect holding the whole project together.

Always review Gemini's output for security loopholes.