The Art of Destroying Software đ„
The code you wrote today is probably wrong.
software-engineering · code-quality · refactoring

Thereâs a screaming truth that the software industry has been resisting with admirable consistency for decades: the code you wrote today is probably wrong.
Not because youâre a bad programmer. But because when you started, you couldnât predict what you were going to discover along the way. The problem with software isnât writing it â itâs that you generally have to write it before you fully understand the problem youâre solving. And by the time you finally do understand it, youâve already got several layers of abstraction and interdependencies on top of it that make changing anything painful.
The industryâs usual solution to this is more abstraction. More layers. More design patterns with Latin names. An architecture so intricate and complex that debugging it feels like archaeology â digging up bones and trying to figure out what the original programmer had in mind.
But thereâs a much simpler solution: what if we just accept that the code we write today is going to be wrong, and design our software to be easy to destroy and rewrite as many times as necessary?
The Talk Nobody Wants to Give
Greg Young has a talk called âThe Art of Destroying Software.â Itâs one of the most honest and courageous talks Iâve seen. In this article Iâll summarize the most important points based on my own experience and interpretation.
âThe Art of Destroying Softwareâ
Young opens the talk by asking how many people have attended a conference talk about deleting code. The silence in the room says it all.
There are thousands of talks about how to write it. How to refactor it. How to test it. About architectures guaranteed to outlive you. But about deleting it? Nothing. As if code were a sacred investment to be protected at all costs â not a hypothesis about a problem we donât fully understand yet.
Young brings up the âBig Ball of Mudâ paper and says something uncomfortable: that big ball of mud isnât a design failure. Itâs the natural state of software under real economic pressure. If your system isnât a big ball of mud, maybe you just donât have enough users for it to matter.
And the solution the paper proposes isnât what youâd expect either â not âimprove your architecture.â Itâs âcreate small balls of mud inside the big one.â Manageable islands. Zones where you can walk in, burn everything down, and walk out in a reasonable amount of time.
Thatâs the principle: optimize for deletion.
The Metric Nobody Measures
Young proposes a rule that sounds simple and that almost nobody actually applies: no part of your system should take more than one week to rewrite from scratch.
Not as a sprint goal â as a design criterion.
If a component takes more than a week to rewrite, that component is a risk zone. Not because the code is bad, but because you no longer control it â it controls you. And when a new feature arrives that doesnât fit the current model, youâll spend two weeks fighting the model instead of two days writing a new one.
Young tells the story of working on Event Store DB, realizing his model didnât support what he needed to add, and rewriting the entire backend in two days. Two days. His estimate: if heâd tried to adapt the existing code, it would have been two weeks of suffering to reach the same place.
The right question isnât âhow much did this cost to write?â Itâs âhow much would it cost to delete it and start over tomorrow?â If that answer scares you, youâve already lost control of your system.
Micro Is Not a Size, Itâs a Guarantee
When the industry adopted microservices, it took the word âmicroâ and, with its characteristic creativity, interpreted it as a team responsibility constraint. Each team has its service, each service has its repo, each repo has its pipeline. The carving criterion wasnât the domain but the org chart: if thereâs a âpaymentsâ team, thereâs a payments service. If thereâs a âusersâ team, thereâs a users service. Conwayâs Law dressed up as architecture. They debated at conferences, wrote books, drew diagrams with arrows connecting boxes named after teams. Mission accomplished.
Thatâs missing the point entirely.
âMicroâ doesnât describe size or complexity. It describes the guarantee: this service has one single reason to exist (single responsibility), and therefore one single reason to change. If the business changes tomorrow, only one specific part of the system needs to move. The rest stays intact. And if the part that moves turns out to be unrecognizable under the new requirements, you delete it and rewrite it. In a week.
A service with two responsibilities canât be half-deleted. When you try to rewrite âthe authentication partâ you discover itâs tangled with âthe user profile partâ which shares data with âthe notifications part.â What looked like minor surgery ends up being an organ transplant with the patient wide awake.
Single responsibility isnât an aesthetic principle of clean code. Itâs the necessary condition for deletion to be possible.
The Refucktor
One of the best parts of the talk is when Young dismantles refactoring as practiced by 90% of the industry.
His definition: a refactor is when you change either your code or your tests. One of the two. The one you donât touch is your measurement â the evidence that you didnât break anything.
What most people do: change code and tests at the same time. Young has a name for that: refucktor. Itâs not a refactor â itâs a rewrite with the fear of admitting youâre rewriting.
And the best part: modern refactoring tools actively push you toward the refucktor. They offer automatic changes that touch code and tests in the same move. Convenient. And completely useless as a validation mechanism.
If you can delete the component and rewrite it in a week, the three-month ârefactorâ you were planning becomes a different problem entirely. You donât need to refactor anymore. You rewrite â with the knowledge you didnât have when you wrote it the first time.
Technical Debt and the Collective Hypocrisy
Young also has an unpopular stance on technical debt: itâs not inherently bad.
Say you have a mortgage. Is that bad debt? It let you buy a house you couldnât pay for upfront. Technical debt works the same way: it gives you time-to-market in exchange for future work. The problem isnât having it. The problem is not knowing how much you have, and not being able to pay it down because everything is so tangled that nobody wants to touch anything.
If a component can be rewritten in a week, the technical debt inside it stops being terrifying. Did you code fast and leave it messy? Fine. When it accumulates enough grime, delete it and start over with everything youâve learned. No âtechnical debt reductionâ sprint. No meeting with the CTO to explain why six months without new features is somehow a good idea.
You just delete. And rewrite better.
Knowledge Arrives at the End
Thereâs a question Young asks that should be tattooed on the forehead of everyone who has ever sat through a three-day architecture planning meeting at the start of a project:
When do you know the most about your system â at the beginning, when youâre planning it, or at the end, after youâve built it?
At the end. Always at the end. After youâve faced the real problems, after youâve seen how the system behaves under load, after youâve seen which parts are truly critical and which ones arenât, after youâve absorbed those dozens of requirement changes you couldnât have predicted. Thatâs when you actually know what youâre doing.
You design the architecture when you know the least. You make the most important decisions when you have the least information. And then you spend years paying the cost of those decisions â not because they were stupid, but because they were inevitably premature.
The only reasonable response is to design knowing youâll be wrong. Not to avoid the mistake â but to make the mistake cheap. So that when the moment comes that you truly understand the problem, you can throw away what you built before and do it right, without that being a six-month project.
Events Force You to Think
Event-driven architecture has a reputation as the solution to coupling between services. Thatâs true, but itâs the secondary benefit. The first one is less obvious and more important: events force you to have clear responsibilities.
When you design a direct call between services, you can be vague. âThe orders service tells the inventory service to update the stock.â Nobody asks questions. The coupling hides inside the convenience.
When you design an event, you canât be vague. You have to decide what happened from the perspective of the domain emitting it. And that decision forces you to understand exactly what that domain is responsible for, and where its responsibility ends.
order.confirmed doesnât tell anyone what to do. It describes something that happened. The inventory service decides whether it cares. The notifications service decides whether it cares. The billing service decides whether it cares. The orders domain doesnât know they exist, and it doesnât need to.
The practical result: each service has exactly one reason to change. If inventory logic changes, only inventory changes. If notification logic changes, only notifications change. The orders domain never knows about any of that because it never knew those things existed.
Thatâs single responsibility for real. Not as a principle in a book, but as an inevitable consequence of the design. And a service with one reason to change is a service you can rewrite in a week without fear of what breaks on the other side â because on the other side there are only consumers of a fact that happened, not dependents of how you implemented it.
The Problem Isnât Clean Architecture. Itâs You. Well, No â It Actually Is Clean Architecture.
Letâs talk about the promise Iâve seen broken in production more times than any other.
Clean Architecture tells you: separate your business logic from infrastructure details. Put interfaces in between. That way, when you need to change the database someday, you only touch one layer. The rest stays intact. It sounds perfect. It sounds exactly like optimizing for change.
What actually happens: you implement a microservice with use cases, repositories, providers, datasources â each one hidden behind its corresponding interface. Four layers of abstraction to read a single row from a database. The day you decide to migrate from DynamoDB to MongoDB â for cost reasons, for features, for whatever â the promise was clear: touch only the datasource, implement the new interface, done.
And then you donât. You end up touching everywhere. The models didnât map the same way. The queries assumed DynamoDB semantics. The use cases had infrastructure details leaking upward without anyone noticing. The abstraction that was supposed to isolate changes had distributed them invisibly across the entire codebase.
The easy conclusion is âthey implemented it wrong.â Probably true. But thatâs exactly the trap: an architecture so complex that implementing it correctly requires a level of discipline and understanding that most teams donât have isnât a good architecture. Itâs an architecture that always charges you the downsides and only delivers the benefits under ideal conditions that donât exist.
An interface is a promise that more than one real implementation will exist. If today you only have one implementation, you donât have an interface â you have bureaucracy with syntax. And that bureaucracy is what makes changing something simple require touching ten files across four different layers.
The question to ask before introducing any abstraction is brutal in its simplicity: do I already have two real implementations of this, or am I just anticipating a flexibility I might never need? If the answer is no, donât abstract anything â when the time comes to change, delete and rewrite. Thatâs the whole point of optimizing for deletion.
Simple code you can rewrite in three days beats elegant code nobody fully understands and takes three weeks to modify. Every time.
Unix Knew. We Forgot.
Young closes with something I think is the most important point in the entire talk: this isnât new.
Microservices, SOA, actors, objects â all the same concept recycled with different names every ten years. The Unix philosophy of the 70s already said it: small programs, doing one thing, composed together. Are you afraid to delete and rewrite grep from scratch? No. Because grep is small, does one thing, and you can understand it in an afternoon.
The problem isnât that the industry doesnât know this. The problem is that it knows, adopts the form â microservices, SOA, actors â and completely loses the point. The goal was never to have small services. The goal was to be able to delete them without fear. So that if a service canât absorb a new requirement, you donât spend weeks fighting what you have, but can rebuild it in a few days with a design that actually supports everything you now understand.
Microservices without deleteability isnât an architecture. Itâs a monolith with more servers.
Fear as a Metric
Young throws out a question almost in passing, without drama, thatâs probably the most important one in the entire talk:
âCan you imagine working as a developer and not being afraid?â
Fear of your own code is so common it stopped looking like a problem. Itâs just part of the job. âBe careful with that part.â âDonât touch that, itâll break everything.â âBetter not change anything near there.â Phrases so normalized theyâve become invisible.
But theyâre the most honest symptom of a system you can no longer destroy. Not the legacy code, not the technical debt, not the tests that fail in CI but âwork fine in prod.â The fear. Thatâs the real indicator.
A system optimized for deletion doesnât give you technical superpowers. It doesnât make you smarter or more productive in any abstract sense. It simply takes away something you shouldnât have had in the first place: the anxiety of touching your own work.
When you can delete any part and rewrite it in a week, the fear disappears. Not because the code is perfect, but because its imperfection stopped being permanent.
Optimize for deletion. Not because youâre going to delete everything tomorrow. But because the system you can destroy without fear is the only system you can change without fear. And a system you can change without fear is the only one that ages well.
Everything else is archaeology with Kubernetes on top.