The Story of Max, a Real Programmer
Sun 29 June 2025Tagged: software
This is a story about Imagebin. Imagebin is the longest-lived software project that I still maintain. I'm the only user. I use it to host images, mainly to include in my blog, sometimes for sharing in other places. Imagebin's oldest changelog entry is dated May 2010, but I know it had already existed for about a year before I had the idea of keeping a changelog.
Here's an image hosted by Imagebin:
For years Imagebin was wide open to the public and anybody could upload their own images to it. Almost nobody did. But a couple of years ago I finally put a password on it during a paranoid spell.
But actually this is not a story about Imagebin. This is a story about the boy genius who wrote it, and the ways of his craft.
Lest a whole new generation of programmers
grow up in ignorance of this glorious past,
I feel duty-bound to describe,
as best I can through the generation gap,
how a Real Programmer wrote code.
I'll call him Max,
because that was his name.
$shortfilename = sprintf("%s%s", $curnum, image_type_to_extension($imgsize[2]));
$newfilename = "images/original/$shortfilename";
$thumbfilename = "images/thumbs/$shortfilename";
move_uploaded_file($_FILES['upload']['tmp_name'], $newfilename);
ob_start();
passthru("exiftool -overwrite_original -all= -tagsFromFile @ -orientation $newfilename");
passthru("convert $newfilename -geometry 600x600 $thumbfilename");
ob_end_clean();
Max was a school friend of mine. He didn't like to use his surname on the internet, because that was the style at the time, so I won't share his surname. Max disappeared from our lives shortly after he went to university. We think he probably got recruited by MI6 or something.
This weekend I set about rewriting Max's Imagebin in Go so that my server wouldn't have to run PHP any more. And so that I could rid myself of all the distasteful shit you find in PHP written by children 15+ years ago.
I don't remember exactly what provoked him to write Imagebin, and I'm not even certain that "Imagebin" is what he called it. That might just be what I called it.
files := r.MultipartForm.File["upload"]
for _, file := range files {
src, err := file.Open()
if err != nil {
return err
}
defer src.Close()
imgNum++
filename := fmt.Sprintf("%d%s", imgNum, filepath.Ext(file.Filename))
dst, err := os.Create(ORIGINAL_DIR + "/" + filename)
if err != nil {
return err
}
defer dst.Close()
_, err = io.Copy(dst, src)
if err != nil {
return err
}
// Remove EXIF data using exiftool
exifCmd := exec.Command("exiftool", "-overwrite_original", "-all=", "-tagsFromFile", "@", "-orientation", ORIGINAL_DIR+"/"+filename)
if err := exifCmd.Run(); err != nil {
return fmt.Errorf("Failed to remove EXIF data from %s: %v\n", filename, err)
}
// Generate thumbnail using ImageMagick convert
convertCmd := exec.Command("convert", ORIGINAL_DIR+"/"+filename, "-geometry", "600x600", THUMBS_DIR+"/"+filename)
if err := convertCmd.Run(); err != nil {
return fmt.Errorf("Failed to create thumbnail for %s: %v\n", filename, err)
}
}
I was struck by how much better Max's code is than mine! For all its flaws, Max's code is simple. It just does what it needs to do and gets out of the way.
Max's Imagebin is a single 233-line PHP script, interleaving code and HTML, of which the first 48 lines are a changelog of what I have done to it since inheriting it from Max. So call it 185 lines of code.
At school, Max used to carry around a HP 620LX in his blazer pocket. Remember this was a time before anyone had seen a smartphone. Sure, you had PDAs, but they sucked because they didn't have real keyboards. The HP 620LX was a palmtop computer, the height of coolness.
My Go version is 205 lines of code plus a 100-line HTML template, which is stored in an entire separate file. So call it 305 lines plus complexity penalty for the extra file. And my version is no better! And my version requires a build step, and you need to leave the daemon running. With Max's version you just stick the PHP file on the server and it runs whenever the web server asks it to.
ob_start();
passthru("ls images/original | sort -n | tail -n1");
$lastfilename = ob_get_contents();
ob_end_clean();
$lastnum = explode(".", $lastfilename);
$curnum = $lastnum[0] + 1;
And btw this is my third attempt at doing this in Go. I had to keep making a conscious effort not to make it even more complicated than this.
func highestImageNum() int {
files, err := filepath.Glob(ORIGINAL_DIR + "/*")
if err != nil {
return 0
}
re := regexp.MustCompile(`/(\d+)`)
highest := 0
for _, file := range files {
matches := re.FindStringSubmatch(file)
if len(matches) > 1 {
num, err := strconv.Atoi(matches[1])
if err == nil && num > highest {
highest = num
}
}
}
return highest
}
And some part of me doesn't even understand why my Go version is so much bigger. None of it looks extraneous. It has a few quality-of-life features, like automatically creating the directories if they don't already exist, and supporting multiple files in a single upload, But nothing that should make it twice as big. Are our tools just worse now? Was early 2000s PHP actually good?
While I was writing this, I noticed something else: Max's code doesn't define any functions! It's just a single straight line. Upload handling, HTML header, thumbnail code, HTML footer. When you put it like that, it's kind of surprising that it's so large. It hardly does anything at all!
Max didn't need a templating engine, he just wrote HTML and put his code inside <?php tags.
Max didn't need a request router, he just put his PHP file at the right place on the disk.
Max didn't need a request object, he just got query parameters out of $_GET.
Max didn't need a response writer, he just printed to stdout.
And Max didn't need version control, he just copied the file to index.php.bak if he was worried he might want to revert his changes.
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. It's so simple that nothing goes wrong. I expect I'd have much more trouble getting my Go code to keep running for the next 15 years.
And yeah we all scoff at these stupid outdated practices, but what's our answer? We make a grand effort to write a simpler, better, modern replacement, and it ends up twice as complicated and worse?
For what?
The reason the Go code is so much bigger is because it checks and (kind of) handles errors everywhere (?) they could occur. The PHP code just ignores them and flies on through regardless. But even if you get rid of checking for the more unlikely error cases, the Go version is longer. It's longer because it's structured across several functions, and with a separate template. The Go version is Designed. It's Engineered. But it's not better.
I think there are lessons to (re-)learn from Max's style. You don't always have to make everything into a big structure with lots of moving parts. Sometimes you're allowed to just write simple straight-line code. Sometimes that's fine. Sometimes that's better.
Longevity doesn't always come from engineering sophistication. Just as often, longevity comes from simplicity.
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. Whether that simplicity came from wisdom or from naivety doesn't matter. The result speaks for itself.
So I'm not going to bother running my Go version of the Imagebin. I'm going to leave Max's code in place, and I'm going to let my server keep running PHP.
And I think that's how it should be.
I didn't feel comfortable
hacking up the code of a Real Programmer.
If you like my blog, please consider subscribing to the RSS feed or the mailing list: