The big file was dead

The dread of an unfamiliar codebase is real and it points you at the wrong file almost every time.

#git #culture

I spent my first full day on an inherited store reading one file.

It was the biggest thing in the project, a custom price class a little under 2000 lines long. The developer handing it over had brought it up twice, both times with a small laugh. Of course that’s where I went.

I read it the way you read anything you’re scared of, which is quickly, then slowly, then a third time. I came out of the third pass no further along than the first.

The next morning I ran the log on it, mostly to find out who to blame. The last change was in 2018, one line, inside a merge. Before that, a real edit in 2017.

It still ran on every page with a price on it, which on a store is pretty much all of them (I checked). But nothing anybody had wanted from that site in two years had needed a single line of it to move. I’d spent a whole day getting fluent in a room nobody goes into.

Back in 2016, on a practice’s WordPress site, the terrifying file really was the business. It was a 200-line jQuery function that every page ran. The ugliest stretch of it was the rule deciding whose inbox a consultation request landed in, right under a comment telling me not to touch it. I’d have cheerfully simplified it in week one.

So the instinct I brought with me was that big and ugly means important. That’s about half right. The half it gets wrong costs you a week.

Follow the money

I should have started by asking the log where the work goes. These days I do that before I open a single file.

first hour
# which files this project actually works on
git log --since="2 years ago" --name-only --format=format: \
  | sed '/^$/d' | sort | uniq -c | sort -rn | head
Shell

That’s every file named in every commit for the last two years, counted and sorted biggest first. The sed is there because --format=format: leaves a blank line per commit. Without it those blanks sort straight to the top and sit there looking like the most edited file in the project.

the top of the list
     71 app/design/frontend/Acme/store/web/css/source/_extend.less
     58 app/design/frontend/Acme/store/Magento_Checkout/templates/cart/form.phtml
     44 app/code/Acme/Shipping/Model/Carrier/Freight.php
     37 app/design/frontend/Acme/store/Magento_Catalog/layout/catalog_product_view.xml
     29 app/code/Acme/Checkout/Plugin/LayoutProcessorPlugin.php
     26 app/design/frontend/Acme/store/Magento_Checkout/web/js/view/shipping.js
Text

Every project I’ve ever run this on has a stylesheet at the top, and so that part isn’t really information. The rest of it is. This store is basically a cart and a shipping calculator with a catalog attached. I got that out of one shell pipeline instead of three meetings.

The file I’d read isn’t in that list. It isn’t further down either. Nothing touched it inside the window, so it doesn’t show up at all. I guess that’s an answer too, just one delivered as an absence.

A directory tree tells you how somebody once meant to organize the project. The log tells you where everyone has actually been. Those are two different documents, and only one of them gets updated by accident every time anybody does anything.

It’s also worth reading a hot file’s history and not only its contents. A few of those cart commits are reverts of each other, the same free shipping rule going in and coming back out over about a year. That argument is nowhere in the code because code only ever shows you who won.

The ugly parts of a codebase are usually ugly because somebody lost an argument in them. The log is the only place that argument survives.

Who asked for this?

The log couldn’t tell me why the price class still ran, since nothing I searched for called it by name. On Magento 2 that’s normal. A class doesn’t go and get what it needs. It lists what it needs in its constructor and the framework hands it over.

di.xml decides what gets handed over. I took that file on faith for my first couple of years on the platform.

app/code/Acme/Pricing/etc/di.xml
<preference for="Magento\Catalog\Model\Product\Type\Price"
            type="Acme\Pricing\Model\Price"/>
XML

That one line hands out the big file everywhere Magento would have used its own price model.

In the end, the project I’ve been building in my spare time made it readable. It’s on Laravel, where the same idea is smaller and better documented. Laravel’s service container lets you bind a class to whatever should be handed out when something asks for it.

Once I’d written a few bindings myself, a preference read as one of those. A plugin, which wraps a method on somebody else’s class without touching their file, read a lot like middleware for a single method. Neither comparison is exact. It was still the first time that file read like a list of decisions instead of a list of incantations.

It always feels like this

Without a procedure, my first day looks like the one I just described. It looked like that for most of my first few years, too.

I open the project. There’s a small, unpleasant jolt of not understanding it. So I open a file because opening a file feels like doing something.

It doesn’t help, since a file on its own means nothing. So I open another one. By lunch I’ve got 14 tabs open and I’ve read pieces of all of them. The not-understanding has compounded into something with a pulse.

That isn’t a research method. It’s a nervous habit with a text editor attached.

I’ve had the habit since before I did this for a living. At a home improvement store I worked at, the training was a set of computer modules. I finished them, didn’t know who I was supposed to tell, and went through them again. And then again, for most of a week.

I was the most thoroughly trained person on the floor on my first day. The first customer who asked me where something was got pointed at a coworker because I had no idea which aisle it was in. The modules were never going to tell me that. The big file was never going to tell me where the work was, either.

It took me an embarrassing number of years to accept that feeling lost in an unfamiliar codebase is a constant and not a signal. It’s there in hour one whether the code is beautiful or appalling, whether the project is documented or a swamp, whether you’re any good at this or you aren’t. It’s what an unfamiliar codebase feels like from the inside. It tells you nothing about the codebase and nothing about you.

For years I read it as a verdict, which made me want it over with. So I rushed, which is the very thing that makes it take longer.

A procedure fixes that, and not because the steps are optimal. It works because on step three of six you know you’re on step three of six. “I don’t understand this yet” turns into a schedule instead of an accusation.

Stupid question, but

Keep a file open while you read, and write down what confused you. I don’t mean notes on what the code does. I mean notes on what confused you.

Every “why is this here,” every “where does this come from,” every “I assumed X and it turned out to be Y.” They’re probably the most valuable thing you’ll produce that month and they last about three weeks.

notes.md
- Two shipping carriers under Acme/Shipping. Only one is switched on in
  config.xml. Is the other dead, or is something calling it directly?
- A `wholesale` customer attribute, set on a couple hundred customers.
  Nothing I can find reads it.
- Free shipping threshold appears in three places and they disagree.
  Which one does the site use?
- Why does the cart template get edited every other week?
Markdown

By week three you’ll have absorbed all of them, which feels like getting good at the project. It’s actually the loss of the only outsider’s view this codebase will get until the next person arrives. They’ll be exactly as quiet about it for exactly the same reason.

At the end of the first month about half of mine have answers. The answers go in the README, which is the onboarding document the project never had.

The only person qualified to write that document is the newest one on the project. Knowing the project is exactly what disqualifies you from the job. So it has to happen while you’re still ignorant enough to have the questions.

Almost any order will do

The order I wrote up a few years ago is still the one I use: the site before the code, the history before the files, the manifest, the entry points, the templates, then the logic. And always with a question in hand instead of a hope of understanding.

I’d change the emphasis. I wrote it up as though the order were the insight. Having done this a dozen or so more times since, I don’t think it is. Almost any consistent order would probably do the same work.

Having one at all is the point. The alternative isn’t a different order. It’s the instinct, which walks you straight into the biggest file in the project and keeps you there until it gets dark.

Diving in isn’t faster. It only feels like progress, at the exact hour when you want progress most and it’s worth the least. The big file will still be there in week three if it ever turns out you need it, though I never did open that one again.

Read similar posts

View posts by tag

#accessibility #agency #ai #careers #cross-browser-compatibility #css #culture #debugging #documentation #ecommerce #forms #git #html #images #javascript #performance #php #privacy #scss #security #shopify #small-print #tooling #typography #wordpress