Thoughts on teaching object-oriented programming with WordPress and over-engineering

This site has grown a lot in the last year or so. We’ve spent a lot of time going over object-oriented solutions to WordPress problems. So much so that, we have a small library’s worth of material that you can refer to.

With any type of growth, criticism will arise. This is a good thing. I’m a big proponent of “Strong opinions, weakly held“. But this can’t happen without discussion and debate. In the long run, I always feel it leads to a better outcome. (Well, that’s as long you don’t get stuck just debating!)

Recently, there was a debate on the nature of the solutions that you’ll see on this site. They’re over-engineered. I think this is a valid criticism and I wanted to share some of my thoughts on the whole thing.

My teaching thesis

We can’t talk about over-engineering without first discussing my current teaching thesis. The thesis attempts to answer these two questions:

  1. Why is it hard to teach object-oriented programming to WordPress developers?
  2. Why have so many tried and failed (in my opinion) at it?

This could have been a post by itself. That said, I don’t think it makes sense to explain why we’re using over-engineering without going over it first. So let’s do that.

You don’t need object-oriented programming

This is the most important point for me to remember as the teacher. You don’t need object-oriented programming to solve WordPress problems. You already have the WordPress way of doing things (also called procedural programming).

This means that you cannot arrive and say, “OOP is better! Just do it!” It flat out doesn’t work. The moment your student gets stuck, they’ll just go back to what worked for them before they started.

So, because of this, everything is on you as the teacher. You have to prove beyond any doubt that object-oriented programming is useful. And to do that, you have to make it as easy and simple for them to understand as possible.

Object-oriented programming and Lego bricks

A good way to make things easy to understand is to have a good analogy. The best one I’ve found is to describe classes as Lego bricks. A lot of us have played (or still play!) with them. For me, the best part has always been to use the bricks to build something new.

That’s also how object-oriented programming works. You piece together classes to build your solution. In normal circumstances, the language and framework that you use act as the Lego set. They give you a bunch of classes which you then use to build your solution.

The problem with WordPress is that it doesn’t offer us many Lego bricks that we can use. Yes, WordPress core has classes, but they aren’t that well designed. We can’t piece them together to build something else. (And that’s the essence of object-oriented programming.)

Building our own bricks

As a teacher, this leaves you with one solution (at least that I can see). You need to build all the bricks that WordPress doesn’t have. And that’s what we’re trying to do with a lot of the object-oriented programming articles on this site.

Each article presents a problem that you might encounter in WordPress. It then solves the problem by designing one or more classes. These classes then become new bricks in our Lego set.

This grows our Lego set over time. And one day we’ll have enough bricks to build something like an object-oriented plugin. But doing things this way has consequences. One of them is over-engineering.

Teaching through abstractions

The main complaint is that we’re adding unnecessary abstractions on top of WordPress. Why create a routing system when there’s the rewrite API? Why create an event management system when you can just use the plugin API?

Because without them, we don’t have any Lego bricks to build anything with. This makes life so much harder for the students. And, like we saw earlier, there’s nothing to compel them to stick around when things get tough. They can just go back to what they were doing before.

This leaves us with little choice, but to create an abstraction layer on top of WordPress. Yes, it’s an unnecessary layer from an architectural standpoint. But it’s a necessary one from a teaching standpoint.

We’re giving students a Lego set to work with. If WordPress had one that we could use, we’d use that one. But it doesn’t so we built one by creating an unnecessary abstraction layer.

Isn’t this going to teach over-engineering?

This is a good follow-up concern. It’s possible that teaching object-oriented programming this way will lead to that outcome. You’ll have learned how to use it but became an architecture astronaut in the process.

Of course, that’s not the goal of doing this. That’s why each object-oriented design article solves a specific problem. The student is free to determine whether they have the problem or not. If they don’t, they shouldn’t solve a problem that they don’t have.

But all this hinges on faith. Faith that the student will be smart enough to make that decision. And, if they make the wrong decision, that it’s their learning experience to make.

That seems like a fair tradeoff for the opportunity to grow as a developer. Especially since we don’t know how it’ll play out in practice. The alternative is to just be patient and wait until WordPress gives us the teaching tools that we need. Should we do that?

No, we shouldn’t. Being patient just means we’re making it someone else’s problem. And, to be fair to WordPress, it’s not its problem to solve either. So let’s not wait and, instead, have faith that things will work out fine.

Why is this (maybe) working?

So here we are. We now have an over-engineered teaching tool. But one that seems to be working (from what I can see anyhow). Why is that? It’s because we tried to build a Lego set that was both easy and simple.

Easy vs Simple

Now, you should pay close attention to the use of “easy” and “simple” here. They’re not interchangeable. So what’s the difference between the two?

Well, “simple” describes the amount of complexity in our code. Meanwhile, “easy” is about the amount of effort that you have to put in. We don’t measure them the same way either.

The first one is objective. For example, you can calculate the cyclomatic complexity of a piece of code. As long as the code doesn’t change, this value will never change.

The other is relative. It depends on your skill level and your current knowledge of the code that you’re using. And if something is easy for me, it doesn’t mean that it’s easy for you. (Also known as this meme.) Or it could have been hard for you before, but not anymore.

WordPress as an example

Let’s use WordPress as an example. The WordPress community has done a tremendous job making it as easy as possible to learn. You have access to countless resources regardless of your skill level. It’s one of the main reasons why WordPress is such a popular platform today.

But this doesn’t mean that WordPress code is simple. In fact, WordPress is one of the most complex PHP projects out there. Now, this isn’t meant as a reproach. Any legacy application as old as WordPress accumulates technical debt.

That said, the goal here is to highlight this distinction between easy and simple. WordPress can be easy if you’ve been using it for a while. (Or it could also still be hard!) But the WordPress codebase will never be simple. (Well, unless there’s a rewrite, but let’s not get into that.)

Making it easy and simple

So getting back to this over-engineered teaching tool. How can we try to make it easy and simple? And why do we need over-engineering to do it?

Teaching makes things easier

Well, like we saw earlier, easy is relative. There’s no way to guarantee that our Lego set will be easy to use for everyone. But we can stack the odds in our favour by sharing as much knowledge as possible like WordPress does. That means a lot of teaching.

And there are a lot of things to teach around this Lego set. You can’t stop at the Lego set either. You have to look beyond it too. Using the Lego set is just one part of your student’s larger journey.

Putting yourself in your student’s shoes

So you have to put yourself in their shoes and look at where they started that journey. Often their starting point is a place where they only did procedural programming with WordPress. That means that you can’t give them an object-oriented Lego set and expect them to be able to use it.

When you do that, you’re just taking a shortcut. And you assume that they have the knowledge and familiarity to see the shortcut you took. In reality, you’re just trying to make things easier for yourself. But that’s wrong because, again, it’s not because it’s easy for you that it is for them. What you end up doing is making things harder for them by obscuring their path.

Instead, you should strive to light up as much of their path as possible. That means taking a step back and teaching everything around the Lego set. You have to not only teach object-oriented concepts but the relevant inner workings of WordPress as well. For example, if we’re going to create an abstraction over a WordPress API, we should know how that API works too.

Abstractions for simplicity

And this brings us to our over-engineered abstractions. Why do we need them? What purpose do they serve? Are they only there to add unnecessary architecture?

No, I don’t think so. The role of the abstractions is to make the student’s object-oriented code simpler. They’re able to do that because they abstract away WordPress.

Now, let’s be clear. They’re not trying to abstract (or hide) the complexities of WordPress. This is the primary cause of leaky abstractions. And those bring complexities of their own.

It also doesn’t mean that our abstractions don’t make things more complex. They do to an extent (any abstraction does). But it’s not that significant because they’re not trying to hide WordPress’ complexity.

Distancing ourselves from WordPress

All that they’re trying to do is to distance us from WordPress. After all, your student is trying to learn object-oriented programming. They’re not trying to learn how WordPress works.

WordPress is just the teaching backdrop. We’re using it in our code, but it’s not an important part of it. This is what helps keep our object-oriented code simple.

And keeping that code simple is crucial. You want your student to be able to follow what the object-oriented code is doing. That’s how they’ll learn.

But, if you’re busy trying to stay close to WordPress, you’re going to make things complex. Which will result in code that’s confusing and hard to read. In the end, you’ll just complicate things for your students. You’ll have given them an excuse to go back to what they were doing before.

Over-engineering with purpose

So those are my current thoughts on the matter. The goal here wasn’t to convince you to embrace over-engineering in practice. Or that it’s somehow better than if you didn’t over-engineer solutions. (It’s not.) No, the goal was to show intent behind its use in a teaching context.

Teaching object-oriented programming with WordPress is challenging endeavour. You can’t approach it as if you were designing a library or a framework. Both impose their own set of requirements which don’t always overlap.

These different requirements might require that we build extra abstractions in our code. These might seem like superfluous architecture in the context of a library or framework. But I think they are necessary for teaching purposes and that’s why they exist.