Code is Poetry

Menu

WordPress is releasing version 4.9.6 soon. This version number (which follows 4.9.5) is including a whole bunch of features meant to comply with the GDPR, the new European privacy law. This new feature set is a great idea, this version number is not. I say that because of semantic versioning.

Now, this isn’t meant to be an article about WordPress—I’d publish that on WPShout. But one of the biggest reasons I care so much about semantic versioning is that WordPress demonstrably does not. And while it’s not the end of the world — WordPress is still huge, despite ignoring semantic versioning — I think WordPress would be better if it did. So would your project.

What are Semantic Version Numbers?

The way that software version numbers should work is called semantic versioning. Semantic versioning is my preferred way of tagging software releases. Why? It’s the most well-known way to track how the software you interact with has changed. It makes it relatively easy to assess (intended) compatibility.

Here’s the simplest possible summary of semantic versioning, from what is widely regarded as the canonical source:

Given a version number MAJOR.MINOR.PATCH, increment the:

MAJOR version when you make incompatible API changes,

MINOR version when you add functionality in a backwards-compatible manner, and

PATCH version when you make backwards-compatible bug fixes.

Semantic Versioning Examples

By “incompatible API changes” on a MAJOR version change, I know I can’t upgrade with any guarantee of safety. That means that I understand that from 4.2.3 to 5.0.1, things that used to work may not. In the WordPress world, that would mean that my plugin or theme that relies on yours may break. In the web framework world, that’d mean that my code which inter-operates with your library or framework may need to be edited. Semantic versioning prescribes that this only happen on major releases, when the very front number changes.

When I hear that MINOR version will be backwards-compatible, I know I can update safely. I know that if something broke in our code interacting, it’s because you missed a test. Not because you intended this. So that lets me know that any incompatibility is something you regard as a bug. There may be new features in this release I’m interested in. I may choose to look into those.

When I hear that PATCH numbers are merely bug fixes, I know I should upgrade to them quickly, and with knowledge that nothing will have outwardly changed in your intent.

Taken together, this is a lot of power from a few numbers. If you’re using semantic versions, and I’m using version 1.7.4 of your software, I know that I can safely go all the way to a version like 1.12.68 without issue. I should also know that if it exists, I may have problems and complications if I try to update to 2.1.5. Further, I should expect that 1.7.5 would only fix minor bugs for me, while 1.8.0 will still be compatible. But you’ll have added a few features that I should check out to make my working with that changed software better.

Holistically, this system of semantic versioning has embedding into a few short characters, a great deal of meaning about intent. Software version numbers are something that we’ve agreed can be really useful shorthand for us to communicate with each other. They’re very brief and terse communication, like semaphore flags. A few can say a lot.

Other Methods of Software Versioning

There are a number of other ways that you can number software, and none of them are wrong. After all, if you’re making your code freely available, I don’t have a ton of room to complain. But I do find most other schemes I’ve encountered less useful than semantic versioning.

A truly sadistic scheme might tag every release with a random number generator. So the bug fix release after 3.21.7 was 67.4.92. 67.4.92 is then followed by a bunch of new features in 5.8.1. I’ve (thankfully) never seen a strategy that chaotic. But such a strategy wouldn’t always stop me from using your software. It would be something I’d have to factor into my decision, but if your stuff’s really great it may not be such a big obstacle that I wouldn’t use it.

The Wikipedia page on the topic covers a number of systems that are used to number software in great depth. The one used by TeX, a well-known and well-loved typesetting engine, caught my eye:

Since version 3, updates have been indicated by adding an extra digit at the end, so that the version number asymptotically approaches π [pi]; this is a form of unary numbering – the version number is the number of digits. The current version is 3.1415926. This is a reflection of the fact that TeX is now very stable, and only minor updates are anticipated.

The page also brings up somewhat more familiar strategies like decimal numbering — 1.168 — or date based systems. Windows famously, though hardly exclusively, went to named releases for a long period before returning to numeric ones with Windows 7, 8 and 10.

Why Versioning Is Communication

Version numbers are a complicated topic that I’ve now solved by explaining semantic versioning. So confusion about compatibility will never cause complications or strife anywhere in the world ever again. You’re welcome. 😜

More seriously, if you’re in the business of releasing software, I heartily encourage you to use semantic versioning. There are reasons—popular ones include marketing, art, personal eccentricity, or some idea you think is better—it may not be the right approach for your project. But it’s the sanest and best place I can think to start.

And the reason for that is that it saves you from needing to (for example) explain in long written blobs of text what people should expect in the next release of your consumer software or code library. Because the most common answer to software versioning is “use semantic versioning” a great deal of hassle can be avoided by adopting it.

Why WordPress’s Un-semantics Frustrate

Thanks to semantic versioning’s popularity, anytime we see a software version numbers in a digit.digit.digit format, we expect meaning in those numbers similar to, if not identical to, the standard.

Similar to, but not identical with, the semantic versioning standard is what you get in WordPress. WordPress effectively just does “major” and “patch” releases. And generally assures compatibility between major releases. So in some way, we can assume that version 4.4 is backwards-compatible with 4.3. This would typically make them “minor” versions, but (intended) compatibility hasn’t been perfect or universal historically. Specific examples are escaping my mind, but version 4.4 of WordPress probably broke some (small fraction of) 4.0 compatibility, as did 4.8 (probably).

Given that relatively solid track record of only-minor releases, why in May of 2018, is WordPress releasing a 4.9.6 with a bunch of new features? Because for marketing reasons BDFL Matt Mullenweg is holding WordPress 5.0 to be the release where the new visual editor “Gutenberg” is added. This means that if the WordPress team want to release something before 5.0, they must release a 4.x. And because in WordPress, people have never seen version numbers like 4.10.0 (3.9 gave way to 4.0, so 4.9 must give way to 5.0), we’re stuck with a major set of new features coming out in 4.9.6. No reading of the semantic versioning standard ever prescribed that.

This is really annoying for people who want to rely on finding useful meaning in version numbers. The only way you would know to expect that new features will go in in 4.9.6 is if you’re following the community news and discussion. Few people do.

It’s great that WordPress is getting GDPR-compliance-based changes. It’s also great that Gutenberg’s reservation of “5.0” isn’t stopping all forward-progress on the rest of WordPress. But it’s bad that 4.9.6 isn’t as safe and simple a release as 4.9.1 or 4.9.5. No one will know that from version number alone either.

Why You Should Be Thoughtful About What You Communicate

At heart, I think semantic versioning matters because we’re all just monkey doing our best to understand each other.

We’re helped in this quest by language. Number are a part of that language. Being careless about your software version numbers because you can use words to explain is silly.

Language helps us describe indescribable feelings more succinctly. It’s a remarkable feat, but they’re slow and plodding. Numbers help us quickly grasp the difference between “a lot” and “really quite a lot” better. Version numbers help us understand “I meant that to break” from “I hope all your stuff still works” very quickly. Semantic versioning is a powerful and compact encoding of intent.

We must be thoughtful about what we communicate in software because understanding what a software tool does is hard. Being thoughtful and clear about using well-known methods of communication makes it easier. A little. 🙃 And that little bit of speed in understanding our project is worth that little bit of extra effort it costs us, as software authors.

Because we are thoughtful (caring) people, we use communication tools like semantic versioning. Happy hacking!

It’s easy to think about programming as an exercise of computers, or of languages and design. But at its heart programming is just about people. I bring this up because it’s so easy to lose sight of the fact that people are who you’re really programming for, and I just need a reminder sometimes. Maybe you do too.

Computers Make More Logical Sense than People

I got into programming for the same reason that many other people like me did. By like me, I mean outwardly similar: socially-awkward, middle-class white males growing up in the United States in the 1990s. It was a place to do really cool stuff without having to deal with those messy people and their confusing preferences and agendas. I didn’t really comprehend people easily, but I could understand computers.

And whether you look like me or not, you probably think (like I did then) that programming is about computers. About how we can make them do cool stuff really fast and blow people away. I no longer believe that that is the use or purpose of software.

People Are Using Your Software

Software is written for people. Computers are tools that people use to accomplish goals, nothing more. Computers are completely incidental to the human goals for which software exists. And when we lose touch with those human realities at the edges of computer systems, we do both users and fellow programmers a disservice.

Consider Apple

I have a rather irrational love for Apple (Computer). And whatever you think about Apple, one of the things they have a history of getting (mostly) right is prioritizing the experience of the person using their products. Where many other technology companies are influenced primarily by what the technology enables them to do, or what they have a cohort of their customers fervently screaming for, Apple has a history of placing the individual user’s experience of a computer system before everything.

Apple’s hardly the only company which would claim to aspire to this ideal. But they are the one which most regularly has come close. (Which is also not to say that they never falters in a achieving it.)

In Which I Make An Unfair Generalization about Java

Every terrible and rightly reviled piece of “enterprise” Java software, every computer that works but doesn’t delight, every little website delivered with a “well it’s a little weird, but you have to just take these three unintuitive steps…” is a small but tangible disservice to the notion that people are at the heart of what we make software for.

There are sane and necessary trade-off that must be made in business. Not all of us can afford a team of designers working for a year to design the new Facebook Like button. So we cut corners, we make sacrifices, and people are served a little less well by the resulting product. There’s nothing wrong with making these trade-offs between what the software we’re making is enabling its users to do and what we can sanely make work given existing constraints.

The trade-offs we make in designing the user’s experience of and interface to our software are a great topic to consider. And I’m no expert on how best to thread that needle.

People are the Only Important Interpreters of Software

I’ve written about how you name things while programming, and how you can think about the stories your programs tell. And it’s only on reflection that I see I was driving a broader point: we should write our software not with a focus on making sure that a computer will successfully get it working in the way we want, but so that another person can pick it up and quickly make sense of it.

Part of that effort is enabled outside of your software. Quite simply, we humans need a good amount of education before we can really wrap our heads around some of thoughts that computers allow us to think. And syntaxes required to encode certain ideas and data structures into computers require some familiarity. We’re still probably decades away from sufficient structures of performant abstractions and syntax evolutions of programming languages that we could sanely expect any human off the street to pick up our program and be able to change it.

But those things said, that’s a goal that we too often dismiss entirely when programming: thinking about how we’re communicating the functioning of our dance with the computer (… er … program) to another human. Too frequently in software I’ve written and let lay fallow, or when I pick up something left behind by someone else, I’m forced to spend minutes or hours making sense of what exactly all these obscure names, syntaxes, and flows are meant to be accomplishing. And that’s a mark of code that could be made significantly better.

Here’s What You Should Do…

So in an effort to make your software better, here are some concrete thoughts I have about how to make your programs more decipherable by your follow humans:

Favor explicit and unmistakable names — There are lots of ways you’re probably in the habit of writing poor names. I have a tendency to pick the typing speed of dsc over a longer and clearer download_stream_connection. Some people will do the my_thing dance, as if a future visitor will know what made mine unique. Look for places your names aren’t clear, and change them. (More on this in my article about naming.)

Try to have a clear story for your program, and make sure it tells it — When your program goes through three distinct phases in the transformation of an amorphous blob of files to a useful collection for humans, its entry point should be a function or method that explicitly carries out each of those phases. Each phase can also be laid out clearly and in a place a person would expect to find them. (More on this in my article about stories.)

Take testing as an opportunity to retell your stories — Automated software testing, when its done, is frequently done after the codes been written and the tests are just an afterthought that just make sure we test out our (poor) design. Names like testThatItHasACharacteristic are a symptom of that problem. Well-named and structured tests are a great place to see a software system in action, and they are a great opportunity to communicate the stories of your software. Treat them as such.

Don’t fear the comments — I have a preference for making my names and program flows so clear and explicit that comments feel superfluous. But I also have a bad habit of falling short of that goal for a variety of reasons, and then leaving no comments at all. I still think it’s sane to feel that good code shouldn’t need comments, but if you don’t have time to make it so good your comments are superfluous, you should probably have some comments.

Refactor mercilessly — Whenever you can, take a step back after you get a thing working and make sure you’ve done it well. The TDD teachers love to chant “red-green-refactor”, and with good reason. Whether you’re doing the deliberate practice of TDD or a more haphazard reload-browser-and-click-the-button style, once it’s working your software will benefit markedly if you take a bit of time and make sure that you clean up the ugliness that you created while you were just getting it to work in the first place.

Surely there are loads of other good ideas you should consider when you’re writing good software. But I do hope at least one of those gave you a bit of food for thought about how you can make your software better and more useful for the future human who is likely to be tasked with debugging it or adding new features. After all, until computers can themselves build new features and debug features programmed into them, human will always be the most important factors on either end of your software.

So this is about programming?

Who’s Writing This?

I think the first thing I ever programmed was some Lego, using a language known as Lego Logo. I was about 9 at the time.

I’ve been coding since way back when I had a TI-83 in middle school and I just had to make a video game. What I made is still online, even. It’s a very basic stock trading game in TI-BASIC, called NYSE. It’s features are almost comical, but I made it, and you can still see my cool brand and email address on the page. (Though I lost access to that @yahoo.com email account long ago.)

I’ve been working professionally as a developer for a while. Before I did, I was getting a BA in History and some experience with a less-cushy job. Here in the start of the 21st century, few jobs are better and more reliable than those of us software developers.

My journey back to programming involved a lot of time with WordPress. I love WordPress. I still run a site all about WordPress and being better at developing for it called WPShout. But I also like to think and learn beyond WordPress. I’ve dabbled with a number of languages and frameworks outside of WordPress, including a little Python and a lot of the PHP frameworks Laravel and Symfony. About those latter two topics, I often speak at PHP conferences, like the late great Lone Star PHP.

What do you mean by “thoughtful”?

Great question!

I’m going to do that somewhat-lazy writer trick of referring to someone else’s definitions.

Google’s definition gives as a meaning for thoughtful:

Absorbed in or involving thought

Showing consideration for the needs of other people

Showing careful consideration and attention

Of the three, I intend primarily #2 and #3. In general, the thing that’s exceptionally easy to miss while we write code is that it’s mostly written for other humans. Those human may be people you naturally think of as distinct from you: your enemies, your clients, you co-workers. But they may also be, well, you at different times. (To avoiding going to far into definition #1, we’ll not spill more words over this.)

I believe profoundly that the most important audience for the code we write is not our current self, or the computer, but other people. We should consider their needs and expectations. And when we do, better code naturally results.

Why does Thoughtful Code exist?

Thoughtful Code exists, primarily, because I selfishly love to learn and teach and have been lacking outlets for that lately. While I love WPShout a lot, and will always love to write there, I also need places to share things I learn and things I think which are outside of the WordPress space.

So the intent, here, is that this is broadly “David’s non-WordPress code journal.” Obviously, that’s not a great marketing name. And I do want to be a bit more unified in focused than that over time. But for now, as I wait to really get clear on this, that’s what it is.