Writing Crappy Code Is Not a Crime

Let’s start with the truth: many of us write crappy code. Not once. Not twice. Constantly.

This isn’t always a failure. — It’s often how progress happens. My code is mostly an abomination, and it always has been. I started coding in the late 1970s on a PDP-8 running the RSTS operating system at Brockton High School, coding in the Focal language. My only way to save programs was paper tape. I’m not kidding. And god help you if you dropped your paper tape while running across the quad between classes. Tom Hanks said that “there is no crying in baseball”, but I can promise you that dropping your paper tape is most certainly a reason to cry.

As per usual, I digress.

We’ve built a peculiar culture of shame around code, particularly in private-equity-backed companies. If it’s not elegant enough to impress the Clean Code gods, we apologize for it. Here’s the thing: perfection is not the goal — progress is.

As Reid Hoffman (LinkedIn’s founder) once said:

“If you are not embarrassed by the first version of your product, you’ve launched too late.”

Let’s define “Crappy”

Let’s be clear: crappy code isn’t code that doesn’t work — that’s just bad code. Crappy code mostly works, but it might be messy, verbose, overcomplicated, or just plain ugly. I say “mostly” works because it likely doesn’t handle edge cases and unexpected uses all that well. It’s the kind of code that mostly solves a problem today and probably makes you wince tomorrow. And that’s fine. Because it gets the job done. To be clear, I’m not talking about throw-away code here. In my many years in private equity, I have been hands-on with writing data conversion code — code that gets used during the conversion process and then gets thrown away. I don’t waste time on elegance and maintainability for code that gets used once and thrown away. What I am talking about here is code that goes into production — whether it’s in software that you sell to customers or internal programs that you write to run your business.

Why Crappy Code Matters

Crappy code has a bad rep, but it’s often the fastest way to learn, ship, and improve.

  • It moves projects forward. Perfect is the enemy of shipped.

  • It’s how you learn. Every “what was I thinking?” moment levels up your skills.

  • It sparks collaboration. Rough drafts invite contribution — blank pages don’t.

  • It surfaces reality. You don’t find edge cases or bottlenecks until you ship something.

The Clean Code Trap

We’ve been sold the myth that “real” engineers write flawless code from the start—total nonsense. Most real-world systems — even from billion-dollar companies — are held together by hacks, patches, and Jira tickets. These days, it’s even more complicated because your average CEO is fast becoming a true believer in replacing engineers with AI. This obsession with perfection often leads to analysis paralysis. You over-engineer for problems you don’t have yet. You might spend days polishing abstractions that may never matter. Meanwhile, the team that shipped an ugly version yesterday is already winning customers.

Crappy Code Is a Phase, Not a Failure

Some of the world's most successful software companies reportedly began as total messes.

  • Facebook’s early codebase? Chaos.

  • Amazon’s first architecture? Held together with duct tape.

  • Even NASA’s Apollo code? Full of compromises.

Because that’s how software evolves:

Build something functional -> Learn from reality ->Iterate and improve ->Repeat forever

Crappy code is not necessarily a dead end — it’s maybe the first draft of great software.

When Crappy Is a Problem

Let’s be real: “crappy” isn’t an excuse for sloppiness. It’s fine if code is messy — it’s not fine if it’s irresponsible. Here’s when it crosses the line:

  • You ignore technical debt forever. At Parkergale, we focus on buying founder-owned software companies, and we see this problem all the time. Founders often coax their engineering teams to implement a feature for a specific customer quickly. The founder usually “promises” the engineering team that they will get the time and resources to clean up the technical debt that builds up from these rushed projects. But that promise is quickly forgotten when the next “must have” feature request comes along. It’s also essential to remember that no development team writes everything in-house. You inherit technical debt from every software vendor that you use, embed in your product, or integrate into. Good old Apple always manages to stick it to all of us every year during their World Wide Developer Conference.

  • You push insecure code into production. I don’t think anyone is in denial about the importance of cybersecurity in today's world. But even rushed code needs to be designed with cybersecurity in mind from the outset. It is tough to fix deep-seated security flaws in your codebase.

  • You treat refactoring like a nice-to-have. Refactoring is often intertwined with technical debt, but it is not the same thing. Your codebase is like a house. Refactoring is tidying up the rooms — reorganizing furniture, labeling drawers, and patching cracks. The house works the same way, but it’s easier to live in. Eliminating technical debt is akin to replacing a leaky roof, updating outdated wiring, or demolishing a poorly constructed wall. It’s deeper work that removes structural issues and unlocks new possibilities.

How to Embrace Imperfection (Without Burning the House Down)

  • Could you ship now, and refine later? MVP first, polish second. But be careful about how you define “MVP” — minimally viable product. Only your customers and prospects can tell you if a piece of software is usable.

  • Explain shortcuts. A good comment turns “WTF?” into “makes sense.”

  • Make reviews collaborative. It’s a conversation, not a courtroom.

  • Refactor regularly. Cleanup is part of the building process, not an afterthought.

The Final Word: Be Brave, Be Crappy

Writing crappy code isn’t a flaw — it’s a feature. It means you’re experimenting, iterating, and moving forward. It means you’re building something instead of planning everything. So the next time you cringe at old code, don’t beat yourself up — celebrate it. That’s growth. That’s momentum. That’s how software is made. Because in the end, crappy code isn’t the enemy. Stagnation is.

Your turn: What’s the “crappiest” piece of code you’ve ever written — and why are you secretly proud of it?

Next
Next

My inbox is filled with AI pitches