All posts

Breaking down the task that scares you

Published May 9, 2026 · by Majd Ghithan, written with the help of AI

Breaking down the task that scares you

There's a specific kind of ticket that makes my stomach drop. Not the hard ones, hard is fine. It's the ambiguous ones. "Migrate billing to the new provider." "Add multi-tenancy." Four words that hide a month of unknowns, and every time I've opened one of these I've felt the same pull: to stall, to reorganize my desk, to do literally any other ticket first.

I've learned that the fear isn't about difficulty. It's about not being able to see the shape of the thing. And you don't fix "I can't see it" by staring harder. You fix it by cutting it up until each piece is something you've done before.

The fear is uncertainty, not size

A big task you understand isn't scary, it's just long. You can see the pieces, you know roughly how each one goes, you just have to do them. What actually triggers the dread is the part you can't see: the new provider's API you've never touched, the legacy code nobody understands, the "how does auth even work here" question you've been avoiding.

So the first move isn't to plan the whole thing. It's to find the single scariest unknown and attack that first, while everything else waits. (This is the cousin of estimating in ranges, the width of your estimate and the size of your fear come from the exact same place: the parts you haven't seen yet.)

Kill the biggest unknown first with a spike

A spike is throwaway code whose only job is to answer a question. Not to ship, not to be clean, just to convert "I have no idea if this is even possible" into "okay, now I know."

When I had to migrate billing, the thing keeping me up wasn't the hundred small tasks. It was one question: does the new provider's webhook actually give us enough to reconcile a payment? So before planning anything, I spent half a day wiring the ugliest possible test, hardcoded keys, one endpoint, print the payload. Deleted it after. But now the scariest unknown was dead, and the rest of the work went from a fog to a list.

Slice into shippable pieces, not layers

Here's the mistake I made for years: I'd break a big task by layer. First all the migrations, then all the models, then all the controllers, then wire up the UI. It feels organized. It's a trap. You have nothing that works until the very end, so you get no feedback, no proof, and no morale for two weeks, and if the estimate was wrong you find out far too late to react.

The better cut is vertical: each slice is a thin, complete path that actually works end to end, even if it does almost nothing.

Sliced by layer (scary)
1. All DB migrations
2. All models + relationships
3. All controllers
4. All the UI
5. Wire it together + pray

-> nothing works until step 5
Sliced vertically (shippable)
1. One provider, one plan, hardcoded -> a real charge succeeds
2. Same path, real plan data from DB
3. Add webhook -> mark paid
4. Add the second plan
5. Handle failures + refunds

-> something real works after step 1

The right column ships something true on day one, a single charge that actually goes through. Ugly, narrow, hardcoded, but real. Everything after that is widening a path that already works, which is a completely different feeling from building four disconnected layers and hoping they meet.

Each slice should teach you something

The best slices aren't just small, they're ordered so the early ones resolve the biggest risks. If the whole thing might fail because of one integration, that integration is slice one, not slice five. You want to be wrong early, while being wrong is cheap and there's still time to change course.

That's the real payoff of slicing a scary task: you're not just making it smaller, you're rearranging it so the questions that could sink the whole project get answered first, when you can still do something about the answer.

The mindset

A task feels scary in proportion to how much of it you can't see. You can't make yourself braver, but you can make the task smaller and clearer until there's nothing left to be scared of, just a list of things you already know how to do.

So when the four-word ticket lands and your stomach drops, don't push through the fear and don't stall. Name the scariest unknown, spend a few hours killing it, then slice what's left into thin paths that each work on their own. The dread was never about the work. It was about the fog. Cut the fog and the work is just work.

🤖 Heads up: this post was drafted with AI. Spot something wrong or off?Edit it on GitHub & open a PR
Majd Ghithan

Majd Ghithan

Full-Stack Engineer & Tech Lead

More posts

Laravel finally resizes images for you

Laravel finally resizes images for you

Every Laravel app I've built that takes an avatar ended the same way: composer require intervention/image, wire up a facade, write a little service class, and hope the next dev…

July 26, 2026Read more
What actually breaks at 100,000 users (that never breaks in a demo)

What actually breaks at 100,000 users (that never breaks in a demo)

The first time I shipped a dashboard to a hundred thousand active users, nothing I had tested was what broke. Everything that failed had passed every check I ran. It worked on m…

July 25, 2026Read more
Where your queue jobs go to die under load

Where your queue jobs go to die under load

The support ticket said "I never got my invoice email." I checked the logs. The job ran. It succeeded. failedjobs was empty. Everything said the email went out. It did not.

July 18, 2026Read more
The indexes you're missing (and the one that's hurting you)

The indexes you're missing (and the one that's hurting you)

A client sent me a query that took 4.2 seconds. One WHERE, one ORDER BY, a table with three million rows. I added a single index and it dropped to 11 milliseconds. They asked if…

July 11, 2026Read more
Caching in Laravel without the stampede

Caching in Laravel without the stampede

We cached the homepage's "trending products" query for five minutes. It was our slowest query — about 900ms, a big aggregation across orders. Caching it took the homepage from s…

July 4, 2026Read more
Taking one endpoint from 800ms to 80ms

Taking one endpoint from 800ms to 80ms

The order-details endpoint took 800 milliseconds. Not broken, just slow enough that the app felt heavy everywhere it was used. The team's instinct was "the server needs more mem…

June 27, 2026Read more
The N+1 you can't see (it's hiding in your accessors)

The N+1 you can't see (it's hiding in your accessors)

I've fixed hundreds of N+1 queries. The easy ones are right there in the controller — a foreach with $order-customer inside it, obvious the moment you read the code. Those aren'…

June 20, 2026Read more
The Friday deploy that charged customers twice

The Friday deploy that charged customers twice

It was 4:40 on a Friday. The change was tiny — a one-line tweak to how we called the payment provider, plus a bump to the queue worker's timeout. Small, tested, reviewed. I depl…

June 13, 2026Read more
Code review people don't dread

Code review people don't dread

I once left forty-one comments on a junior's pull request. I was proud of it. Thorough, I told myself. The next day he barely made eye contact, and his next PR sat open for a we…

June 6, 2026Read more
Hiring a mid-level Laravel dev: the signals that actually matter

Hiring a mid-level Laravel dev: the signals that actually matter

The best hire I ever made failed my first question. I asked him to explain service containers and he stumbled, went quiet, then said "honestly I use them every day but I've neve…

May 30, 2026Read more
Saying no to a feature without being the 'no' person

Saying no to a feature without being the 'no' person

For about a year I was the engineer everyone learned to route around. Not because I was wrong, I was usually right, but because my answer to new ideas was a flat "no, that'll br…

May 23, 2026Read more
My first 90 days as a tech lead (and the habit I had to break)

My first 90 days as a tech lead (and the habit I had to break)

Three weeks into leading my first team, I stayed late to "help" by rewriting a junior's feature myself. It was faster my way. I pushed it, felt productive, went home. The next m…

May 16, 2026Read more
1:1s that aren't just status updates

1:1s that aren't just status updates

For my first few months as a lead, my 1:1s were thirty minutes of me asking "so, what are you working on?" and nodding at answers I already knew from standup. We both left sligh…

May 2, 2026Read more
Get the business logic out of your controllers

Get the business logic out of your controllers

I once opened a OrderController@store method that was 240 lines long. Validation, a discount calculation, three model writes, a Stripe charge, two emails, a Slack notification,…

April 25, 2026Read more
Form Requests are the most underrated thing in Laravel

Form Requests are the most underrated thing in Laravel

Most Laravel devs meet Form Requests once, in a tutorial, use them to hold a rules() array, and never look deeper. That's a shame, because a Form Request is the cleanest place i…

April 18, 2026Read more
Testing Laravel without mocking everything

Testing Laravel without mocking everything

I inherited a codebase once with 900 unit tests and no confidence. Every test mocked the repository, mocked the model, mocked the mailer, mocked the thing three layers down. The…

April 11, 2026Read more
Three Eloquent features that clean up your models

Three Eloquent features that clean up your models

The messiest Laravel model I ever wrote wasn't messy because of Eloquent. It was messy because I ignored the parts of Eloquent that exist specifically to keep it clean. The same…

April 4, 2026Read more
The migration that locked the table for eight minutes

The migration that locked the table for eight minutes

The deploy looked boring. One migration, adding a lastseenat column to the users table with a default of now(). I'd written a hundred like it. I ran it at 2pm on a Tuesday becau…

March 28, 2026Read more
Chasing a memory leak in a Laravel queue worker

Chasing a memory leak in a Laravel queue worker

The alert came in at 4am: one of our queue:work processes had been OOM-killed. The supervisor restarted it, it processed jobs for about forty minutes, and got killed again. It w…

March 21, 2026Read more