Handy comparison pictures

So here's a random fitness-related link.  It's a handy page I found for doing visual body fat comparisons.  I particularly like this one because (at least for the men's section) a bunch of the pictures are of the same guy.  Apparently he must have lost a bunch of weight and kept good track of it.  That makes it much easier to see the differences in physique than when you're looking at different people with different sizes and shapes.

If you're not into fitness, you might not be familiar with body fat measurement.  Body fat percentage is one of those metrics that are handy for gauging your fitness level.  It's basically just the percentage of your body weight that consists of fat.  If you don't train, then just tracking your weight is fine, but once you're lifting weights or doing other strength training, you're going to build muscle.  Since muscle is more dense than fat, it makes weight tracking less reliable - you can get into a situation where you're getting thinner, but are actually gaining weight because you're burning fat and building muscle.

There are a number of ways to measure body fat: there's the DEXA scan, which stands for dual energy X-ray absorptiometry and is considered the "gold standard"; there are multiple techniques using calipers to measure skin folds; and there's the seriously low-tech method of eyeballing it, i.e. using comparison pictures. Of course, none of these measurement techniques is exact.  Even the DEXA scan is just an estimate that can be influenced by a variety of factors.  The only 100% accurate way to determine your body fat percentage is to excise every gram of fat from your body, weigh it, and compare that to your total weight - which can't be done without killing you.

Looking at pictures is the method I use.  It's obviously the least accurate and the least precise, but it has the benefit of being by far the cheapest and easiest.  I mean, you're just looking at pictures on the internet, for crying out loud!  And for my purposes, the exact number doesn't really matter anyway.  It's more a reference point for helping to figure out what weight changes mean and where my general fitness level is.  It's nice to have a general idea, but it's not important enough to me to spend significant time or money on it.  It's just one metric among many.  How useful it is depends on your needs and goals.

Conference talks

The other day I decided to go back to something I did when I was still working in the office: putting tech conference talks on in the background while I work.  Sometimes it's nice to have a little background noise if I'm not trying to concentrate too deeply on something (what I'm currently working on involved a lot of waiting for CI pipelines to run).  Of course, sometimes I my concentration level ramps up and I totally tune out the entire talk, but sometimes I don't and it ends up being interesting.

This particular afternoon I was listening to some talks from the GOTOpia Europe 2020 virtual conference.  This one had an especially good lineup, including talks from Dave Thomas, Kevlin Henney, and Allen Holub, who are some of my favorite presenters.  Cat Swetel, who I'd never seen speak before, also had a very interesting presentation on metrics that I would heartily recommend.

It might not be the same vibe as the live conferences, but it's at least nice to be reminded that the entire world hasn't been canceled due to the pandemic.  And there are always some interesting discussions at GOTO, so it's worth a watch.

Composer autoload annoyances

Note to self: Sometimes you need to run composer du -o to make things work.

I'm not entirely sure why.  But it's a pain in the butt.

This has come up a couple of times in working on one of our projects for work.  This particular one is an internal command-line application written in PHP and using the command-line components from the Symfony framework.  I won't get into the details, but the point is that it glues together the various steps required to configure and run certain things on Linux-based servers.  So to test it, I have to put the code on my test server and make sure it works there.

The problem that I ran into today was that I tried to add a new command class to the application and it barfed all over itself.  The Symfony DI container complained that it couldn't find a certain class name in a certain file. The PSR-4 autoloader requires that the class name and namespace match the filesystem path, so usually this indicates a typo in one of those.  But in this case, everything was fine.  The app worked fine on my laptop, and if I deleted the new command, it worked again.

Well, it turns out that running composer du -o fixed it.  I suspect, based on the composer documentation, that the issue was that the class map was being cached by the opcache.  The Symfony cache was empty, so that's about the only one left.  Unfortunately, this is pretty opaque when it comes to trouble-shooting.  I would have expected it to fall back to reading the filesystem, but apparently there's more to it than that.  Perhaps it's related to how Symfony collects the commands - I haven't put in the time to investigate it.

But in any case, that's something to look out for.  Gotta love those weird errors that give you absolutely no indication of the solution.

A very retro Christmas

I'm certainly not a "hardcore" gamer by any stretch of the imagination.  However, like many kids who grew up in the 80s and 90s, I have fond memories of playing Nintendo.  So I still have a soft spot for retro games, which I occasionally play via emulation.  Turns out there's a large community of retro games on YouTube, so I sometimes watch their videos.  I particularly like channels like The Gaming Historian, that trace the history and context of games, franchises, or pieces of hardware.

I've also recently taken to watching the odd retro gaming video on YouTube.  In particular, I'm kind of fascinated by speed-running.  Several months ago I stumbled upon this video of a Dragon Warrior speed run in less than half an hour.  I loved Dragon Warrior as a kid, and I remember spending hours and hours grinding so that I'd be at a high enough level to move on to the next area.  But this run used random number generator (RNG) manipulation to control the "random" actions of the game and basically beat it over lunch.  I find the amount of work and investigation that goes into this type of thing truly impressive.  (Though I can no longer remember what it's like to have the free time that you'd need to do this.)

Anyway, while I'm watching these videos on my tablet or phone, my son will sometimes sidle up and watch them over my shoulder.  So he knows about and is interested in various old-school games.  He even sometimes watches me plays them or takes a turn playing them on my phone.  He's also been getting more interested in games, coding, and computers in general lately.

So this year, we got him a DIY project for Christmas - a retro gaming console.  Or, more specifically, the components to build a retro gaming console.  This consisted of a Raspberry Pi 400 CanaKit and a couple of IR wireless controllers.  I walked him through assembling the hardware, showing him what the components were and what they're for, and took care of flashing the microSD card with a RetroPie image and getting some games onto it.

Overall, this was actually a remarkably easy process.  The CanaKit comes with all the hardware you need, except for controllers, and it's pretty easy to up together.  I don't think I even needed any tools.  The controllers I got were advertised as working with Raspberry Pi and "just worked".  Even installing RetroPie was pretty painless.  The process was fairly well documented and required minimal configuration.

So now we have a nice little retro gaming console.  RetroPie works well and has a fairly easy to use interface (it even has some instructions for controlling it with the gamepad on-screen).  My son hasn't had much problem with it so far.  In fact, we beat Contra together this afternoon.  We used the Konami code to get 30 lives, of course.  I can't imagine playing without it - I'd almost forgotten how brutally difficult early video games could be.

Refactoring LnBlog

Author's note:  Happy new year!  I thought I'd start the year off with another old post that's been sitting in my drafts folder since March 24, 2013.  This time, though, I'm going to provide more inline commentary.  As usual, the interjections will be italicized and in parentheses.

You see, this post is on LnBlog, and specifically what is (or was) wrong with it.  If you don't know, LnBlog is the software that runs this website - I wrote it as a "teach yourself PHP" project starting back around 2005.  I've been improving it, on and off, ever since.  So in this post, I'm going to show you what I thought of it back in 2013 and then discuss what I think now and what has changed.  Hopefully it will be somewhat enlightening.  Enjoy!

The year is (relatively) new and it's time for some reflection. In this case, reflection on past code - namely LnBlog, the software that runs this site.

I've come a long way from LnBlog, which as my first "teach yourself PHP" project. I've now been doing full-time professional PHP development since 2007 and can reasonably claim to have some expertise in it. And looking back, while the LnBlog codebase is surprisingly not horrifying for someone who had a whopping two months of web development experience going into it, it's still a mess. So it's time to start slowly refactoring it. And who knows? Blogging my thought process might be useful or interesting to others.

(Back to now: I actually did blog some of this stuff, but not until 2017 or so.  And I still agree with that initial assessment.  The code had plenty of problems then and it still does.  If I were starting fresh today, I'd probably do almost everything differently.  But on the other hand, I've seen much worse in much newer code.  And in the last three years or so I've been making slow and steady improvements.)

The Issues

There are lot of things about LnBlog that need changing. A few of them are functional, but it's mostly maintenance issues. By that I mean that the code is not amenable to change. It's not well organized, it's too hard to understand, and it's too difficult to make updates. So let's go over a few of the obvious difficulties.

1. The plugin system

I have to face it - the plugin system is an unholy mess. The entire design is poorly thought out. It's built on the premise that a "plugin" will be a single PHP file, which makes things...painful. Any plugin with significant functionality or a decent amount markup starts to get messy very quickly. The "single file" limitation makes adding styles and JavaScript ugly as well.

On the up side, the event-driven aspect works reasonably well. The code for it is a bit nasty, but it works. The main problem is that there aren't really enough extension points. It needs a bit more granularity, I think. Or perhaps it just needs to be better organized.

(Back to now: I still agree with most of this, except perhaps the thing about extension points.  So far, the only place where that's been a real problem is when it comes to inserting markup mid-page.  But yeah, the whole "a plugin is one file" thing was ill-conceived.  The good news is that it's totally fixable - I just need to figure out some design conventions around splitting things out, which hasn't been a priority so far.)

2. The templating system

This one is also an unholy mess. The idea isn't bad - allow any file in a theme to be over-ridden. However, I tried to abstract the template files too much. The files are too big and contain too much logic. Also, the simple template library I'm using is more a hindrance than a help. I'd be better off just ditching it.

I've also been thinking of getting rid of the translation support. Let's face it - I'm the only person using this software. And I'm only fluent in one language. Granted, the translation markers don't cause any harm, but they don't really do anything for me either, and accounting for them in JS is a bit of a pain.

(Back to now: The only thing I still agree with here is that the existing templates are a mess.  But that has nothing to do with the template system - I just did a bad job of implementing the template logic.  I'm working on fixing that - for instance, I added some Jinja-like block functionality to the template library.  I had considered re-writing the templates in Twig or something, but it quickly became obvious that that would be a huge amount of work, that it would be difficult to do in a piece-wise fashion, and it's not clear that the payoff would be worth it.  Likewise with the translation markers - taking them out would be a bunch of work for almost zero payoff and the JS thing isn't really that big a deal.  Besides, if I ever changed my mind again it's WAY more work to put them back in.)

3. The UI sucks

Yeah, my client-side skills have come a long way since I built LnBlog. The UI is very Web 1.0. The JavaScript is poorly written, the style sheets are a mess, the markup is badly done, and it's generally "serviceable" at best.

As I realized the other day, the style sheets and markup are probably the worst part. Trying to update them is difficult at best, which is exactly the opposite of what you want in a theme system. In retrospect, my idea to replace files wholesale rather than overriding seems misguided. They're too fragmented. When it comes to the style sheets and JavaScript, this also hurts performance, because there are a lot of files and everything is loaded in the page head.

(Back to now: This is pretty much still accurate.  I've been slowly improving the UI, but it's still not looking particularly "modern".  That's not such a big deal, but the templates and CSS are still a pain-point.  Really, what I need to do is rework the theme system so that I can easily make lighter-weight themes, i.e. I should be able to just create one override CSS file and call it good.  I have the framework for that in place, but I have yet to actually go through the existing themes and make that work.)

4. Too much compatibility

When I first started writing LnBlog, I had a really crappy shared web hosting account. And by "really crappy", I mean it offered no database server and had safe-mode and the various other half-baked PHP "security measures" enabled by default. So I actually built LnBlog to be maximally compatible with such an environment.

These days, you can get decent hosting pretty cheap. So unless you can't afford to pay anything, there's no need to settle for such crappy hosting. And again, let's be honest here - I don't even know anyone other than me who's using this software. So supporting such crappy, hypothetical configurations is a waste of my time.

In addition, I really put an absolutely ridiculous number of configuration settings into LnBlog. The main config file is extensively documented and comes to over 700 lines. That's completely nuts and a pain to deal with. It contains a lot of settings that are pointless and that hardly anyone would ever want to override. And most of those could be moved into a GUI rather than having to edit a file. There's absolutely no reason for many of those settings.

(Back to now: This is also still true.  I've been looking at redoing the config system, but that's another one of those things that is a big change because it has tendrils all through the code.  I have been moving some stuff out of the main blogconfig.php file, and I've been avoiding adding to it, but there's still a lot there.  For the most part, it's not a huge issue, since most of the things you would want to configure are through the UI, but still....)

5. No real controller structure

I knew nothing of MVC or design patterns when I first wrote LnBlog. As a result, the "glue" code is in the form of old-style procedural pages. They're messy, poorly organized, and hard to maintain. A more modern approach would make things much easier to deal with.

(Back to now: The old "pages" are dead in all but name.  A handful of them still exist, but they're three-liners that just delegate to a controller class.  The bad news is that it's pretty much just two monolithic controller classes with all the old logic dumped into them.  So that sucks.  But they have dependency injection and some unit test coverage, so this is still an improvement.  And I've at least got a little routing groundwork laid so that I could start breaking off pieces of functionality into other classes in the future.)

The Problem

While I'd like to fix all this stuff in one shot, there are three big problems here:

  1. That's a lot of stuff, both in terms of the number of tasks and the amount of code involved.
  2. I no longer have the kind of free time I did when I first wrote this.
  3. I'm actually using this software.

Of course, those are two sides of the same coin.  LnBlog isn't huge, but it isn't tiny either - the codebase is upwards of 20,000 lines.  That wouldn't be a big deal if I were working on it as my full-time job, but this is a side-project and I can devote maybe a couple hours a day to it sometimes.  So major surgery is pretty much out.  And the third factor means that I need to be careful about breaking changes - not only do I not want to break my own website, but I also want to avoid having to do a lot of migration work because writing migration scripts is not my idea of a fun way to spend my free time.

(Back to now: This is always a problem with open-source and side projects.  Nothing has changed here except, perhaps, my development process.  After that year I spent learning about the Personal Software Process, I started using some of those methods for my personal projects.  The main change was that, when making any kind of a big change or feature addition, I actual do a semi-formal process with a requirements and design phase and review phases.  It sounds kind of silly for a personal project, but it's actually extremely useful.  The main benefit is just in having my thoughts documented.  Since I might be going a week or more between coding sessions on any particular feature, it's insanely helpful to have documentation to refer back to.  That way I don't have to remember or waste time figuring things out again.  And by having design- and code-review phases as part of my development process, I have a built-in reminder to go back and check that I actually implemented all those things I documented.  Having the whole thing written out just makes it much easier when you have long gaps in between work sessions.)

General commentary from the present: So as you can see from the above comments, I've fixed or am fixing a lot of the things that bothered me about LnBlog eight years ago.  In the last two or three years I've put a lot of work into this project again.  Part of it is because I actually use it and want it to be better, but part of it is also "sharpening the saw".  I've been using LnBlog as an exercise in building my development skills.  It's not just coding new features, like the flurry of development in the first two years or so that I worked on LnBlog, it's cleaning up my past messes, adding quality assurance (in the form of tests and static analysis), updating the documentation and figuring out how to balance responsible project management with limited resources).  It's an exercise in managing legacy code.

To me, this is a useful and important thing to practice.  As a professional developer, you will have to deal with legacy code.  In my day job, I've had to deal with code that was written by our CEO 10+ years ago when he started the company.  Software is a weird combination of things that live a week and things that live forever, and there's seldom any good way to tell which group the code will be in when you're writing it.  So while it's important to know how to write code correctly the first time, it's also important to know how to deal with the reality of the code you have.  And no, "let's rewrite it" is not dealing with reality.  And when you have a code-base that's 15 years old, that you're actively using, and that you originally wrote, it's a great opportunity to experiment and build your skills in terms of modernizing legacy code.

And that's just what I'm doing.  Slowly but surely, LnBlog is getting better.  I've implemented a bunch of new features, and in the process I've worked on my design and analysis skills, both at a product level and at a technical level.  I've fixed a bunch of bugs, which makes my life easier.  I've implemented additional tests and static analysis, which also makes my life easier by finding bugs faster and giving me more confidence in my code.  I've improved the design of the system, which again makes my life easier because I can now do more with less effort.  Sure, there's still plenty do to, but I've made lots of progress, and things are only getting better.