Skip to main content
Claude Code

Deep Modules: The Claude Code Skill Saving My Codebase

I ran the improve-codebase-architecture skill's deep-modules lens over my production Laravel app: what it flagged and the cache bug it predicted.

7 min
Read time
1,338
Words
Published
Last revised
Engr Mejba Ahmed

Written by

Engr Mejba Ahmed

Share Article

Deep Modules: The Claude Code Skill Saving My Codebase

AI-assisted development has a rot problem, and it isn't the model's code quality. It's the rate. Claude Code ships my decisions five to ten times faster than my hands did, which means every architectural shortcut compounds on a calendar my judgment was never trained for. The tool I use as a counterweight is the improve-codebase-architecture skill from Matt Pocock's skills repo, which reads a codebase through John Ousterhout's deep-modules lens. It has a permanent slot in my setup, and rather than review it abstractly, I want to show you what that lens surfaces on my actual production codebase, the Laravel platform serving the page you're reading.

Deep Modules: The Claude Code Skill Saving My Codebase - overview of the vocabulary, in five minutes, what the lens flags on my real codebase

The vocabulary, in five minutes

The skill is opinionated about language, and adopting its glossary is half the value. A module is anything with an interface and an implementation: a function, a class, a package. The interface is everything a caller must know to use it, not just the type signature but invariants, error modes, and ordering. A deep module hides a lot of behavior behind a small interface; a shallow module has an interface nearly as complex as what it hides, so callers learn a lot and gain little.

Two more terms do the practical work. A seam is where an interface lives, the place behavior can be swapped without editing code in place. An adapter is a concrete implementation satisfying an interface at a seam, and the skill's aphorism here is the best one-liner on testability I've read: one adapter is a hypothetical seam, two adapters is a real seam. If only production code ever implements your interface, you haven't proven the boundary exists. The moment a fake implementation slots in for tests, the seam is real.

The skill's sharpest diagnostic is the deletion test: imagine deleting the module. If complexity simply vanishes, the module was a pass-through that never earned its keep. If complexity reappears smeared across its callers, the module was doing real work.

What the lens flags on my real codebase

The 39-model folder. My app/Models/Website directory holds thirty-nine models spanning courses, forums, flashcards, live chat, a prompt library, agent skills, AI news, and more. My own CLAUDE.md carries a warning that the folder "has grown large." The deep-modules reading is more precise than "large": the folder is a namespace pretending to be a module. It has no interface at all, just an alphabetical pile where CourseLessonProgress sits next to ForumReply next to ChatSetting. Understanding any one product area means mentally reassembling its five to eight models from a list of thirty-nine. The deepening move isn't renaming or splitting files; it's promoting each product area to a module with a front door, so the course domain exposes enrollment and progress operations while its persistence shape stays inside. Low urgency, because the models are individually clean. High eventual cost, because every new domain makes the pile's cognitive tax worse.

The cache seam that already shipped a bug. This is the finding I can defend hardest, because the bug is documented in my own project notes. Cache invalidation on this platform lives in model observers that call Cache::forget('sitemap_xml') and friends directly, with string keys, on save and delete. Meanwhile my blog controller caches processed post HTML under post_content_{id}_{locale} keys. Two writers, no shared interface, and the observers don't know the controller's keys exist. The predictable consequence: I once edited post content directly and the site kept serving the stale render, because the observer busted the sitemap cache but not the content cache. I lost real time to that drift before recording it as a gotcha.

The deep-modules reading is that this isn't a caching bug, it's a missing module. Cache keys are an implementation detail currently leaking across the codebase as stringly-typed knowledge every caller must carry. The fix is a single invalidation module whose interface speaks in domain events, "this post changed," and whose implementation owns the mapping to every affected key. The skill's framing predicts the bug from the architecture alone: wherever the same hidden knowledge lives in two places, drift between them will eventually manifest as a defect. It did.

The deep module already there. The lens also finds what's working, which matters for calibration. My ContentProcessingService takes raw post content and hands back publishable HTML, with markdown-versus-HTML detection, GitHub-flavored rendering, HTML purification, and heading-ID injection all hidden behind essentially one call. Callers know nothing about purifier configs or parser choices. When I swap a parser or tighten sanitization rules, no caller changes. That's the leverage ratio Ousterhout means: learn ten things, get a thousand. If I ever wonder what "deep" should feel like in this codebase, the answer is already in it.

The counterintuitive keeper. My services catalog deliberately reuses the shop's Product model rather than introducing a parallel Service model. A code reviewer's instinct calls that a smell. The deletion test defends it: delete the reuse and introduce the "cleaner" duplicate, and complexity doesn't vanish, it reappears as two pricing implementations, two admin resources, and two checkout paths that must never drift. Sometimes the deep move is refusing to create the second shallow module. This is the same judgment I lean on when deciding whether a simplification pass is genuinely reducing surface area or just relocating it.

How the skill actually behaves

Mechanically, it scans for clusters of shallow, tightly coupled modules, produces a shortlist of deepening proposals, each naming the modules to merge, the proposed interface, where the test seam would live, and the migration risks, and then holds an interactive design pass where you argue with it. It files issues for accepted proposals rather than refactoring autonomously, and that restraint is correct. Humans make every architectural call; the skill supplies the pressure and the vocabulary.

Where it stumbles, honestly: it's biased toward TypeScript-shaped proposals, so on PHP I translate idiom, and it doesn't model migration cost well. A proposal can be beautiful in isolation while the cost of moving callers and rewriting tests exceeds the leverage gained. I read every proposal with one question layered on top: is the migration cheaper than the drift it prevents? For my cache seam, obviously yes. For the 39-model folder, not yet, so it's tracked rather than executed.

One rule I hold to on legacy-ish code: never deepen an untested cluster directly. Pin the current behavior with characterization tests first, then refactor against them. On this codebase, PHPStan at level 8 plus the test suite is the safety net that makes accepted proposals cheap to execute, and half the time the first commit of a deepening is a test commit. It's the same discipline that turned my N+1 query cleanup from risky surgery into routine maintenance.

The upstream effect is the real payoff

The unexpected benefit after months with this skill isn't the refactors it proposed. It's that the vocabulary migrated upstream into how I prompt. When I start a Claude Code session on a new feature now, I specify the seam before the behavior: what's the interface, what stays hidden, where does the fake adapter go for tests. The generated code arrives closer to what the skill's next scan would have proposed anyway, which means the scans keep getting quieter. Architectural pressure applied before generation beats pressure applied after, for the same reason a healthy instruction file beats a clever prompt: context shapes everything downstream.

Software entropy is a one-way arrow, and AI made the arrow faster. The fix is not slower shipping. It's pressure that scales with the shipping rate, applied by something that reads your whole repo more often than you do. Ask the skill's question of your own codebase this week: where would the test seam go? If a module has no answer, you've found your first deepening.

Architecture reviews on real production code — naming the shallow clusters, then arguing about which deepenings clear the migration-cost bar — are the engagements I take on most often and enjoy most. Describe your stack to me and we'll start where I started here: with the seam question.

Coffee cup

Enjoyed this article?

Your support helps me create more in-depth technical content, open-source tools, and free resources for the developer community.

Related Topics

Engr Mejba Ahmed

Engr Mejba Ahmed

Engr. Mejba Ahmed builds AI-powered applications and secure cloud systems for businesses worldwide. With 8+ years shipping production software in Laravel, Python, and AWS, he's helped companies automate workflows, reduce infrastructure costs, and scale without security headaches. He writes about practical AI integration, cloud architecture, and developer productivity.

Related Articles

Browse All

Comments

Leave a Comment

Comments are moderated before appearing.

Learning Resources

Expand Your Knowledge

Accelerate your growth with structured courses, verified certificates, interactive flashcards, and production-ready AI agent skills.

Sample Certificate of Completion

Sample certificate — complete any course to earn yours

Engr Mejba Ahmed

Engr Mejba Ahmed

AI assistant · trained on my work

👋

Hey there!

Quick Actions

WhatsApp Direct line to me

Chat on WhatsApp

+880 1723 741224 · Replies within the hour on working days

Popular Questions

Engr Mejba Ahmed is connected
Engr Mejba Ahmed is typing...
Engr Mejba Ahmed avatar

✉ Want me to follow up? Drop your email

Engr Mejba Ahmed avatar

📞 Connect Directly

Choose how you'd like to reach me

WhatsApp

+880 1723 741224

Email

mejba.13@gmail.com

✓ Details sent! I'll get back to you shortly.

Powered by OpenAI

335+

Blog Posts

25

AI Courses

63

Projects

Services & Expertise

Pricing & Process

Learning & Resources

Connect & Support