When I started building a fitness application for workout tracking, I did not begin with a strong vision of the final product. I did not know exactly how the app would look, how users would interact with it, or how complex it would become. What I did know was that I wanted to learn by building something real instead of staying in theory.

At that stage, perfection felt attractive but unrealistic. Every decision seemed important, and waiting for the “right” one created hesitation. I quickly realized that if I stopped every time something felt unclear, the project would never move forward.

Momentum became my main driver. Writing code, seeing something work, breaking it, and fixing it again gave me more clarity than any planning document could. This way of working slowly shaped my approach.

That approach is what I later started calling Vibe Coding. It is not about ignoring best practices, but about respecting movement, learning, and progress. It is about allowing the product to teach you what it needs.
Another important reason this project even started was personal motivation. I had a clear fitness goal for myself and wanted a better way to track workouts, progress, and consistency. Instead of looking for the perfect app, I decided to build something that worked exactly the way I needed. Knowing that I was building this for my own use made a big difference. Every feature had a direct purpose, and every improvement solved a real problem I personally faced. This connection between a personal goal and a technical challenge created strong motivation. On days when development felt hard or slow, the fitness goal reminded me why I started. Building something for myself removed pressure and replaced it with curiosity. It made learning feel useful instead of forced. This personal connection became one of the strongest drivers behind both the project and the Vibe Coding mindset.

How It All Started
The project began with a very simple intention: I wanted to learn Flutter properly and understand how mobile applications work beyond surface-level knowledge. I had experience with web development, but mobile felt like a different world with different rules, limitations, and expectations. To close that gap, I enrolled in a Udemy course focused on Flutter fundamentals. At first, the content felt overwhelming. Widgets, state, layout constraints, navigation, lifecycle — everything was new and required a different way of thinking.

I followed the course step by step, building small examples and trying to understand why things worked the way they did. I broke things on purpose just to see what would happen. I changed layouts, removed state handling, and rewired navigation flows to learn through mistakes. This phase was slow and sometimes frustrating, but it was essential. It helped me build intuition instead of just copying code.

At some point, I noticed that I was no longer just following lessons. I was changing things because I wanted them to behave differently. I was experimenting instead of repeating. That was an important shift. The project stopped feeling like homework and started feeling like something I owned.

Eventually, I realized I could use this learning project to build something real. I chose a workout tracking app because it was complex enough to challenge me but familiar enough to reason about. That decision changed everything. Learning turned into responsibility. Temporary choices suddenly mattered.

From Learning Project to Real Product

Once I decided to treat the app as a real product, the complexity increased immediately. Learning Flutter alone was no longer enough. I needed persistent data, authentication, proper APIs, and a backend that could grow. This is where Laravel came in. I was comfortable with it and knew it would allow me to move fast.

Connecting the Flutter frontend with the Laravel backend was one of the first reality checks. Nothing worked perfectly on the first try. APIs changed frequently because I was still discovering what data the app truly needed. Some responses were too simple, others too complex. I often had to change both frontend and backend in the same session.

This back-and-forth was exhausting at times. It felt like the ground was constantly moving. But stopping to redesign everything every time would have killed momentum. Instead, I accepted that many things would be rewritten. That acceptance was painful but freeing.

This is a struggle many developers face but rarely talk about. We want our first version to be clean and correct. In real products, first versions are usually wrong. Accepting that early saved me months of hesitation. I learned that moving forward imperfectly was better than standing still perfectly.

Building Without Perfect Architecture

Architecture was one of my biggest internal battles. I care deeply about clean code and structure. I like clear boundaries, well-defined responsibilities, and systems that make sense. Early in the project, I tried to design for all future scenarios. That effort slowed everything down.

I noticed a pattern. Every time I tried to make the system “future-proof,” progress stopped. I was designing solutions for problems I had not experienced yet. This created complexity without value. It also increased mental load and reduced motivation.

Vibe Coding helped me step back and change perspective. Instead of asking how the system should look in one year, I started asking what the system needs today. This shift changed everything. Architecture became something that evolves, not something that blocks progress.

When real usage patterns appeared, refactoring felt natural. It felt justified instead of forced. I was no longer guessing. I was responding. This reduced stress and improved code quality over time.

This struggle is common among experienced developers. Knowing best practices can sometimes slow you down more than help you. Learning when to apply them is just as important as knowing them.

Learning Through Real Usage

Once the app became usable, real problems started showing up. Some workout flows that looked logical in code felt confusing when used in practice. Some buttons were technically correct but placed poorly from a user perspective. These issues were invisible during planning.

Data modeling also changed through usage. Fields I thought were optional became critical. Others that seemed important were barely used. These insights only appeared because something real existed.

Performance followed the same pattern. With test data, everything worked fine. With real usage, bottlenecks appeared. Fixing them required understanding behavior, not theory.

This phase was emotionally challenging. It is hard to see your assumptions break. But it was also the most valuable learning stage. Momentum turned mistakes into feedback.

I learned that real usage is the best teacher. No amount of planning replaces it.

The In-App Purchases Reality Check

In-app purchases were one of the hardest challenges I faced. Apple and Google ecosystems are complex, strict, and constantly changing. Even small mistakes can block progress for days. The learning curve here was steep and frustrating.

Documentation exists, but it is often fragmented and difficult to follow. Some steps only make sense after failing once. Testing subscriptions added another layer of complexity.

What made this worse was how fast things change. Many resources were outdated. Even AI tools struggled to provide accurate answers because platform behavior had changed.

This forced me to rely more on official documentation, trial and error, and patience. Progress here was slow and mentally draining. But stopping was not an option.

This struggle taught me that not all problems can be solved quickly. Some require persistence more than skill.


Using AI Without Losing Control

AI tools like Codex were incredibly helpful, especially when working with large codebases or repetitive tasks. They helped maintain context and speed up changes. But they were not magic.

The quality of output depended entirely on how well I described the problem. Vague prompts produced vague code. Clear needs produced useful results. Writing good prompts became a skill.

Even with Vibe Coding, connecting Flutter, Laravel, Apple, and Google was mostly manual work. AI could assist, but it could not understand the full system without guidance.

I learned never to give the wheel completely to AI. Every output was reviewed. Every change was tested. I committed often to keep control and reduce risk.

AI is a powerful assistant, but responsibility stays with the developer.

Keeping Motivation Alive

Long projects test motivation more than skill. There were days when progress felt invisible. Energy dropped slowly, not suddenly. Recognizing this early helped me react.

Small wins became essential. Finishing a screen, fixing a bug, or improving a flow brought momentum back. These moments mattered more than big milestones.

Perfect code never motivated me. Seeing something work did. Progress created energy, and energy created more progress.

This cycle kept the project alive when motivation was low.

Final Thoughts

This fitness workout tracking app started as a learning experiment. It became real through momentum, not perfection. Every struggle shaped how I work today.

Vibe Coding helped me stay productive in uncertainty. It helped me accept imperfect solutions and trust progress. It reminded me that clarity comes from movement.

If there is one thing I learned, it is this: waiting for perfect conditions is the fastest way to stop. Build, learn, adjust, and keep moving.

That is what Vibe Coding really means.

Leave a Reply


The reCAPTCHA verification period has expired. Please reload the page.