back to pipeline
view source

DHH Was Right: How AI Vindicated the 'Just Write the Code' Philosophy

$cat library-purge.md

Your go.mod file imports 47 different packages. Your vendor directory weighs 156MB. Your security scanner sends you vulnerability alerts for indirect dependencies you've never heard of. Your Docker builds spend more time downloading modules than compiling your actual application.

This is what we call "modern Go development."

Meanwhile, David Heinemeier Hansson has been quietly vindicated. For years, he's been saying "just write the damn code yourself" while the rest of the industry built increasingly complex dependency trees. Everyone called him old-fashioned. Accused him of not understanding "modern development practices."

Turns out DHH was playing the long game.

Because now we have AI that can write exactly the code you need, when you need it. No external packages. No dependencies. No external maintainers to worry about. Just vanilla Go that does exactly what you want and nothing more.

The age of dependency madness is ending. AI is about to make your go.mod file obsolete.

The Madness We Normalized

Here's what we somehow convinced ourselves was normal:

A typical Go microservice in 2025 has:

  • 47 direct dependencies in go.mod
  • 234 indirect dependencies
  • 156MB in the vendor directory
  • 12 different HTTP client libraries (because apparently net/http isn't good enough)
  • 8 different logging libraries
  • 6 different configuration libraries
  • Dependencies on packages that duplicate standard library functionality

This isn't software engineering. It's digital hoarding.

We've created a world where Go developers are afraid to use the standard library. Need to make an HTTP request? Instead of using net/http, you're told to import resty or req because they have "better APIs." Want structured logging? Pull in logrus or zap instead of the standard log/slog package.

We've outsourced thinking to package maintainers who may or may not understand our use cases, may or may not keep their packages updated, and may or may not accidentally break our builds with a single commit.

Remember when a popular Go dependency changed its import path and broke thousands of projects? Or when security vulnerabilities in transitive dependencies forced emergency updates across entire organizations?

The Library Complexity Industrial Complex

This dependency madness didn't happen by accident. It was enabled and encouraged by an entire industry built around convincing Go developers that the standard library isn't good enough.

Framework evangelists tell you that you NEED Gin or Echo to build a web service. Never mind that net/http is perfectly capable and comes with excellent performance out of the box.

Library maintainers create packages that wrap standard library functions with "better" APIs but somehow require 15 other packages to do it. Because why use net/http when you can import a client library that imports a retry library that imports a circuit breaker library?

Tool creators convince you that you need complex dependency injection frameworks like Wire or Fx for projects that could work fine with simple constructor functions.

Training companies sell courses on framework-specific solutions instead of teaching fundamental Go idioms and standard library usage.

The beautiful part? Most of these "solutions" are more complex than the problems they're supposed to solve.

You want to make an HTTP request with retries? Instead of using net/http with a simple retry loop, you're told to install hashicorp/go-retryablehttp (which pulls in 8 dependencies) because it has "enterprise-grade retry logic." Never mind that you could write the exact retry logic you need in less code than it takes to import the library.

The DHH Vindication

David Heinemeier Hansson has been saying this for years: "Just write the damn code."

While the Go world was building increasingly complex dependency trees, DHH was advocating for:

  • Standard library over external packages
  • Simple solutions over clever abstractions
  • Understanding your code over importing someone else's
  • Boring technology that just works

He got mocked for this. Called "old-fashioned." Accused of not understanding "modern development practices."

But it turns out DHH was right. Dead right.

Go was actually designed with these principles in mind. The language creators explicitly built a rich standard library to reduce the need for external dependencies. They valued simplicity, readability, and maintainability over clever abstractions.

But the ecosystem gradually convinced developers that the standard library wasn't enough. That you needed frameworks and libraries to be "productive."

The problem wasn't that writing your own code was hard. The problem was that writing good Go code required knowledge and effort that many developers weren't willing to invest.

But AI changes everything.

The AI Revolution

Here's what changes everything:

You: "Write me an HTTP client with retries and timeout handling"

Traditional approach: Import hashicorp/go-retryablehttp (pulls in 8 dependencies, 2.3MB)

AI approach: Claude generates 30 lines of standard library code that does exactly what you need.

The difference isn't just about dependency count:

  • You understand the code - no black box abstractions
  • Zero security surface - no third-party packages to audit
  • Complete control - modify retry logic for your exact use case
  • Single binary deployment - no dependency hell in production
  • Instant debugging - when it breaks, you know exactly why

AI doesn't just reduce dependencies. It eliminates the need for them entirely.

The Resistance Arguments (And Why They're Wrong)

"You can't replace well-tested libraries with AI-generated code!"

Wrong. You're not replacing well-tested libraries with untested code. You're replacing bloated, general-purpose libraries with focused, specific code that does exactly what you need.

Most bugs in applications come from complexity and abstractions, not from simple, straightforward code.

"What about security vulnerabilities?"

AI-generated code that you control is MORE secure than depending on packages that might have vulnerabilities you don't know about. When you own the code, you can audit it, understand it, and fix it.

"This will lead to code duplication!"

Good! Code duplication is often better than dependency coupling. If you need the same functionality in multiple places, either extract it to your own utility functions or generate it again. Both approaches give you more control than depending on external packages.

"AI code isn't optimized!"

For 90% of applications, "optimization" doesn't matter. And when it does matter, you can ask AI to optimize for your specific use case rather than accepting the general-purpose optimizations of a library.

What This Looks Like in Practice

Current Go Microservice:

  • 47 direct dependencies in go.mod
  • 234 indirect dependencies
  • 156MB vendor directory
  • Complex framework abstractions
  • Dependency vulnerability alerts every week

AI-Generated Standard Library Service:

  • Zero external dependencies
  • Standard library HTTP server
  • Custom middleware for your specific needs
  • Simple, readable Go code
  • Compiles to a single binary

Current API Client:

import (
    "github.com/go-resty/resty/v2"
    "github.com/hashicorp/go-retryablehttp"
    "github.com/sony/gobreaker"
)

client := resty.New().
    SetRetryCount(3).
    SetTimeout(30 * time.Second)

AI-Generated API Client:

// Claude generates exactly the retry logic, timeout handling,
// and circuit breaking you need for your specific API
// using only net/http and time packages

The Economics of the Shift

This isn't just technical - it's economic disruption:

Who loses:

  • Library maintainers whose packages become obsolete
  • Framework consultants charging $300/hour for complexity management
  • Training companies selling framework-specific courses
  • Security vendors selling dependency scanning tools

Who wins:

  • Developers who ship faster with simpler code
  • Companies with smaller attack surfaces and faster builds
  • Teams that understand their entire codebase
  • Organizations that can actually debug their production systems

The smart money is already moving. Developers learning AI-assisted standard library development will outpace those optimizing framework configurations.

The Broader Implications

This shift represents more than just changing how we manage dependencies. It's about returning to first principles:

Understanding over abstraction: When you generate code specifically for your needs, you understand what it does.

Simplicity over cleverness: AI can generate simple, readable solutions instead of clever, abstract ones.

Ownership over dependency: You own and control the code in your application.

Flexibility over framework lock-in: Vanilla solutions work everywhere and adapt to your needs.

This is the web development equivalent of the return to simplicity that DHH has been advocating for years. Except now we have AI to make that simplicity practical and productive.

What You Should Do

Starting fresh?

  • Build with standard library first, AI when you need specific functionality
  • Question every external dependency: "Could AI generate this instead?"
  • Measure success by code you understand, not packages you import

Maintaining legacy systems?

  • Audit your go.mod - start replacing the simplest libraries first
  • Use AI to rewrite small utility packages as standard library code
  • Track your progress: dependencies removed, security alerts eliminated, build time improvements

Library maintainer?

  • Your value isn't code generation anymore - it's domain expertise
  • Consider pivoting to AI workflow optimization
  • Focus on problems AI can't solve: complex algorithms, domain-specific knowledge, integration patterns

The transition is happening. The question is whether you'll lead it or get left behind.

The Future Is Standard Library

The future of Go development isn't Gin v2 or the next web framework. It's the Go standard library enhanced by AI that can generate exactly what you need, when you need it.

No more dependency hell. No more framework churn. No more praying that your 47 dependencies don't conflict with each other.

Just simple, understandable Go code that does exactly what you need and nothing more.

DHH was right all along. We just needed AI to make "just write the damn code" practical for everyone.

The great library purge is coming. Your go.mod file's days are numbered.

And your applications will be better for it.


P.S. - Yes, there will still be use cases for complex libraries and frameworks. But they should be the exception, not the default.