PHP retrospective

Here's a talk Rasmus recently did on 25 years of working on PHP.  I found it interesting and entertaining.

One of the things I thought was really interesting was the explanation for many of the more hair-brained features of PHP.  It's all the same explanation - for most of it's history, Rasmus was operating under the assumption that PHP was about six months from being out-dated and replaced.  

This is interesting to me because it's the sort of thing that most developers can relate to.  In retrospect, it's obvious that features like safe_mode were a bad idea.  But on the other hand, if you think that your language is going to be replaced "soon", then it kind of makes sense as a quick-fix for a serious issue.

To me, this speaks to the trade-off between "always do it right" and "just do what you need to".  You often hear the latter perspective from the agile methods camp.  For instance, it's the motivating idea behind the "minimum viable product", i.e. that you should build the smallest thing that remotely even remotely fits the requirements, even if you know you're going to immediately throw it away, because "hey, you never know if it'll be good enough".  But then the software craftsmanship camp, which is kind of related to the agile one, often give the opposite advice, that you should "always do it right, because it might be good enough to go to production."

I had this conundrum in a previous job.  We were building a system to integrate 3D models of building interiors with 360-degree internal panoramic images and and external aerial imagery.  The general idea was that you could explore the interior of a building as well as look at the surroundings using oblique and orthogonal images, as well as orthomosaic imagery.  It was actually a pretty cool system, and we built a nice, unified web interface that allowed you to transition seamlessly between the various views.

That's all well and good, but there was a problem: the contract with the customer called for an offline version of the system.  This was a major issue, because the application was leveraging our existing technology (which was online-only) for the external imagery.  So we were faced with the prospect of taking our existing online infrastructure, which was based on PostgreSQL and PHP, and somehow turning that into a stand-alone offline application.  In the best-case scenario, this seemed like a big pain in the neck in terms of packaging and maintenance.  In the worst case, it could be a massive time and resource sink.

Neither I nor the other senior engineer on the team were enthusiastic about this.  I mean, it's a lot of work and there was no clear use-case for it.  In fact, the only reason we were doing it was because the contract said we had to.  So what did we do?  We cheated and went with the "minimum viable product" solution.  We knew that, either way, we'd only be able to include a limited set of external imagery, so we took advantage of that fact.  Rather than repackage the entire web-based system for offline use, we pre-calculated every possible AJAX call that the web page could make.  It was a decent number of calls, but completely unreasonable.  That allowed us to just ship the front-end (wrapped up in NW.js) with a bunch of JSON files and a little bit of custom mapper logic to map the standard AJAX calls to the pre-calculated JSON responses.

And you know what?  It worked just fine.  It met the requirements and held up our part of the contract.  It might not have been the "right way" to do it, but it worked.  And last I knew, there were no complaints from the customer and no interest in an offline solution from any other customer, which vindicates our choice of a "cheat" solution.

Of course, if we wanted to have a really flexible, powerful solution that we could extend in the future, we would have done it "right".  But in this case, we kinda figured that this project wasn't going anyplace long-term, so we went with the easy fix - just like Rasmus.  So while I'm still annoyed by some of his early choices, his explanation gives me a little context and some sympathy for his thought process.

Getting fit

The other week, I watched a Jarvis Johnson video about losing 50 pounds.  For the zero people who've been following my blog for over ten years, you might know that I did something similar in 2007 and documented my progress here.  (Although, unlike Jarvis, I did do some exercise.  Not a lot, but some.)

I've actually been on a similar journey this year.  It's a little different this time, though, both to what I did ten years ago and to what Jarvis did.  This time, instead of just trying to "lose weight", my goal is to actually get healthier and improve my overall fitness.

Motivation

The last time I lost weight, the goal was just the traditional "to lose X pounds" or "get to X weight".  This time, the goal is more specific: to lose fat (not the same as "losing weight"), build lean muscle, and develop healthier eating habits.  Why?  Well, there are several reasons.  For one, I want to be in sufficiently good shape to play with my son until he's too old to think I'm cool.  I also want to stay strong and healthy long enough that when I one day (hopefully) have grandchildren, I'll still be able to run around and play with them too.  In fact, I'd like be able to stay healthy and mobile for as long as humanly possible - preferably until I die.  And the best way to ensure that is to start taking better care of myself and building better habits now.

But it's more than just that (as if that wasn't enough).  There's also a self-actualization aspect to it.  Part of living a fulfilling life is constantly trying to develop yourself and becoming better than you were before. There are many axes along which you can do that: social, intellectual, moral, spiritual, etc.  Well, I came to the realization that physical development is also a valid form of self-improvement.  We often forget that our physical and mental health are not independent - they directly impact each other.  Your mind is connected to your body, in a very literal sense.  So the healthier you are physically, the more mental energy and stamina you can muster, which in turn helps you grow in other areas.  Penn Jillette summed this aspect up nicely in his interview with Joe Rogan here:

Another important motivation is to serve as a role-model.  As I mentioned above, I have a young son and I want him to grow up to be a mentally and physically strong, healthy, confident, and independent adult.  He's still too young to appreciate the implications, but I want him to learn how to eat a healthy diet, exercise safely and productively, and develop the discipline to maintain the good habits he'll need to succeed in live.  We live in a society that doesn't encourage healthy living, in either the physical or emotional sense, so I can't count on him to pick this up on his own.  I figure if I can start living a healthy life-style myself, I can help him learn the skills he needs early and not have to figure it out later in life like me.

Inspiration

So, why bother to change?  Yes, I've given some good reasons above, but let's be honest - most people could give those same reasons.  And the fact is, most people don't act on them, as I didn't for many years.  So clearly I needed more than just motivation to change my lifestyle.  I needed inspiration.

It's kind of lame, but I'll be honest.  The truth is that I got inspired by allowing myself to be sucked down a YouTube rabbit-hole.  There, I said it.

It started with martial arts channels.  In particular, some of Ramsey Dewey's videos.  He had a video where he talked about training to be a fighter and gave this simple piece of advice - just do something to improve yourself every day.  It doesn't have to be a big, dramatic change - small things work too.  The key is to just do something, consistently, every day.  And if you keep at it and you will get better.  It might not happen fast, and your progress might not be even, but that's OK.  The important thing is to put in consistent effort towards your goal.

At that point, I felt like I'd like to be a little stronger (sitting behind a keyboard all day is not conducive to muscle development), so I decided to take Ramsey's advice and start doing some strength exercises every night.  Nothing fancy - just some push-ups and sit-ups before bed.  But it was something and I was doing it consistently.  And after a few weeks, I noticed that I was able to do more of them than when I started, so I was making progress.  That prompted me to start increasing the number of reps, trying different techniques, and adding some squats and other leg exercises.

Looking for more exercise ideas led me to the world of YouTube fitness, which, like the rest of the internet, has some great content as well as a whole lot of morons.  Fortunately, good channels aren't hard to find, so I quickly discovered Athlean-X and Calisthenicmovement.  Both offer lots of excellent exercise demonstrations, workout ideas, and lots of background information about nutrition, the bio-mechanics of various movements, and how they fit together.  From there, I branched out into channels that focus less on demonstrations and workout specifics and more on commentary and criticism, such as Every Damn Day Fitness and Shredded Sports Science, both of which offer humor combined with reality-checks intended to cut through the nonsense that permeates much of the fitness industry.

I think the main thing I took from these channels, and what inspired me to get into shape, was to really internalize the idea that your fitness is something that is within your control.  Quite often people think about fitness as something that happens to them - that either you're naturally thin and athletic, or you're not, and there's not really that much you can do about it either way.  But that's not the case.  Sure, there are people who have legitimate medical issues that impact their diet or ability to exercise, but the majority of over-weight or out-of-shape people do have the ability to change their body composition and fitness level.  And it's not a choice between "dad bod" and spending four hours a day in the gym, either.  Different people can have different goals in line with their lifestyle and other commitments, and there are different ways to achieve those goals.  It's not always easy, but it's certainly not impossible.

This sounds like a fairly obvious thing, and I think it's something I sort of knew on an intellectual level, but I didn't really "get it".  But after a while, I realized that, conceptually, getting in shape is no different than learning a new programming language or technology.  It requires hard work, and it's easier if you have a plan and someone to guide you, but it is achievable if you're willing to put in the time and effort.  There are no shortcuts, no silver bullets, no magic formula - just time and hard work.  And while it's true that this stuff comes easier to some people than to others, nobody is born into it - the limiting factors are time and energy, not genetics.

Taking Action

For me, internalizing this message and seeing a few good examples was enough to move me to action.  When you think about "getting in shape" in terms of "natural athletes" vs. "regular people", it's easy to write off the possibility of meaningful change.  But when you think of it in terms of "just putting in the work"...that's a different story.  At that point, I realized: I can do this.  I know how to work hard, maintain discipline, and follow and monitor a plan.  Heck, I do that in my work all the time.  This is something I can realistically achieve.  

So I started putting changes in place.  After a few months of doing the body-weight exercises I mentioned above, I decided to start adjusting my diet.  I didn't "go on a diet", but rather started trying to build healthier eating habits.  Basically, this meant moving towards a the kind of diet your grandmother always said you should be eating - cut down on the breads and sweets, cut down on between-meal snacks, and eat lots of vegetables.  In fact, for the first few months I completely cut out between meal snacks.  I also cut way down on my alcohol consumption.  I went from "a drink or two before bed" down to "one drink once in a while".

For my meals, I started making a point of having a sizable serving of green vegetables with every lunch and dinner and cutting down on the refined carbohydrates (breads, pasta, etc.).  To facilitate this, I started pre-cooking my lunches for the week.  On Sunday evening, I prepare four days worth of lunch (I still take advantage of "free lunch Friday" at the office) which I then portion out so that I can just grab them each morning before I leave.  As an example, last week I made turkey burgers and chicken breast (for alternate days), roasted sweet potatoes, broccoli sautéed with onions, and some chopped kale salad from Wegmans.  Lest this sound boring, I make liberal use of the spice cabinet to jazz things up.  We have a number of interesting spice mixes from Pennzey's that add a lot of flavor to the meat and veggies.

After about three months of this, I was down about 15 pounds (from 191 to around 175) and was feeling stronger from the strength training.  However, it was also becoming clear that I needed to be more organized about my training.  This whole "cobble together a workout from YouTube videos" think worked fine initially, but it was becoming clear that I didn't really know what I was doing.  I was starting to notice some strength imbalances and mobility issues and I didn't know how to address them or work around them.  So I decided to get myself on an organized training program.

I decided to go with the Athlean-X "AX-1 Training Camp" program.  I chose this partly because I was already familiar with the YouTube channel and trusted the quality of the material.  But the program had several other aspects that I found very appealing:

  1. It takes a "don't waste time" philosophy, which they sum up as "trading time for intensity".  The short version is that, unless you have difficulty executing one or more of the exercises (which did occasionally happen to me), the workouts shouldn't last more than 40 minutes (about 45 if you do the optional "six-pack shuffle" abdominal workouts that are included).  In fact, some of the conditioning workouts can take as little as ten minutes (just don't mistake "short" for "easy").
  2. The entire program can be accessed from your phone.  It's a mobile-friendly website that lets you access your workouts, watch the demo videos, and keep track of your weight and repetition numbers for each exercise.
  3. You can do the all the workouts from home with relatively little equipment.  I only had to buy a doorway pull-up bar, a physio ball, and a set of adjustable dumbbells.  Not only does it save money over a gym membership, it also saves time - no driving back and forth.  (Note that really do need an adjustable dumbbell set.  The program is based on lifting to failure in a certain range of repetitions, so you need to be able to move the weight up and down in fairly small increments, and the only way to do that is to have adjustable dumbbells or have a rack of a dozen dumbbells in five-pound increments, which is both costly and takes up a lot of space.)  In fact, the entire program has a "no excuses" philosophy to exercise, offering adaptations and substitutions you can make to the exercises.  One of the "extras" is a set of videos showing various ways to get an exercise in even if you don't have the "proper" equipment for it.  There are also plenty of options offered for the conditioning workouts, including ones that can be done indoors with zero equipment.

I've been really enjoying this program so far and would definitely recommend it.  The one thing to keep in mind is that when Athlean-X uses the tagline "if you want to look like an athlete, you have to train like an athlete," they aren't kidding.  Even though it's the "beginner-level" program, AX-1 is definitely challenging and requires dedication.  If you are extremely over-weight or if you haven't been exercising at all, then don't expect to have an easy time with it.  You might want to consider starting with something less demanding or be prepared in advance to repeat the first month several times.  (The program is structured around three one-month phases, each of which ends in a "challenge".  If you don't "pass" the challenge, you're supposed to repeat the current phase until you can pass.  You also repeat the challenges in later months, so you can track the changes in your performance.)

Results

Long story short: so far, my results have been very good.  

At this point, I'm down to about 168 pounds and in the best shape of my life by far.  I don't look like a fitness magazine model or anything, but I look better and feel feel stronger than I ever have and my energy and endurance levels, both physical and mental, are higher than before.  I'm also discovering bones and muscles that I didn't even know I had, which is cool but kinda weird at the same time.

In terms of lifestyle changes, things are going quite well.  I started the basic body-weight exercises last November, changed my diet in March, and switched over to doing AX-1 in June.  I'm currently maintaining a six-day training schedule (I'm on my second round of AX-1, this time including one of their "TNT" plugins, which adds an extra workout), doing my workouts first thing in the morning before work.  I am still pre-cooking my lunches and maintaining a healthy diet without too much difficulty or feeling of restriction.  I'm also being more mindful of my sleep schedule and getting to bed at a reasonable time.  While all of this does require some effort and discipline, I'm not finding it to be burdensome and I'm feeling really good, so the extra effort is definitely worth it.  At this point I can see myself maintaining this lifestyle for a very long time, which was exactly the point in the first place.

Birthday book acquisitions

This is my more-than-slightly belated birthday post. cool

This year, my birthday fell on the last day of our vacation in Cape Cod.  We've been there several times, so we've seen most of the attractions we're interested in at least once.  Thus we had a nice, restful, laid-back week.

I'm not usually much for shopping, but one of my traditional activities on the cape is to go shopping for used books.  (Actually, I do that pretty much everywhere.)  However, this year I was very disappointed to find that my favorite used book shop on Main St. in downtown Hyannis had closed! I'd shopped there every time we've been to the cape and they had a really nice selection.  I define a "nice selection" at a used book store as one that includes a wide range of unusual books on a wide variety of topics (such as this one, which I bought at that shop two years ago and spent my vacation week reading), as opposed to used book stores that carry mostly mass-market paperbacks, usually in the mystery and romance genres.  

Fortunately, I was able to find another good used book shop - Parnassus Book Services in Yarmouth.  We always stay in Hyannis, so it's not as convenient as the other one was, but they've got a great selection.  In fact, it's a bit daunting - the shelves literally go up to the ceiling and they're completely packed.

Yet even with the abbreviated browsing time I had when shopping with a small child, I still managed to find several interesting volumes, including:

  1. Islam by Karen Armstong
  2. A History of the Vikings by Gwyn Jones
  3. The Book of J by Bloom and Rosenberg
  4. Dinosaur Lives by John Horner
  5. Aristophanes' The Forgs
  6. Exodus: The True Story by Ian Wilson 
  7. Discovering Dinosaurs by Norell, Gaffney, and Dingus
  8. Fundamentals of Elcetronic Data Processing: An Introduction To Business Computer Programming, edited by Rice and Freidman

My birthday book haul

As you can see, my book tastes are a bit eclectic.  Two themes that are obvious are my interest in studying religion and Dinosaurs.  The former is a legacy of my BA in Philosophy, while the latter is a result of being the father of a six-year-old boy - I loved dinosaurs when I was young too, and my son's interest in them re-sparked mine.

I couldn't resist the one on the bottom, though: Fundamentals of Electronic Data Processing: An Introduction to Business Computer Programming.  It's from the 1960's, so basically a piece of computing history.  I've got a couple of other computing books of similar vintage sitting on my shelf, though this is certainly the oldest.  One of these days I'll have to read them all the way through and write up some reviews, like I did with my copy of The Mythical Man-Month.  It's always interesting to see just how much has stayed the same despite the radical changes in technology.

I give up - switching to GItHub

Well, I officially give up.  I'm switching to GitHub.

If you read back through this blog, you might get the idea that I'm a bit of a contrarian.  I'm generally not the type to jump on the latest popular thing.  I'd rather go my own way and do what I think is best than go along with the crowd.  But at the same time, I know a lost cause when I see it and I can recognize when it's time to cut my losses.

For many years, I ran my own Mercurial repository on my web host, including the web viewer interface, as well as my own issue tracker (originally MantisBT, more recently The Bug Genie).  However, I've reached the point where I can't justify doing that anymore.  So I'm giving up and switching over to GitHub like everybody else.

I take no real pleasure in this.  I've been using Git professionally for many years, but I've never been a big fan of it.  I mean, I can't say it's bad - it's not.  But I think it's hard to use an more complicated than it needs to be.  As a comment I once saw put it, Git "isn't a revision control system, it's more of a workflow tool that you can use to do version control."  And I still think the only reason Git got popular is because it was created by programming celebrity Linus Torvalds.  If it had been created by Joe Nobody I suspect it would probably be in the same boat as Bazaar today.

That said, at this point it's clear that Git has won the distributed VCS war, and done so decisively.  Everything supports Git, and nothing supports Mercurial.  Heck, even BitBucket, the original cloud Mercurial host, is now dropping Mercurial support.  For me, that was kind of the final nail in the coffin.  

That's not the only reason for my switch, though.  There are a bunch of smaller things that have been adding up over time:

  • There's just more tool support for Git.  These days, if a development tool has any VCS integration, it's for Git.  Mercurial is left out in the cold.
  • While running my own Mercurial and bug tracker installations isn't a huge maintenance burden, it is a burden.  Every now and then they break because of my host changing some configuration, or they need to be upgraded.  These days my time is scarce and it's no longer fun or interesting to do that work.
  • There are some niggling bugs in my existing environment.  The one that really annoys me is that my last Mercurial upgrade broke the script that integrates it with The Bug Genie.  I could probably fix it if I really wanted to, but the script is larger than you'd expect and it's not enough of an annoyance to dedicate the time it would take to become familiar with it.
  • My web host actually now provides support for Git hosting.  So I can actually still have my own repo on my own hosting (in addition to GitHub) without having to do any extra work.
  • Honestly, at this point I've got ore experience with Git than Mercurial, to the point that I find myself trying to run Git commands in my Mercurial repos.  So by using Mercurial at home I'm kind of fighting my own instincts, which is counterproductive.

So there you have it.  I'm currently in the process of converting all my Mercurial repos to Git.  After that, I'll look at moving my issue tracking in to GitHub.  In the long run, it's gonna be less work to just go with the flow.

LnBlog Refactoring Step 3: Uploads and drafts

It's time for the third, slightly shorter, installment of my ongoing series on refactoring my blogging software.  In the first part, I discussed reworking how post publication was done and in the second part I talked about reworking things to add Webmention support.  This time, we're going to talk about two mini-projects to improve the UI for editing posts.

This improvement is, I'm slightly sad to say, pretty boring.  It basically involves fixing a "bug" that's really an artifact of some very old design choices.  These choices led to the existing implementation behaving in unexpected ways when the workflow changed.

The Problem

Originally LnBlog was pretty basic and written almost entirely in HTML and PHP, i.e. there was no JavaScript to speak of.  You wrote posts either in raw HTML in a text area box, using "auto-markup", which just automatically linkified things, or using "LBCode", which is my own bastardized version of the BBCode markup that used to be popular on web forums.  I had implemented some plugins to support WYSIWYG post editors, but I didn't really use them and they didn't get much love.

The old LnBlog post editor

Well, I eventually got tired of writing in LBCode and switched to composing all my posts using the TinyMCE plugin.  That is now the standard way to compose your posts in LnBlog.  The problem is that the existing workflow wasn't really designed for WYSIWYG composition.

In the old model, the idea was that you could compose your entire post on the entry editing page, hit "publish", and it would all be submitted to the server in one go.  There's also a "review" button which renders your post as it would appear when published and a "save draft" button to save your work for later.  These also assume that submitting the post is an all-or-nothing operation.  So if you got part way done with your post and decided you didn't like it, you could just leave the page and nothing would be saved to the server.

At this point it is also worth noting how LnBlog stores its data.  Everything is file-based and entries are self-contained.  That means that each entry has a directory and that directory contains all the post data, comments, and uploaded files that are belong to that entry.

What's the problem with this?  Well, to have meaningful WYSIWYG editing, you need to be able to do things like upload a file and then be able to see it in the post editor.  In the old workflow, you'd have to write your post, insert an image tag with the file name of your picture (which would not render), add your picture as an upload, save the entry (either by saving the draft or using the "preview", which would have trigger a save if you had uploads), and then go back to editing your post.  This was an unacceptably workflow clunky.

On top of this, there was a further problem.  Even after you previewed your post, it still wouldn't render correctly in the WYSIWYG editor.  That's because the relative URLs were inconsistent.  The uploaded files got stored in a special, segregated draft directory, but the post editor page itself was not relative to that directory, so TinyMCE didn't have the right path to render it.  And you can't use an absolute URL because the URL will change after the post is published.

So there were two semi-related tasks to fix this.  The first was to introduce a better upload mechanism.  The old one was just a regular <input type="file"> box, which worked but wasn't especially user-friendly.  The second one was to fix things such that TinyMCE could consistently render the correct URL for any files we uploaded.

The solution - Design

The actual solution to this problem was not so much in the code as it was in changing the design.  The first part was simple: fix the clunky old upload process by introducing a more modern JavaScript widget to do the uploads.  So after looking at some alternatives, I decided to implement Dropzone.js as the standard upload mechanism.

The new, more modern LnBlog post editor.

The second part involved changing the workflow for writing and publishing posts.  The result was a somewhat simpler and more consistent workflow that reduces the number of branches in the code.  In the old workflow, you had the following possible cases when submitting a post to the server:

  1. New post being published (nothing saved yet).
  2. New post being saved as a draft (nothing saved yet).
  3. Existing draft post being published.
  4. Existing draft post being saved.
  5. New (not yet saved) post being previewed with attached files.
  6. Existing draft post being previewed with attached files.

This is kind of a lot of cases.  Too many, in fact.  Publishing and saving were slightly different depending on whether or not the entry already existed, and then there were the preview cases.  These were necessary because extra processing was required when an entry was previewed with new attachments because, well, if you attached an image, you'd want to see it.  So this complexity was a minor problem in and of itself.

So the solution was to change the workflow such that all of these are no longer special cases.  I did this by simply issuing the decree that all draft entries shall always already exist.  In other words, just create a new draft when we first open the new post editor.  This does two things for us:

  1. It allows us to solve the "relative URL" problem because now we can make the draft editing URL always relative to the draft storage directory.
  2. It eliminates some of those special cases.  If the draft always exists, then "publish new post" and "publish existing draft" are effectively the same operation.  When combined with the modern upload widget, this also eliminates the need for the special "preview" cases.

The implementation - Results

I won't get into the actual implementation details of these tasks because, frankly, they're not very interesting.  There aren't any good lessons or generalizations to take from the code - it's mostly just adapting the ideosyncratic stuff that was already there.

The implementation was also small and went fairly smoothly.  The upload widget was actually the hard part - there were a bunch of minor issues in the process of integrating that.  There were some issues with the other part as well, but less serious.  Much of it was just integration issues that weren't necessarily expected and would have been hard to foresee.  You know, the kind of thing you expect from legacy code.  Here's some stats from Process Dashboard:

Project File Upload Draft always exists
Hours to complete (planned): 4:13 3:00
Hours to complete (actual): 7:49 5:23
LOC changed/added (planned): 210 135
LOC changed/added (actual): 141 182
Defects/KLOC (found in test): 42.6 27.5
Defects/KLOC (total): 81.5 44.0

As you can see, my estimates here were not great.  The upload part involved more trial and error with Dropzone.js than I had expected and ended up with more bugs.  The draft workflow change went better, but I ended up spending more time on the design than I initially anticipated.  However, these tasks both had a lot of unknowns, so I didn't really expect the estimates to be that accurate.

Take Away

The interesting thing about this project was not so much what needed to be done but why it needed to be done. 

Editing posts is obvious a fundamental function of a blog, and it's one that I originally wrote way back in 2005.  It's worth remembering that the web was a very different place back then.  Internet Explorer was still the leading web browser; PHP 5 was still brand new; it wasn't yet considered "safe" to just use JavaScript for everything (because, hey, people might not have JavaScript enabled); internet speeds were still pretty slow; and browsing on mobile devices was just starting to become feasible.  In that world, a lot of the design decisions I made at the time seemed pretty reasonable.

But, of course, the web evolved.  The modern web makes it much easier for the file upload workflow to be asynchronous, which offers a much nicer user experience.  By ditching some of the biases and assumptions of the old post editor, I was more easily able to update the interface.

One of the interesting things to note here is that changing the post editing workflow was easier than the alternatives.  Keeping the old workflow was by no means impossible.  I kicked around several ideas that didn't involve changing it.  However, most of those had other limitations or complications and I eventually decided that they would ultimately be more work.  

This is something that comes up with some regularity when working with an older code-base.  It often happens that the assumptions baked into the architecture don't age well as the world around the application progresses.  Thus, when you need to finally "fix" that aspect of the app, you end up having to do a bit of cost-benefit analysis.  Is it better to re-vamp this part of the application?  Or should you shim in the new features in a kinda-hacky-but-it-works sort of way?

While as developers, our first instinct is usually to do the "real" fix and replace the old thing, the "correct" answer is seldom so straight-forward.  In this case, the "real" fix was relatively small and straight-forward.  But in other cases, the old assumptions are smeared through the entire application and trying to remove them becomes a nightmare.  It might take weeks or months to make a relatively simple change, and then weeks or months after that to deal with all the unforeseen fallout of that change.  Is that worth the effort?  It probably depends on what the "real" fix buys you.

I had a project at work once that was a great example of that.  On the surface, the request was a simple "I want to be able to update this field", where the field in question was data that was generally but not necessarily static. In most systems, this would be as simple as adding a UI to edit that field and having it update the datastore.  But in this case, that field was used internally as the unique identifier and was used that way across a number of different systems.  So this assumption was everywhere.  Everybody knew this was a terrible design, but it had been that way for a decade and was such a huge pain to fix that we had been putting it off for years.  When we finally bit the bullet and did it right, unraveling the baked-in assumptions about this piece of data took an entire team over a month.  At an extremely conservative estimate, that's well over $25,000 to fix "make this field updatable".  That's a pretty hefty price tag for something that seems so trivial.

The point is, old applications tend to have lots of weird, esoteric design decisions and implementation-specific issues that constrain them.  Sometimes removing these constraints is simple and straight-forward.  Sometimes it's not.  And without full context, it's often hard to tell when one it will be.  So whenever possible, try to have pity on the future maintenance programmer who will be working on your system and anticipate those kind of issues.  After all, that programmer might be you.