Latest News

Just Checking In

Blink your eyes in a pandemic and the next thing you know, three months have passed.

I really felt like I was getting in the groove for awhile, too. Last time I checked in, I wrote about how it’s 2021 and we should all really consider using namespaces in WordPress projects by now, and I was planning out my next set of topics for my series about Rethinking PHP devlopment in WordPress (is it a rule that I link to this in every post I write now?).

In fact, that series is still ongoing, and I’ve got a doozy planned for using objects as a data structure instead of arrays, but I’ve been starting and not being terribly good at finishing a few different side projects, and have also gotten a bit sidetracked by participating in the Dev Book Club, where we’ve been reading and discussing the 2nd edition of the great Martin Fowler book, Refactoring. I’ve owned the 1st edition for a long time and admittedly read about half of it, so it’s great going through it again because all of the examples are written in JavaScript instead of Java and it’s just really hitting me a bit better now that I have more developer experience under my belt than when I first tried readin git.

Since you were last here, too, I refreshed the theme on my site, and I’ve been digging into how to develop board games on the Board Game Arena platform, because even though I can see the light at the end of the tunnel in this pandemic and might be able to eventual play games with my friends in person again at some point this year, it’s still cool to learn new things and I’m hopeful that we’ll all continue to play games online in the meantime, too.

All of which is to say, I just wanted to write a little bit to say hey, encourage you to check out Gravity Forms 2.5 that finally released last week, and let you know that it’s finally springtime in Minnesota. I pumped air in my bike tires and took the briefest of rides a couple of weeks ago, and let me tell you: sheltering in place for like 15 months has really put a damper on my fitness. I’m looking forward to setting some new goals, getting out a little bit more this year, working on some fun developer tools, absorbing as much knowledge as I can about my craft, learning more about the world, giving back to my community, and figuring out just how to be as “normal” as possible again in the coming weeks and months.

In the meantime, hey! I hope you’ve been well.

WordPress and the Curious Case of PHP Namespaces

For part two of my series on Rethinking PHP Development in WordPress, I wanted to write about three significant elements of object oriented programming: classes, interfaces, and namespaces. A big reason I wanted to write about them together is because I think they’re so integral to understanding the way PHP developers who cut their teeth on WordPress learn their craft. However, I felt that might get a bit verbose and keep me from hitting that “Publish” button, so I wanted to focus on just one segment of that topic today: namespaces.

What is a namespace?

Before we can talk about namespaces, let’s focus on a second on symbols. In computer programming, a symbol is simply something that has a human-readable form. A function is a symbol. Class names are symbols. So are variables. We use symbols in programming because they help us understand what we’re trying to make our programs do.

We have control over what we name our symbols, the same way that our parents named us, and we name our own pets, children, and computer hardware (you’ve named your computer, right?).

In real-life, symbols can be complicated. Have you ever worked somewhere that had more than one Chris, Travis, Sam, or (C/K)arl (I do!). We differentiate between first names by passing down our family names, but sometimes, that’s not even enough. In the U.S., we have Social Security Numbers so we can differentiate – on paper, at least – between the thousands of John Smiths and Jane Jacksons in our country.

Last names and identifying numbers are a type of namespace. Basically, a namespace is a way to ensure that something that must be unique in your system is, in fact, unique.

In PHP, we have to ensure that all of our symbols are unique in order to prevent fatal errors. And, in the WordPress community, at least, we’ve established a couple of different ways of attempting to achieve that goal.

Function prefixes

Everyone who has written WordPress code for any length of time has been told time and time again to “prefix their functions.” What does that mean? Well, let’s say I had a function that registered a product post type:

<?php
function register_post_type() {
    register_post_type( 'product', array( /* My options... */ ) );
}
add_action( 'init', 'register_post_type' );

If you’ve been writing PHP code in WordPress for any length of time, hopefully the problem is evident to you right away, because in this particular example, I’m declaring a function name that is named the exact same as the WordPress core function I’m calling within it. This is called a naming collision, and it PHP, it will generate a fatal error, which causes your code not to complete execution.

They way we’ve gotten around this for years in the WordPress ecosystem is two-fold. First, we prefix our function calls to reduce the chance that someone else (usually another plugin) has declared a function with the same name as us. And second, we wrap that function declaration in some code that checks whether that function has already been declared. Here’s another example:

<?php
if ( ! function_exists( 'jmw_register_post_type' ) {
    function jmw_register_post_type() {
        register_post_type( 'product', array( /* My options... */ ) );
    }
    add_action( 'init', 'jmw_register_post_type' );
}

The function_exists method in PHP allows us to check whether someone else has created a function with the same name before we make a declaration for our own. The jmw prefix in this example attempts to further minimize the chance that someone has created another function with the same name.

This approach is perfectly suitable, and has worked reasonably well for many developers over the history of the WordPress project. If you examine the code from the WordPress plugin repository, chances are high that you’ll see this pattern a lot.

Classes as a namespace

Over time, developers began separating their code a bit more, grouping like-functions into separate files, and exploring the use of a class-based system for further namespacing. I think this happened for at least two reasons:

  1. Classes can have the same names as functions, but you can store a lot more information in a class, which means you can make big collections of functions.
  2. WordPress developers, after writing functional code for years, were eager to try their hand at object-oriented programming.

Re-hashing the example from the previous section, we might have something like this:

<?php
class JMW_Custom_Post_Types {
    public static function register_product() {
        register_post_type( 'product', array( /* My options... */ ) );
    }
}
add_action( 'init', array( 'JMW_Custom_Post_Types', 'register_product' );

As with the ! function_exists check in the previous example, we might also wrap the class declaration in a ! class_exists check here, too, just to make sure that our JMW_ prefix is sufficient.

I want to reiterate here: this is fine. The thing about computer programming, particularly in PHP, is that there are a lot of ways to do things, and whatever gets your code shipped and out to the world is more important than which particular approaches you used.

That said, I want to tell you about a third approach, because there is currently not a single* example of it in all of WordPress core.

The namespace keyword

The namespace keyword has been a part of PHP since version 5.3. It avoids the prefixing and class-based approaches ot avoiding symbol collisions in the language. Here’s another example of the function-based approach from earlier, but using the keyword instead:

<?php
namespace JMW;

function register_post_type() {
    \register_post_type( 'product', array( /* My options... */ ) );
}
add_action( 'init', 'JMW\register_post_type' );

Notice anything weird? Well, in this example, I’m prefixing the call to WordPress’s register_post_type function with a backward slash. That’s because I need to tell PHP that I want to use a method from the global namespace, which is to say: I want to use the register_post_type method that didn’t declare a namespace, because WordPress does not currently have any namespace conventions in core.

That said, the code in the above example won’t fail because PHP allows us to have two functions with the same name, so long as we identify distinct namespaces for each of them, just like how two people named Travis can work at the same company (sometimes, you might just give them nicknames, even if they have different last names. Nicknames are another form of namespacing.)!

How is this better?

It may not be evident at first why this makes a difference. Adding a namespace to the top of your file might be more work, but what it really does is frees you up from the way things have always been done. If, for example, you’re a plugin developer and you really like using short, concise function names, you can use them without fear of symbol collision from WordPress core or other plugins. Heck, you can use them without fear of symbol collision from your own code!

Let me demonstrate what I mean with a few more examples:

<?php
namespace JMW\Product_Post_Type;

function register() {
        register_post_type( 'product', array( /* My options... */ ) );
}
add_action( 'init', 'JMW\Product_Post_Type\register' );
<?php
namespace JMW\Faculty_Post_Type;

function register() {
    register_post_type( 'faculty', array( /* My options... * ) );
}
add_action( 'init', 'JMW\Faculty_Post_Type\register' );

The above examples might be two separate functions files name product-post-type.php and faculty-post-type.php, respectively. Although they both contain a register method, you could include them both in your functions.php file without worrying about a symbol collision, because they’re each namespaced differently. This gives developers a lot of flexibility to use short function names without worry that there will be a symbol collision, even within their own codebase.

Summary

These examples only really scratch the surface. In the broader PHP ecosystem, namespaces are frequently used not just to prevent symbol collision, but also to dictate class file organization, such as in the PSR-4 standard recommended by the PHP Framework Interoperability Group. In their configuration, every package (e.g., a WordPress plugin) has both a vendor and a package namespace at the top-level:

<?php
namespace JMichaelWard\MyGreatPlugin;

In PSR-4, the above example would be considered the root namespace, which means any files with that namespace could be located in the root of a directory indicated by the developer. Namespaces with extra levels would map to a sub-directory. Example:

<?php
namespace JMichaelWard\MyGreatPlugin\PostType;

The PostType sub-namespace would suggest that I have a directory named PostType where all of my classes are kept. This approach helps simply class autoloading, which is perhaps another post altogether.

Needless to say, namespacing your function and class files in WordPress, even if core isn’t yet doing it, can provide some great benefits. It allows you to confidently use shorter method names (particularly when paired with the <vendor>/<packagename> approach I just described). It allows you to group code into directories when paired with class autoloading. And, least importantly, but important nonetheless: it allows you to use a language feature that has been available in PHP for nearly 12 years.

I hope this post inspires you to experiment with PHP namespacing, and sets you on your journey for further exploration of the server-side language of WordPress.

Footnotes

* WordPress core contains the PHPMailer library, which in fact, uses the native PHP namespace keyword.

How a Conversation About Filterable Autoloader Paths Pleasantly Derailed My Sunday Afternoon

My good friend Gary Kovar posed a really interesting question on Twitter yesterday:

This led to some conversation both on Twitter and separately on Slack, and I began to realize that this dovetails nicely into that series about re-envisioning PHP development for WordPress I’ve been alluding to for months. Consider this post the first in that series.

Dependency Management in WordPress

Here is a real-life problem I encountered on a client project while I was working in agency: the client was using one plugin to save their media uploads to Amazon S3, and they wanted another custom plugin developed that, when creating a new site in WordPress multisite, a hook would be triggered that creates a new bucket on S3 for that site’s media.

The client had one of the most sophisticated build, testing, and deployment setups for WordPress I have encountered yet in my career. They were using Composer for installing their WordPress plugins, and so naturally, when I began building this custom plugin, I created a composer.json file and required the latest version of the Amazon SDK as a dependency, then got to work on building out the functionality to automatically create the buckets.

Everything was going great. That was, at least, until I got to the point where I’d actually attempted to install my plugin alongside all of the other plugins in their multisite installation. It turned out that the plugin that was uploading media to Amazon was using an older version of the SDK, whereas I had coded my plugin against a new version. When their build processes attempted to pull my plugin into the site alongside the other one, everything appeared to work correctly because the other plugin was shipping the Amazon library alongside its code, instead of downloading it using Composer.

If you’re not familiar with Composer, typically what happens when two libraries (or in this case, WordPress plugins) require incompatible versions of the same library, Composer will exit the install process and inform you of the incompatibility. In this case, because the other plugin wasn’t using Composer, I wasn’t aware of the incompatibility.

There’s an additional wrinkle here, too, because in WordPress, the core application does not have a process to check for and resolve all of the dependencies within a plugin or theme. Thus, if one plugin is installing a library via Composer, and another one ships it with the plugin, it’s possible that whichever plugin loads first will load the dependency. In a well-coded plugin, developers guard against loading a library again if it’s already been loaded to avoid throwing errors in PHP, and well written libraries (such as Amazon’s) can avoid throwing errors if there’s good compatibility in their APIs across versions.

This was the case for this particular project. Ultimately, I came to discover that my code wasn’t working correctly because the other plugin’s library was loading first. We wound up forking that library, checking out its beta version (which used the newer version of the SDK and was nearly released), and went on our merry way.

Why is this a WordPress problem?

The short answer is that it’s complicated. Nearly 40% of the top 10 million websites on the internet today are powered by WordPress. Not every WordPress site is maintained by a developer – in many cases, they’re maintained by non-technical people for whom WordPress was an intuitive solution to help them get their vision online. Those folks don’t care about Composer or PHP dependency resolution or namespace collisions. They (rightfully) just want things to work.

For the rest of us, this means we try to come up with innovative solutions to be able to use the tools that make our jobs easier. Because WordPress core doesn’t have a mechanism for resolving a plugin and theme’s dependencies before it loads them, as plugin developers who work in sophisticated ecosystems like that of my former client, we have to rely on alternative solutions like Mozart or Imposter to package our vendor directory with our project and prefix its class namespaces with our own to avoid naming collisions in PHP.

There has to be a better way, but it’s clear that whatever the solution might be, it’s neither easy nor obvious, or as a community, we may have resolved it by now.

Let’s Talk About Extensibility

So, back to Gary’s question and the conversation that followed, which still pertains to workarounds for the dependency management issues in WordPress, but also includes some nuances around class inheritance, interfaces, and incorporating developer guardrails into open-source projects that I find particularly compelling.

In our conversation, we were discussing class property and method visibility in PHP, and Gary shared with me this filter in the MySQL class of SquareOne, an open-source framework developed by the fine folks at Modern Tribe. Though not about autoloading, I’m hoping the correlation here is clear. Let’s look at this snippet (condensed from the link above):

class MySQL implements Backend {
	const DB_TABLE = 'queue';

	private $table_name;

	public function __construct() {
		global $wpdb;

		$table_name = $wpdb->base_prefix . self::DB_TABLE;

		/**
		 * Filter the table name used for queues on this backend.
		 *
		 * @param string $table_name Table name with $wpdb->prefix added
		 */
		$table_name = apply_filters( 'tribe/queues/mysql/table_name', $table_name );

		$this->table_name = $table_name;
	}

There are two important bits in this example:

  1. The private keyword on the $table_name variable
  2. The call to apply_filters, which provides developers with the ability to override the default value of $table_name

Historically, actions and filters in WordPress have been offered as an easy way to override the default behavior of the code that plugin authors write. Like the end users of WordPress itself, developers who work with the platform have a broad range of experience – especially when it comes to object-oriented programming – and these hooks offer an arguably simpler way of overriding the original programmer’s logic.

A neat thing about PHP, however, is that it also accommodates for changes. Consider this alternative to the snippet above:

class MySQL implements Backend {
    const DB_TABLE = 'queue';

    private $table_name;

    public function __construct() {
        global $wpdb;

        $this->table_name = $wpdb->prefix . self::DB_TABLE;
}

But Jeremy… you just took out the filter.

You got me. :)

In this case, MySQL is instantiated somewhere, and it implements an interface, which means it has a whole set of methods that can be called on it. Instead of filtering just the table name, Modern Tribe could consider allowing for modification of the entire class by filtering the places where it is instantiated, and requiring an interface in that callback.

Here’s a contrived example. Let’s say I’m a developer who wants to extend the MySQL class of SquareOne in my own plugin. Let’s assume, for now, that I only want to override the value of the table name. I could create a class that looks like this:

use Tribe\Libs\Queues_Mysql\Backends\MySQL;

class MyPersonalMySQL extends MySQL {
    protected $table_name;

    public function __construct() {
        global $wpdb;

        parent::__construct();

        $this->table_name = $wpdb->prefix . 'my_personal_queue';
    }
}

Notably, PHP allows you to weaken the access level of class properties and methods for extending classes. Thus, it’s okay here to change the visibility of $table_name from private in the parent class to protected here. Additionally, because I only want to change the table name here, my class can inherit all of the other default behavior from the MySQL class. That said, this does complicate both my approach and Modern Tribe’s. In their case, if they want me to continue to be able to override the class, they have to add a filter to wherever that object is being instantiated. It’d look something like:

$mysql = apply_filters( 'tribe/queues/mysql', new MySQL() );

And I, of course, would need to add the filter myself, AND extend the class, when I could have just filtered the table name in the first place:

add_filter( 'tribe/queues/mysql', new MyPersonalMySQL() );

Versus:

global $wpdb;

add_filter( 'tribe/queues/mysql/table_name', $wpdb->prefix . 'my_personal_queue' );

If extensibility is the goal, then there’s an argument to be made that we as open-source developers could be creating more filters in order to accommodate both procedural and object-oriented developers alike. However, in my mind, the argument for making codebases easier to understand and to raise the bar for WordPress developers alike lies in interfaces.

A Case for Interfaces

In his tweet, Gary asked if there were any open-source examples where the path to a Composer class autoloader is filterable. Using the previous examples as a guide, let’s examine what plugin instantiation might look like from the perspective of a WordPress developer who wants to modify plugins with their own autoloaders. Consider the following plugin:

/**
 * Plugin Name: Incredible Plugin
 * Description: Does something incredible!
 */

namespace JMichaelWard\IncrediblePlugin;

require_once __DIR__ . '/src/IncrediblePlugin.php';

function init( Autoloadable $plugin ) {
    $plugin->init();
    
    return $plugin;
}

add_action( 'plugins_loaded', function() {
    $plugin = apply_filters( 'init_incredible_plugin', new IncrediblePlugin( __FILE__ ) );
    init( $plugin );
} );

The plugin itself might look like this:

namespace JMichaelWard\IncrediblePlugin;

class IncrediblePlugin implements Autoloadable {
    private $plugin_file;

    public function __construct( $plugin_file ) {
        $this->plugin_file = $plugin_file; 
    }

    public function init() {
        $this->autoload();
    }

    public function autoload() {
        require_once plugin_dir_path( $this->plugin_file ) . '/vendor/autoload.php';
    }
}

The beauty here is that this code accomplishes a couple of things.

First, the init method in the main plugin file uses a type-hint against the Autoloadable interface. In this scenario, this means that another plugin author who needs to modify this plugin’s primary class in some fashion could do so simply by extending the IncrediblePlugin class (since it already implements Autoloadable), or that – if somehow needed – they could pass in an entirely new plugin object that meets the requirements of the behaviors for the rest of the plugin, so long as it also extends Autoloadable. If Gary simply didn’t want the autoloader to run, he could override the method and simply have his new class do nothing.

Second, what this achieves – and this is notable because no concept like it exists in WordPress core today – is that because the init method in the main plugin file uses a type-hint, if another developer extended it and forgot to implement that interface, PHP will throw a fatal error and warn that developer that they did not meet the requirements to initialize the plugin.

Believe it or not, errors are good. Great, even. Or, I should clarify, that’s the case when they are part of the development process. Errors provide context for what you haven’t done correctly, and through the process of creating interfaces for your classes, you are establishing a contract for what is required to alter that application, whether you’re the one doing the alteration, or if you’ve created a developer API intended for others to extend.

Conclusion

In this post, I covered the following topics:

  • Challenges associated with dependency management in WordPress
  • Proposed approaches for adopting broader filter usage
  • Weakening restrictive property and method visibility during class extension
  • A case for using PHP interfaces

I expect that a few of these topics will surface again in future editions of this series. For instance, the benefits of interface usage in software development are a significant part of the first 5 principles of S.O.L.I.D. Type-hints, too, help ensure that the values we pass into functions throughout our codebases are of the type we expect, and using them can really help us spot errors during the course of developing new features.

I’ll close this inaugural post in the Rethinking PHP Development in WordPress series by thanking Gary once again for the discussion that helped get my wheels turning. As I seek one or more mentors to increase my own knowledge in 2021, I’m reminded that our friends, colleagues, and peers are often the best mentors of all.

Seeking Mentorship

I’ll keep this short and sweet: one of my professional goals for 2021 is to establish formalized mentorships with one or more of my peers in the tech community.

Through the course of my 8-year development career, I have aimed to increase my knowledge and improve my technical skills in a variety of ways. Like others, I’ve read numerous books to learn about new languages, design patterns, tools, and approaches to engineering. I’ve attended conferences and local meetups to build relationships with others in my field, and of course, to attend presentations and discover what additional tools I can add to my skill set.

In July of last year, I joined the product team at Rocketgenius. There, I work on the add-ons crew where I am responsible for developing and maintaining our collection of WordPress plugins that further extend the functionality of the Gravity Forms plugin.

Moving from the agency space into product has long been one of my career goals, because I think it provides me with the opportunity to apply a lot of the “ideal engineering” scenarios that seem prevalent in all that book-learning: test-driven development, continuous delivery and deployment, domain-driven design, agile development, etc. I’ve had exposure to certain aspects of these concepts in my agency work thanks to working with large corporations that adopt them, but because those projects are so fluid, I’ve typically used what had already been established by our clients instead of working to build something of my own.

Needless to say, I recognize that there are shortcomings in my current skill set that I can work to improve upon in 2021, and I think it would be helpful for me to collaborate with one or more folks over the course of the year. In my mind, this collaboration would entail semi-regular (monthly, perhaps?) calls to discuss challenges working in the technical field, and to share resources and ideas around how to grow one’s professional skill set.

Some initial topics that come to mind:

  • Modernizing legacy codebases (in particular, those which can be extended by end users)
  • Containerization
  • Developing and maintaining custom build processes
  • Test-driven development
  • Domain-driven design
  • Engaging with open-source communities
  • Avoiding burnout

If you have expertise in any of these areas and would be interested forming a mentor/mentee relationship, and especially (but not necessarily limited to) if we already know one another, then please get in touch. I think there’s likely a lot we can learn from one another.

2020: The Lost Year

On March 6th of this year, I posted about leaving my role at WebDevStudios is pursuit of new opportunities. It might as well have been a decade ago.

That weekend, I celebrated “funemployment” by hanging out with some of my closest friends at The Lab in St. Paul, a conceptual taproom of sorts where brewers and beverage makers can try out new recipes in small batches that they can sell to those with adventurous palates. I didn’t have a new role lined up just yet, but I was studying and working through online tutorials to teach myself Python. At the time, I was in the middle of an interviewing process with a company where I’d have the opportunity to branch out beyond both WordPress and agency and finally get to experience the world of product development, all while becoming acquainted with a programming language that was both new and yet somehow familiar to me.

Last winter, lots of tech folks in the Twin Cities had started co-working occasionally at BlackStack Brewing, in large part because of 1) the ample taproom space, and 2) BlackStack’s change in business hours and structure; while still a brewery, they’d also begun marketing themselves as a coffeehouse by day. With fast wifi, a low-key environment, and a staff that was friendly to folks settling in and writing code throughout the day, I made plans for it to be the place where I’d spend my first day with some downtime to write some code for fun.

Much to my surprise, when I showed up to BlackStack that following Monday, I ran into some friends and former colleagues alike. The pandemic hadn’t completely settled here in the U.S., but the news was becoming increasingly scary by the day. Folks were showing up throughout the day, some (such as myself) already very mindful about not shaking hands, but of course, in early March, nobody was wearing masks yet, and a group of us went out for lunch together at The Naughty Greek, a fast casual Mediterranean restaurant just up the street.

Those are probably my last tangible, positive memories of The Before Times, though of course they were already tainted with my experience of working with an epidemiologist for almost 4 years earlier in my career and the worry about what was to come.

Later that week, I hosted my last in-person weekly board game night, something I’d organized for a full four years prior. My friends Nick, Bela, Austyn, and I played Great Western Trail, a game about herding cattle from Texas to Kansas City, where you later ship them off by train. Two days later, on Saturday the 14th, my friend Will was the last invited guest to our home for the entirety of this year. He, my partner Abby, and I played the cooperative game Horrified, which I’d purchased in South Dakota just two months prior when Abby and I visited her folks, oblivious to the fact that a global pandemic was looming.

Of course, we all know the rest. And it’s hardly been just the pandemic that’s resulted in this year being, perhaps inarguably, the most terrible of our lifetimes.

Being Thankful

Employment

The Python job that I was interviewing for in March became suddenly unavailable as a result of the economic downturn from the pandemic. In May, I was fortunate enough to land a position working at a local startup, but it quickly became evident in the subsequent weeks that the culture and development stack wasn’t a right fit for me. I turned in my resignation at the end of June, and starting fresh in my search. That very day, I heard from Steve Henty about an engineering position on the product team at Rocketgenius. After a couple weeks of interviewing with him and various members of the team, and learning more about the company’s mission and vision, I decided that staying in the WordPress space but making the switch over to product was going to be the right fit for me.

Man, am I ever glad I did.

I think I have a hard time articulating sometimes what it is I’m looking for out of my career, or even what I want from an employer. Every company that I’ve worked for in the WordPress agency space has done something smashingly well. Some have given me the opportunity to learn and grow, either by paying for memberships to online tutorial services, or helping sponsor travel to attend or speak at a conference. Some have recognized the benefits and challenges associated with remote work, and have taken great strides to do what they can to make their culture open and inclusive. Some have recognized holidays as official company holidays where others haven’t. Some have granted autonomy and trust to you, as an employee, to make decisions and take actions in the interest of the company, without the need for a special sign-off – making the pitch is usually enough.

I don’t know how they do it, but I’ve been with Rocketgenius now for 5 1/2 months, and somehow they do it all, and I’ve worked at enough places at this point in my career to know not to take this for granted. Every day, I am astounded by the thoughtfulness of my colleagues and leadership, the kind ways with which we interact, and the hard work and care that everyone puts into our products. We plan and communicate and check in with one another in ways that I’ve only seen glimpses of in past roles, and it’s made going to work each day something to look forward to; a welcome distraction from the madness of everything else.

Friendship

Since that festive gathering in the beginning of March, I’ve managed to see my friends a handful of times this year, at extremely social-distanced outings in large backyards, city parks, and the front lawn of the Minnesota State Capitol. I’m grateful for those moments of simply reconnecting with one another, of catching up, of celebrating each other’s wins, and of hoping that we can all hug one another again when we finally get a calendar with a new number on it.

My friends have still managed to make this year special through trivia nights, board game tournaments, scotch nights, meetups, impromptu online gatherings, and the occasional telephone call (hi Josie!).

Love

Above all else, I don’t know what I would have done this year if not for Abby. We celebrated our 12th anniversary at the end of October, and we’ve largely spent the year doing a handful of activities: taking walks around Lake Phalen largely as an excuse to run our car, playing a board game I can talk her into playing, watching a movie she can talk me into watching, finding occasions to use the oven instead of the microwave, and sending each other cute stories we find and as many animal-related pictures and gifs as possible. She supported me by remaining optimstic about my career change, even after it quickly got scarier than I’d expected, and I think what I’ll most cherish about this year is her dedication to getting me out of my comfort zone and encouraging me to take a walk in the neighborhood or go sit in the park for awhile. We started the year playing trivia at our local brewery nearly every Wednesday, and pandemic or not, I’m looking forward to warmer summer nights when we can go hang out in the park some more: the sun for her, the shade for me.

Looking Ahead

There’s a whole lot of stuff that’s going to be the same when we wake up tomorrow morning as it was through most of this year. Still, I think there is reason for optimism and hope, and for the new year, I’m planning on a small set of goals to keep me focused and motivated:

  • First and foremost, giving more than I did last year. I wrote a bit about some of my charitable giving over the summer. I’ve given more since then, both via official and unofficial channels, but I recognize that there’s more that I can do and now that my situation has thankfully stabilized a bit, I’m seeking opportunities to do more of that. One thing I’m considering is a monthly donation to Second Harvest Heartland beginning in January.
  • Reading more. A lot more. I’ve fallen out of the habit, and things were already sufficiently dire before 2020. I only managed to finish three books this year, and two of them I’d started in 2019: We Were Eight Years in Power: An American Tragedy by Ta-Nehisi Coates, Someone Who Will Love You in All Your Damaged Glory by Raphael Bob-Waksberg, and The Answer Is… Reflections on My Life by Alex Trebek. I’m not setting a hard goal, but more non-fiction, non-memoir I think is a good place to start. That said, I’m still trying to get through Exploded View by Sam McPheeters (made all the more difficult since it’s a police story) and The First Bad Man by Miranda July.
  • Writing more. Amazingly, this is my 16th blog post this year! I even got my first-ever reader e-mail the other day, related to my post about Xdebug 3. I’m hoping to write more about technical topics, and in particular, I want to write more about the process of learning. I’ve been less motivated to spend additional time in front of a screen that isn’t something mindless like video games or engaging like playing a board game with my friends, and I feel that my tech exploration has suffered as a result. I’m hopeful that we might start to see things normalize at some point this year, and that I’ll regain that excitement to learn and share what I’m learning more.

That last bullet sorta dovetails into some professional goals I have, too. In a particular, I’m working goals at work to open-source some tools, and a plan for sharing/presenting information about those efforts in some fashion. More on that at another date, I suppose.

To sum things up: so long, 2020. You were terrible, but I’m thankful for the good stuff.