The Story of Max, a Real Programmer
Sun 29 June 2025
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
", 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
", 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