The story of Max, a real programmer

by surprisetalkon 6/30/25, 12:57 PMwith 93 comments
by onlion 7/3/25, 12:43 PM

There is this part in there:

> Are our tools just worse now? Was early 2000s PHP actually good?

Not sure how rhetorical that was, but of course? PHP is a super efficient language that is tailor made to write dynamic web sites, unlike Go. The author mentions a couple of the features that made the original version easier to write and easier to maintain, they are made for the usecase, like $_GET.

And if something like a template engine is needed, like it will be if the project is a little bit bigger, then PHP supports that just fine.

> Max didn't need a request router, he just put his PHP file at the right place on the disk.

The tendency to abstract code away leads to complexity, while a real useful abstraction is about minimizing complexity. Here, the placement of PHP files makes stuff easier -> it's a good abstraction.

And that's why the original code is so much better.

by throwaway2037on 7/3/25, 1:13 PM

This part really hits home. The first time I got to see a huge enterprise C project, I could not believe how simple the code was. Few to no tricks.

    > To be perfectly honest, as a teenager I never thought Max was all that great at programming. I thought his style was overly-simplistic. I thought he just didn't know any better. But 15 years on, I now see that the simplicity that I dismissed as naive was actually what made his code great.

by andrewvcon 7/3/25, 12:25 PM

It’s a fun trip down memory lane, but the real story today, the sadder story, is that there is no longer any use for simple little programs like this that scratch an itch.

They’ve all been solved 100x over by founders who’ve been funded on this site. It used to make sense to have a directory or cgi-bin of helpful scripts. Now it only makes sense as a bit of nostalgia.

I miss the days when we had less, could get less done in a day… but felt more ownership over it. Those days are gone.

by chbkallon 7/3/25, 1:02 PM

Reading this reminds me of the era which was envisioned will happen when I was in college (which was not long ago) - individuals and societies building their own independent custom stuff (both hardware and software) with the power of computers in everyone's hands. I am sure that is still happening in small pockets but most of the 'stuff' we use are built by large mindless corporates on which we have almost no control - and who prioritize profits over well-being of the employees and the community.

I don't know for sure what the problem was (I have my theories) and why could we not get there where most people build their own custom products.

by 13hunteoon 7/3/25, 12:43 PM

Mostly unrelated, but I dislike how normalized AI art is.

by nottorpon 7/3/25, 1:31 PM

But imgbin is a tiny project with exactly one moving part that only interacts with the file system and the user.

When the project becomes more complex, things change for the worse.

Also, you need to protect modules not only from errors, but from the other programmers in your team.

by et1337on 7/3/25, 1:36 PM

To make it a fair comparison, you also need to consider all the old-school Apache and PHP config files required to get that beautiful little script working. :) I still have battle scars.

by brazzyon 7/3/25, 1:11 PM

Early 2000s PHP was a DSL for very simple web apps. So it's no surprise it excels at that.

People soon found out that it was not very good at complex web apps, though.

These days, there's almost no demand for very simple web apps, partially because common use cases are covered by SaaS providers, and those with a need and the money for custom web apps have seen all the fancy stuff that's possible and want it.

So it's no surprise that today's languages and frameworks are more concerned with making complex web apps manageable, and don't optimize much (or at all) for the "very simple" case.

by jonstewarton 7/3/25, 12:09 PM

Max wrote a simple php script. Mel wrote delay loops by accessing previous memory addresses on drums. They are not the same.

by maxehmookauon 7/3/25, 1:01 PM

I appreciated this, just because my name is Max and any sort of validation from HN is hard to come by.

Also, the image kinda looks like me. It's not me though. I don't think.

by fithisuxon 6/30/25, 2:06 PM

I think Max's brain was not polluted with terror and showed trust in his tools.

Today many devs (and not prograamers)

are always suspicious, and terrified on the potential of something going wrong because someone will point a finger

even if the error is harmless or improbable.

My experience is that many modern devs are incapable of assigning significance or probabilities, they are usually not creative, fearful of "not using best practices", and do not take into consideration the anthropic aspect of software.

My 2 cents

by s1mplicissimuson 7/3/25, 12:06 PM

> For years Imagebin was wide open to the public and anybody could upload their own images to it. Almost nobody did.

There's your explanation why it could be so simple

by msteffenon 7/3/25, 12:55 PM

> The reason the Go code is so much bigger is because it checks and (kind of) handles errors everywhere (?) they could occur

I’ve said before and will say again: error handling is most of what’s hard about programming (certainly most of what’s hard about distributed systems).

I keep looking for a programming language that makes error handling a central part of the design (rather than focusing on non-error control flow of various kinds), but honestly I don’t even know what would be better than the current options (Java/Python’s exceptions, or Go’s multiple returns, or Rust’s similar-seeming Result<T, E>). I know Linus likes using goto for errors (though I think it just kind of looks like try/catch in C) but I don’t know of much else.

It would need to be the case that code that doesn’t want to handle errors (like Max’s simple website) doesn’t have any error handling code, but it’s easy to add, and common patterns (e.g. “retry this inner operation N times, maybe with back off and jitter, and then fail this outer operation, either exiting the program or leaving unaffected parts running”) are easy to express

by naruhodoon 7/4/25, 3:19 AM

    files := r.MultipartForm.File["upload"]
    for _, file := range files {
        src, err := file.Open()
        filename := fmt.Sprintf("%d%s", imgNum, filepath.Ext(file.Filename))
        dst, err := os.Create(ORIGINAL_DIR + "/" + filename)
        _, err = io.Copy(dst, src)
Hmmm... can an attacker upload a file named "../../../etc/profile.d/script.sh" or similar ideas, i.e. path traversal?

by marcoflorianoon 7/3/25, 2:26 PM

"It's so simple that nothing goes wrong."

This. The hardest part of solving a problem is to think about the problem and then come up with the right solution. We actually do the opposite: we write code and then think about it.

by ajd555on 7/3/25, 1:22 PM

What a great read! And so many good insights! It almost made me want to convert a project to PHP - perhaps I will for a smaller project.

I love the simplicity and some of the great tools that PHP offers out of the box. I do believe that it only works in some cases. I use go because I need the error handling, the goroutines and the continuously running server to listen for kafka events. But I always always try to keep it simple, sometimes preferring a longer function than writing a useless abstraction that will only add more constraints. This is a great reminder to double my efforts when it comes to KISS!

by cratermoonon 7/3/25, 1:36 PM

A couple of hundred lines of code is going always to be easy to maintain unless it's purposely written in an obfuscated and confusing style. A project with only two maintainers in its lifetime isn't going to be subject to the kind of style meanderings that muck up a codebase that's gone through dozens of maintainers over its lifetime. A couple of thousand lines needs some organization, one function of two thousand lines is impenetrable.

by tudorizeron 7/3/25, 1:37 PM

The gist of the article is a fun thought experiment.

Why count lines of code? Error handling is nothing to sniff at, especially in prod. Imagebin had a small handful of known users. Open it up to the world and most the error handling in Go comes handy.

For PHP, quite a bit was left on the shoulders of the HTTP server (eg. routes). The final result of Go is a binary which includes the server. The comparison is not fully fair, unless I'm missing something.

by huhtenbergon 7/3/25, 12:57 PM

The title is wrong. It should've been

  PHP, a Real Programming Tool.
That's it. That's the story.

by Kostarrron 7/3/25, 12:48 PM

Ok now I want to know. Does Max php code have security issues? Because especially in early straightforward PHP, those were all over the place. I vaguely remember PHP3 just injected query variables into your variables? But as $_GET is mentioned, this is probably at least not the case...

by mgkimsalon 7/3/25, 1:00 PM

> ... I'm going to let my server keep running PHP.

Please get it running at least PHP 8.3. Running PHP 5 or 7 on servers available to the public is negligent in 2025.

by marcoflorianoon 7/3/25, 2:35 PM

"And I think that's how it should be. I didn't feel comfortable hacking up the code of a Real Programmer."

Ok, i actually cried at this part.

by the_afon 7/3/25, 2:01 PM

I suppose everybody knows this is a riff on "The Story of Mel, a Real Programmer" (1983), but I'm posting the link to the classic story here just in case: https://users.cs.utah.edu/~elb/folklore/mel.html

(Actually, the reworked story in free verse style, which is its most popular form)

TFA is cute but it kinda misses the point, because the original Mel didn't write code that was simple or easy to understand. It was simple to him, and arguably there was some elegance to it once you understood it, but unlike the PHP from the updated story, Mel's code was machine code, really hard to understand or modify, and the design was all in his mind.

Mel would also scoff at PHP.

by wavemodeon 7/3/25, 3:02 PM

This is the simple elegance of code whose requirements never change.

Lots of software projects don't have this luxury, sadly.

by leeoniyaon 7/3/25, 1:31 PM

> You might think that Max's practices make for a maintenance nightmare. But I've been "maintaining" it for the last 15 years and I haven't found it to be a nightmare.

c'mon, you're talking about 200 LoC here. anything except BrainFuck would be maintainable at this scale.

have you ever had to fix a non-trivial third party WordPress plugin? the whole API used to be a dumpster fire of global state and magic functions. i dont know what it is now, but 15 years ago it was a total nightmare.

by knowitnoneon 7/3/25, 3:59 PM

Comparing Go to PHP is like comparing C to Assembly

by jerfon 7/3/25, 1:25 PM

A few perhaps less obvious lessons:

I think of "straight-line code" as a distinct sort of code. It's the sort of code that does a thing, then does the next thing, then does the next thing, and if anything fails it basically just stops and yields some kind of error because there's nothing else to do. Programmers feel like they ought to do something about it, like this is bad, but I think there's actually great value in matching the code to the task. Straight-line code is not necessarily improved by some sort of heavyweight "command" pattern implementation that abstracts it into steps, or bouncing around a dozen functions, or through many objects in some other pattern. There's a time and a place for that too; for instance, if these must be configured that may be superior. But a lot of times, if you have a straight-line task, straight-line code is truly the best solution. You have to make sure it doesn't become hairy, there are some traps, but there's also a lot of traps in a lot of the supposed "fixes", many of them that will actually bite you worse.

For many years now I've been banging on the drum that if you've been living solely in the dynamic scripting language world for over a decade, you might want to look back at static languages to put one in your tool belt. When the dynamic scripting languages first came out, they would routinely be estimated at using 1/10th the lines of static languages, and at the time I would have called that a pretty good estimate. However, since then, the gap has closed. In 1998, replacing a 233-line PHP script with a merely 305-line static-code replacement would have been unthinkable. And that's Go, with all its inline error-handling; an exception-based, modern static language might have been able to effectively match the PHP! Post this in the late 90s and people are going to be telling you how amazing it was the static code didn't take over 2000 lines. This doesn't represent our tools falling behind... this represents a staggering advance! And also the Go code is going to likely be faster. Probably not in a relevant way to this user, but at scale it would be highly relevant.

A final observation is that in the early PHP era, everything worked that way. Everything functioned by being a file that represented a program on the disk corresponding to that specific path. If you want to get fancy you had a path like "/cgi-bin/my.cgi/fake/path/here" and had your "my.cgi" receive the remainder of the path as a parameter, and that was a big deal. It took the web world more-or-less a decade to get over the idea that a URL ought to literally and physically correspond to something on the disk. We didn't get rid of that because we all hate fun and convenience. We got rid of that because it produces a lot of big problems at even a medium scale and it's not a good way to structure things in general. It's not something to mourn for, it's something we've had better ways of doing now for so long that people can forget why they're the better way.

by voidUpdateon 7/3/25, 12:36 PM

I mean, if you're going purely off LOC, in the go one each closing brace gets its own line, which probably inflates it quite a bit

by jumploopson 7/3/25, 1:21 PM

> I now see that the simplicity that I dismissed as naive was actually what made his code great.

Simple is robust.