Every developer hears the same advice: "Build side projects."
So we follow tutorials. Clone popular apps. Deploy to Vercel. Add another line to the resume.
It looks productive. It rarely makes you a better engineer.
The Real Problem
Most side projects:
- Solve already-solved problems
- Avoid hard decisions
- Ignore failures and scale
- End at "v1 is done"
Real engineering doesn't work like that.
Real Projects Have Constraints
Instead of asking "What app should I build?"
Ask: "What problem should this system survive?"
Add constraints:
- What if traffic spikes?
- What if a service goes down?
- What if data becomes inconsistent?
The moment constraints appear, architecture matters.
Think in Systems, Not Screens
Start with data flow, not UI.
Ask:
- Where can this break?
- What must be async?
- What needs retries?
- What must be idempotent?
Even a simple backend becomes interesting when failure is allowed.
Example: URL Shortener
Tutorial version:
- Store URL in database
- Generate short code
- Redirect on GET
Systems version:
- What if two users get the same short code?
- How do you handle 10k redirects/second?
- How do you track analytics without blocking redirects?
- What if your database is in a different region?
See the difference?
Trade-offs > Features
Good engineers make trade-offs and explain them.
Write things like:
## Why Redis for caching
Improves latency by ~200ms.
Risk: stale data if URL is updated.
Mitigation: 5 minute TTL.
## Why async analytics
Slower than sync writes.
But won't block redirects if analytics DB is down.
Put this in your README. It matters more than screenshots.
If You Can't Observe It, You Don't Own It
Add basics:
logger.info('URL created', { shortCode, userId });
metrics.increment('url.created');
metrics.timing('url.lookup', duration);
If you can't answer "what broke and why," the project isn't finished.
Let It Break. Then Fix It.
Real systems are never done.
Break your own project:
- Simulate database downtime
- Send 1000 concurrent requests
- Fill database with 1M records
- Deploy on 512MB RAM
- Make your API dependency timeout
Then fix it. Refactor it. Scale it. Repeat.
That loop is where engineers are made.
The Resume Is a Side Effect
Stop building projects for your resume.
Build systems that survive failure.
The resume will take care of itself.
Top comments (1)
15 years ago, shortly after I was hired for a developer position, the director (my skip boss) chatted with me and said my résumé was the worst he had ever seen. No pizzazz. Absolutely boring. (And my referral at the company happened to quit in the meantime — ironically he and I both started our new jobs at each of our new companies on the same day.)
I still got the job. Despite my dull, lackluster résumé.
It also got me my next job. After I was hired there, me and my coworkers who interviewed me all laughed at my dull, lackluster résumé. I was not offended in the least, I thought it was funny.
Since that was going to be my final forever job, I didn't bother updating it.
Several years later I got a phone call from a former coworker from three companies back that I should apply for an open req. I dusted off my dull, lackluster résumé, ran the interviewing gauntlet, and landed the job. My thinking was that I should at least practice interviewing, but it turned out to be an opportunity I could not pass up.
One thing I had done with my dull, lackluster résumé about 35 years ago is that I had pruned it from some of the things I had done. I took out anything about technologies or programming languages I never wanted to work with again. Shrunk it by half.