Found my first "real" project while cleaning up GitHub. Decided to read through it.
Big mistake.
The Setup
One year ago, I built a full-stack blog app. My biggest project at the time. I was so proud.
- Authentication system
- CRUD operations
- Comment section
- File uploads
- Deployed to production
Felt like a senior developer. Showed it to everyone.
Fast forward to today. I opened the codebase.
What I Found
The Good (Surprisingly)
I actually finished something.
Not a half-done tutorial project. Not abandoned after day 3. A complete, working application.
17-year-old me deserves credit for that.
The architecture wasn't terrible.
Separated routes, controllers, models. Not perfect, but organized. I could actually follow my own logic.
It works. Still.
Checked the live site. Still running. No major bugs. Users still posting blogs.
For a beginner project? That's impressive.
The Bad (Oh No)
Then I looked at the actual code.
// My actual code from 1 year ago
const data = await fetch(url).then(res => res.json()).then(data => data).catch(err => console.log(err))
if (data != null && data != undefined && data != '') {
if (data.user != null) {
if (data.user.posts != null) {
if (data.user.posts.length > 0) {
// actual logic finally starts here
}
}
}
}
Six levels of if statements. Just to check if posts exist.
Current me would write:
const data = await fetch(url).then(res => res.json());
if (data?.user?.posts?.length > 0) {
// logic here
}
One line. Optional chaining. Done.
The Ugly (I'm Sorry)
Variable names from hell:
const x = userData;
const xx = userData.posts;
const xxx = userData.posts[0];
const data1 = xxx;
const data2 = data1.comments;
const finalData = data2;
What was I thinking? Was I allergic to meaningful names?
Comments that lie:
// fetches all users
const posts = await getAllPosts();
No. It fetches posts. The comment is wrong. The function name is right. Why did I write that comment?
The infamous TODO:
// TODO: fix this later
// FIXME: this is temporary
// NOTE: refactor this entire file
Spoiler: I never fixed it. It's still there. Still "temporary."
Password in the code:
const DB_PASSWORD = "mypassword123";
Yes. Hardcoded. In the repo. Public repo.
I'm lucky I wasn't hacked.
What I Learned About My Growth
1. I Understand Async Now
Then:
fetch(url)
.then(res => res.json())
.then(data => {
processData(data)
.then(result => {
saveResult(result)
.then(() => {
console.log('done');
})
})
})
Callback hell. I didn't understand promises.
Now:
const res = await fetch(url);
const data = await res.json();
const result = await processData(data);
await saveResult(result);
Clean. Readable. Async/await saved my life.
2. I Know When NOT to Comment
Then: Comments everywhere explaining obvious things
// increment i by 1
i++;
// check if user exists
if (user) {
Now: Comments only when code isn't self-explanatory
// Retry with exponential backoff for rate limiting
await retryWithBackoff(apiCall);
3. I Understand Error Handling
Then:
try {
// 50 lines of code
} catch (err) {
console.log(err);
}
Catch everything. Log nothing useful. Pray it works.
Now:
try {
await riskyOperation();
} catch (err) {
logger.error('Failed to process user data', {
userId,
error: err.message,
stack: err.stack
});
throw new AppError('Failed to process data', 500);
}
Specific errors. Useful context. Actual error handling.
4. I Value Readability Over Cleverness
Then: Tried to be clever
const result = users.filter(u => u.age > 18).map(u => ({...u, adult: true})).reduce((acc, u) => ({...acc, [u.id]: u}), {});
One line! So smart! Impossible to debug.
Now: Readable over clever
const adults = users.filter(user => user.age > 18);
const adultsWithFlag = adults.map(user => ({
...user,
adult: true
}));
const userMap = Object.fromEntries(
adultsWithFlag.map(user => [user.id, user])
);
More lines. Way clearer. Future me will understand this.
The Cringe Moments
My auth "security":
if (password === user.password) {
// login success
}
Plain text passwords. In 2024. I'm embarrassed.
My "validation":
if (email.includes('@')) {
// valid email
}
That's not validation. That's hope.
My error messages:
res.status(500).json({ error: 'Something went wrong' });
Every. Single. Error. Same message. Debugging was a nightmare.
What Stayed Good
Not everything was terrible:
✅ File structure made sense - Even now, I can navigate it easily
✅ Function names were descriptive - getUserPosts() does what it says
✅ Separated concerns - Routes, controllers, models in different files
✅ It works - Despite the mess, users can still use it
The Humbling Realization
One year ago, I thought this was amazing code.
Today, I see all the flaws. The inefficiencies. The bad practices.
One year from now, I'll probably look at my current code and cringe too.
That's not depressing. That's growth.
If you're not embarrassed by your old code, you're not learning.
What I'm Doing About It
Option 1: Rewrite Everything
"Let me fix all these issues!"
Reality: I'd spend weeks rewriting working code. Not worth it.
Option 2: Leave It Alone
"It works, don't touch it"
Reality: But it's public. It's on my portfolio. It represents me.
Option 3: Strategic Improvements (What I'm Actually Doing)
✅ Fixed the security issues (hashed passwords, env variables)
✅ Added proper error handling
✅ Improved the most painful parts
✅ Added a README explaining it's an old project
✅ Left the rest alone
It's a time capsule of my learning journey. That's okay.
The Lesson
Your old code will always look bad. That means you're growing.
Signs you're improving:
- You cringe at code from 6 months ago
- You spot bugs immediately in old projects
- You can't believe you didn't use X pattern
- You want to refactor everything (but don't)
If your year-old code still looks perfect, you haven't learned anything.
My Advice
Go Read Your Old Code
Pick a project from 6-12 months ago. Read it honestly.
You'll feel:
- Proud (you built something!)
- Embarrassed (what was I thinking?)
- Motivated (look how much I've grown)
All three are valid.
Don't Delete It
I almost deleted this project out of embarrassment. Glad I didn't.
It shows:
- Where I started
- How far I've come
- That I actually finish things
- My learning progression
Recruiters appreciate the growth story more than perfect code.
Learn From Past You
Every cringe moment is a lesson:
- Nested ifs everywhere? → Learn optional chaining
- Callback hell? → Master async/await
- Bad variable names? → Practice clean code
- No error handling? → Learn proper patterns
Your past mistakes are your future study guide.
One Year From Now
I'll probably read THIS post and cringe at something I said.
I'll look at my current projects and see obvious flaws.
And that will be a good sign.
It means I'm still learning. Still growing. Still improving.
Your Turn
When's the last time you looked at your old code?
Go find a project from 6+ months ago. Read through it. Come back and tell me:
- What made you proud?
- What made you cringe?
- What did you learn?
Drop it in the comments. Let's celebrate our growth (and our cringe) together.
My commitment:
Not deleting old projects. They're proof of progress, not embarrassment.
Hit ❤️ if you've ever cringed at your own code.
Top comments (0)