When Everything Stopped Working
3:17 AM.
I should be sleeping. I have class in 5 hours.
Instead, I'm staring at my laptop screen, watching my movie
booking app crash. Again. And again. And again.
The error message mocks me:
"Cannot read property 'price' of undefined"
I've been debugging this for 6 hours.
SIX. HOURS.
For context: I'm in my final year of BCA (Bachelor's in Computer
Application). I've taken courses in Data Structures, Algorithms,
Database Systems, Software Engineering.
I have a CGPA of 8.3/10. I'm a "good student."
But none of that prepared me for this moment - sitting alone at
3 AM, completely stuck on a bug that should be "simple."
This is the story of how one stupid bug taught me more about
programming than three years of lectures ever did.
The App (And The Bug)
The app was straightforward - a Flutter movie booking system for
my university project. Users could:
Browse movies
Select theaters and showtimes
Choose seats
See total price
Complete booking
I'd been working on it for 2 months. Everything worked perfectly.
Until I added ONE feature: "Early bird discount - 20% off for
bookings before 6 PM."
Suddenly, the app crashed whenever someone selected a seat.
Here's the code that was breaking:
// Calculate total price
double calculateTotal() {
double total = 0;
selectedSeats.forEach((seat) {
total += seat.price; // ← Crashes here
});
// Apply discount if applicable
if (isEarlyBird) {
total *= 0.8;
}
return total;
}
The error: "NoSuchMethodError: The getter 'price' was called on null"
My thought process:
"But seat DEFINITELY has a price property. I set it right here!"
final seat = Seat(
id: 'A1',
price: 150,
isAvailable: true,
);
class Seat {
final String id;
final double price;
final bool isAvailable;
Seat({required this.id, required this.price, required this.isAvailable});
}
I added print statements everywhere:
print('Selected seats: $selectedSeats');
// Output: [Seat(id: A1, price: 150), Seat(id: B2, price: 150)]
print('Seat: $seat');
// Output: Seat(id: A1, price: 150)
print('Seat price: ${seat.price}');
// Output: 150
Everything looked fine!
But it kept crashing.
The Debugging Journey (Or: Descent Into Madness)
9 PM: "This should be easy. Just a simple null check."
try {
total += seat.price;
} catch (error) {
print('Error: $error');
}
Still crashes. Try-catch doesn't even help?!
10 PM: "Maybe it's a timing issue?"
Future.delayed(Duration(seconds: 1), () {
calculateTotal();
});
Nope. Still crashes.
11 PM: "Is Firebase sending corrupted data?"
Check Firebase print. Data looks perfect.
{
"seats": {
"A1": { "price": 150 },
"B2": { "price": 150 }
}
}
12 AM: "Maybe I need to reinstall everything?"
flutter clean
flutter pub get
20 minutes later... still crashes.
1 AM: "Is this a Dart bug? Is my laptop possessed?"
Test in DartPad:
final seat = {'price': 150};
print(seat['price']); // Works fine
Not a Dart bug. Not possessed. Just me being an idiot.
2 AM: "Stack Overflow will save me!"
Search: "The getter 'price' was called on null"
10,000 results. None match my exact situation.
Try random solutions from Stack Overflow:
Check for null ✓ (already did)
Use null-aware operator ✓ (doesn't help)
Validate data structure ✓ (looks fine)
2:30 AM: The Bargaining Stage
"Please, code. I'll write better comments. I'll use strong typing.
I'll stop using dynamic. Just work."
Code doesn't care about my promises.
3 AM: The Acceptance Stage
Maybe I'm not cut out for programming.
Maybe I should change careers.
Maybe I should become a farmer.
Farmers don't deal with null properties.
The Breakthrough (Thanks To Rubber Duck Debugging)
3:17 AM. Completely exhausted.
I remember something my professor mentioned once: "Rubber Duck
Debugging" - explain your code to an inanimate object.
I don't have a rubber duck. I have a tea mug.
Me, to my mug: "Okay, so when the user selects a seat, I add it
to the array..."
I pull up the code:
void handleSeatSelect(String seatId) {
final seat = availableSeats.firstWhere(
(s) => s.id == seatId,
orElse: () => null,
);
if (seat != null && seat.isAvailable) {
setState(() {
selectedSeats = [...selectedSeats, seat];
});
}
}
Me, still to the mug: "Then when I calculate the total, I loop
through selectedSeats and add each seat's price..."
Wait.
WAIT.
What if firstWhere returns null?
No, that's impossible. I'm only calling this function when a seat
is tapped, and I'm only showing available seats...
Unless...
Oh.
OH NO.
I check my "apply discount" code:
void applyEarlyBirdDiscount() {
selectedSeats.forEach((seat) {
seat.price = seat.price * 0.8; // ← MODIFYING the original object!
});
}
And my "calculate total" code:
double calculateTotal() {
double total = 0;
selectedSeats.forEach((seat) {
total += seat.price; // ← Trying to read the MODIFIED price
});
return total;
}
Here's what was happening:
User selects seat A1 (price: 150)
selectedSeats = [Seat(id: A1, price: 150)]
User applies early bird discount
applyEarlyBirdDiscount() runs
seat.price becomes 120 (150 * 0.8)
BUT... this modifies the REFERENCE
availableSeats ALSO gets modified (same object!)
User deselects seat, then selects again
firstWhere() finds the seat, but price is now undefined because...
Actually, wait. That's not it either.
Let me trace through this more carefully...
Another 20 minutes of debugging
FOUND IT:
void applyDiscount() {
final discounted = selectedSeats.map((seat) {
return Seat(
id: seat.id,
price: seat.price * 0.8,
isAvailable: seat.isAvailable,
);
}).toList();
setState(() {
selectedSeats = discounted; // ← This runs
});
calculateTotal(); // ← This runs immediately after
}
The problem: setState is ASYNCHRONOUS.
When calculateTotal() runs, selectedSeats STILL has the old values.
But I'm trying to calculate based on the NEW (discounted) values.
So sometimes:
selectedSeats has the new objects (with discounted prices)
But sometimes it's in a weird in-between state
Where some objects are updated and some aren't
Leading to null when accessing properties
The fix was stupidly simple:
void applyDiscount() {
final discounted = selectedSeats.map((seat) {
return Seat(
id: seat.id,
price: seat.price * 0.8,
isAvailable: seat.isAvailable,
);
}).toList();
setState(() {
selectedSeats = discounted;
});
// Don't call calculateTotal() directly
// Let Flutter rebuild the UI first
}
Then inside didUpdateWidget or using a ValueNotifier/State management:
@override
void setState(VoidCallback fn) {
super.setState(fn);
calculateTotal(); // Runs AFTER state updates are applied
}
It worked.
After 6 hours.
I wanted to laugh. And sleep.
What My Computer Science Degree Taught Me
In three years of university, I learned:
✅ Data Structures (Arrays, Trees, Graphs)
✅ Algorithms (Sorting, Searching, Big O)
✅ Database Theory (Normalization, SQL, ACID)
✅ Object-Oriented Programming (Classes, Inheritance, Polymorphism)
✅ Software Engineering (SDLC, Design Patterns, Testing)
All important. All useful.
But none of it prepared me for:
❌ Asynchronous state updates in React
❌ JavaScript's weird mutation behavior
❌ The pain of debugging at 3 AM
❌ How to actually FIND bugs (not just understand algorithms)
❌ The emotional rollercoaster of programming
❌ How to explain my code to a coffee mug
What The 3 AM Bug Actually Taught Me
Lesson 1: Understanding syntax ≠ Understanding behavior
I knew flutter. I'd passed exams. I could write functions,
loops, objects.
But I didn't understand:
- How state updates work
- When re-renders happen
- How to captures variables
- The difference between reference and value
You can know syntax perfectly and still write broken code.
Lesson 2: print is your best friend
University taught me about debuggers and breakpoints.
Reality? print() at 3 AM is more effective than any fancy
debugging tool.
print('1. Before discount:', selectedSeats);
// Add discount logic
print('2. After discount:', selectedSeats);
// Calculate total
print('3. During calculation:', seat);
Primitive? Yes. Effective? Absolutely.
Lesson 3: The best debugging technique is explaining your code
Rubber duck debugging sounds silly.
It works.
The act of explaining forces you to question your assumptions:
"When I click this button, it calls this function, which updates
this state, which triggers this re-render, which... wait, does it
trigger the re-render IMMEDIATELY or AFTER the function finishes?"
Boom. Bug found.
Lesson 4: Async is HARD
I thought I understood asynchronous code.
setState() happens "later"
API calls happen "later"
But truly understanding the ORDER and TIMING? That only comes
from breaking things at 3 AM and fixing them.
Lesson 5: Programming is 10% writing code, 90% debugging
University projects are nice and tidy. Assignments work the first
time (or second, or third with clear error messages).
Real projects? You spend HOURS hunting down bugs that turn out to
be a single missing character or a misunderstood concept.
Nobody teaches you that in class.
Lesson 6: The best learning happens when you're stuck
When everything works, you don't learn much.
When nothing works and you spend 6 hours fixing it? You learn:
- How state really works
- How to debug systematically
- How to read error messages carefully
- How to not give up
- How to explain problems clearly
That 3 AM bug taught me more about React than any tutorial ever did.
Lesson 7: You're not dumb, you're learning
At 2 AM, I genuinely thought I wasn't smart enough to be a
developer.
At 3:30 AM, I realized everyone goes through this.
The senior developers I admire? They've all had their 3 AM bugs.
The difference between a junior and senior developer isn't that
seniors don't get stuck.
It's that they've been stuck SO MANY TIMES they know how to get
unstuck faster.
Top comments (0)