Back to all writing

How a Tiny Practice App Started Becoming a Learning System

IPMAT Series•Part 4•6 min read•By Mikhil

How a Tiny Practice App Started Becoming a Learning System

The first version worked.

That was both satisfying and slightly dangerous.

Because once something works, you immediately start seeing everything it cannot do.

I had a functioning practice loop.

I could answer questions.

The app could remember mistakes.

I could save questions.

I could come back later.

That was enough to prove the basic idea.

But it still felt like a tool that served questions.

I wanted it to start behaving more like something that understood the learning process.

That meant adding memory.

Progress.

Repetition.

Motivation.

And eventually, some intelligence.

Mistakes should not disappear

The most obvious place to start was review.

If I got something wrong, the app needed to remember that.

Not forever.

But long enough for me to prove that I had actually repaired the mistake.

So I started treating wrong answers as unfinished work.

A question could move into review.

I could encounter it again later.

If I answered it correctly, the app could clear that miss.

This sounds tiny.

But it changed the emotional meaning of getting something wrong.

A mistake stopped being a dead end.

It became something the system expected me to return to.

That is much closer to how I wanted the app to teach.

Bookmarks stayed separate

I kept bookmarks independent from mistakes.

That distinction became more important as the review system grew.

If I got something wrong and later fixed it, the miss could disappear.

But if I had deliberately saved the question, it should stay saved.

That meant the app was beginning to understand different kinds of user intent.

One state represented weakness.

The other represented interest.

The difference matters.

Then came the streak

I wanted the app to make consistency visible.

Not in a dramatic way.

Just enough to create a small reason to come back.

So I added a streak system based on the local calendar.

If I completed enough meaningful practice in a day, that day counted.

At first, the target was simple:

6 unique practice questions.

That matched the original session size nicely.

One proper session could keep the streak alive.

I liked that because it was achievable without being completely meaningless.

XP made progress feel less invisible

Then I added XP.

Again, not because the app needed to become a game.

But because studying often has almost no immediate feedback.

You solve something.

You understand it.

Then you move on.

The benefit exists, but it is invisible.

XP gave the app a way to acknowledge effort.

A first-time correct answer could award XP.

The system could show that number.

Your total could grow.

You could actually see that you had done something.

But I did not want XP to become farmable.

If I could answer the same easy question twenty times and generate infinite progress, the number would become meaningless.

So repeated answers needed to behave differently from genuine first-time success.

The number only works if it still represents something.

Tiny feedback details started mattering

Once I added progress systems, I started paying more attention to how the app felt.

Correct answers needed better feedback.

Session completion needed to feel satisfying.

XP gains needed to be visible without becoming obnoxious.

Sounds and haptics started entering the design.

Reduced motion also mattered.

I wanted the app to feel alive, but not exhausting.

That became a recurring theme.

There is a very thin line between making studying feel rewarding and turning every interaction into a slot machine.

I wanted to stay on the useful side of that line.

The question bank doubled

The original 32 questions did their job.

They proved the loop.

But they were not enough for regular use.

So the bank expanded to 64 original questions.

That still sounds small compared to a commercial question bank.

And it is.

But I cared more about making the questions useful than making the number impressive.

Every expansion gave me more room to test:

Difficulty.

Topic balance.

Explanations.

Repeated exposure.

Progress tracking.

Review behaviour.

It also made it obvious that content quality would eventually become one of the hardest parts of the product.

Writing software is one problem.

Building good educational material at scale is another.

Then vocabulary became its own system

This was one of the biggest changes.

The project had started because I wanted a better way to learn vocabulary.

But ironically, the earliest working version focused more heavily on question practice.

That started changing.

I began building a proper vocabulary-learning layer.

Instead of only encountering words inside MCQs, I wanted to be able to browse and learn them directly.

That eventually grew into a collection of 154 vocabulary cards.

Now the app had two related but different learning loops.

One was question-based practice.

The other was direct vocabulary learning and review.

That made the product feel much closer to the thing I had originally wanted.

The streak had to evolve too

Once vocabulary became a real part of the product, the original streak rule started feeling too narrow.

Why should a student lose a streak after spending meaningful time reviewing vocabulary just because they did not complete six practice questions?

That would mean the system was rewarding one learning mode while ignoring another.

So the streak logic expanded.

A day could count through:

6 unique practice questions

or

3 reviewed or learned words.

That small change made the system better aligned with the actual behaviour I wanted to encourage.

The streak was no longer tied to one specific screen.

It was tied to meaningful learning activity.

Progress became more than a number

I also wanted the app to show activity over time.

Not just total XP.

A simple seven-day view could show whether I had actually been consistent.

Practice days mattered.

Streak history mattered.

The number of questions solved mattered.

Vocabulary activity mattered.

Eventually, topic weakness and accuracy should matter too.

The more I worked on this, the less interested I became in vanity metrics.

I do not care that I solved 500 questions if I keep making the same grammar mistake.

I care whether the system can notice that.

That is where the project needs to go.

This is where the app changed category

At the beginning, it was basically:

Give me six questions.

Now it had:

Practice.

Review.

Bookmarks.

Progress.

Streaks.

XP.

Activity tracking.

A growing question bank.

A dedicated vocabulary layer.

Different ways to complete a productive day.

That does not make it an intelligent tutor.

Not even close.

But it does mean it stopped being a static question page.

It started maintaining state across time.

It started remembering what I had done.

It started shaping what I should return to.

It started rewarding consistency.

And once a product starts doing those things, architecture becomes much more important.

Because now there is data worth protecting.

Progress worth preserving.

State worth syncing.

And eventually, multiple devices that need to agree with each other.

That is where the next problem appeared.

I wanted the app to work even when my internet did not.