For the past couple of weeks, I (along with others in the comments) have been talking about things such as testing, namespaces, and more. When building well-architected, testable, and scalable software, these are all relevant topics.

But they only scratch the surface of some of the many ways in which we can manage project architecture.

Developers have been experimenting (and using) WordPress with a variety of different tooling such as different web servers (like IIS – good luck :) and with different database servers.

And when it comes to dealing with various types of third-party dependencies like database servers, creating a proper architecture is key to making sure your code is portable between environments and for other reasons, such as testing.

The Clean Architecture

An article from 2012 from 8th Light talks a bit about what’s called The Clean Architecture. Though it’s a few years old, I found that many of the principles it outlines can be of use in the work we do as it relates to WordPress.

The Clean Architecture

The rules of The Clean Architecture are straightforward and make sense when talking about writing code in a platform-agnostic manner.

From the blog:

  1. Independent of Frameworks. The architecture does not depend on the existence of some library of feature laden software. This allows you to use such frameworks as tools, rather than having to cram your system into their limited constraints.
  2. Testable. The business rules can be tested without the UI, Database, Web Server, or any other external element.
  3. Independent of UI. The UI can change easily, without changing the rest of the system. A Web UI could be replaced with a console UI, for example, without changing the business rules.
  4. Independent of Database. You can swap out Oracle or SQL Server, for Mongo, BigTable, CouchDB, or something else. Your business rules are not bound to the database.
  5. Independent of any external agency. In fact, your business rules simply don’t know anything at all about the outside world.

And there are plenty of other things the article covers that are worth reading if for no other reason than to learn alternative ways to organize object-oriented software. Before talking about how this is applicable to WordPress, the article concludes with this statement:

By separating the software into layers, and conforming to The Dependency Rule, you will create a system that is intrinsically testable, with all the benefits that implies.

And this is about as succinct as a statement possible to represent the rules outlined above. Still, this raises the question as to how we might look at this in our work related to WordPress.

Applying This to WordPress

When I talk about these types of principles, I’m usually referring to the work that goes into creating plugins. Themes are completely different types of projects, and I tend to treat core as a foundational layer on which everything else lives.

With that said, here’s a short list as to how I think about the above principles when building WordPress-specific projects.

Independent of Frameworks

When working with WordPress, it’s common to think of frameworks as front-end related libraries for styling our user interface.

But there are a plethora of frameworks that aim to make working with certain things like the Settings API a bit easier. Though I’m not particularly a fan of them, they do exist, and other developers do use them.

When following The Clean Architecture, code should be written such that it does not depend on, or require, the use of a third-party library. Whether or not you use them doesn’t matter when architecting your plugin.

They should not need to be loaded in order to use or test your project. If they are absolutely necessary for a type of testing, then they should already be present on the system. But I’d argue this defeats the purpose of making sure your business logic and related logic are independent of the rest of the application.

Testable

Though this tends to be common in a variety of other testing methodologies, it rings true here as well. As the article states:

The business rules can be tested without the UI, Database, Web Server, or any other external element.

The primary takeaway that we should have is that the server-side code of our plugin should not require any type of templates, partials, or views to function.

Everything should be able to be executed by calls to classes and method calls. In production, the views or templates would trigger this very same logic.

Independent of the UI

In a plugin that includes a UI such as a settings page, front-end functionality, or both, the underlying code should be able to be adjusted so that it doesn’t break the UI.

This means that we’re able to interact with the system and drive it using automated tests or other external code without requiring a web browser or any type of visual element to trigger functionality.

If you do require this, then the direction of your dependencies is bidirectional, and you’re ultimately violating one of the primary principles of The Clean Architecture.

Independent of the Database

Though this isn’t something as common in WordPress since WordPress is effectively the layer that communicates with the database (and our code interacts with WordPress), it’s still worth mentioning that our code should not require the use of a particular database server.

That is, if it’s going to read and write information from a database (regardless of the type), it should be able to do so regardless of how we store the information.

For us, this usually stops at using the Options API or a Metadata API since that’s what WordPress provides as it relates to talking to the database.

Independent of Any External Agency

This sounds a bit fancier or complex than necessary. An “external agency” is anything that exists in “the outside world” or as a third-party library or component that may be part of the overall system.

In the world of WordPress, this may include other plugins that our plugin or project may run alongside. We shouldn’t be concerned with them (let alone conflict with them), nor should our project require them. At this in this particular architecture (there are strategies for dealing with this, but that’s another post).

In short, think of the project that follows this architecture is being self-contained being aware only of itself and various layers knowing only of dependencies facing in one direction.

Architectures for WordPress Projects

There are plenty of other architectures that can be applied to WordPress projects and this is one of many. There are also a variety of tools or patterns that we can employ to help enforce this architecture.

Regardless, the purpose for sharing this, discussing it, and bringing it up is so that we can think more strategically about how we’re organizing the components of our work.

Sometimes, I think plugins are often that of as simple, small extensions that add functionality to WordPress. This is certainly one way in which they work.

But other plugins can be far more advanced and complicated. In those situations, it helps to have some rules and guiding principles to help us organize our work to make sure it remains scalable, testable, and won’t ultimately turn into a big ball of mud.

Category:
Articles
Tags:
,

Join the conversation! 5 Comments

  1. This reminds me a lot of the ideas behind domain-driven design. I find that I also code better too when I try to encapsulate business logic outside the framework or application layer. I like that I can view the business logic independent of whatever I need to do to make it work with the application layer.

    In practice, this is hard to do with WordPress. Mostly because I still haven’t found a good way to dissociate entities from WordPress posts objects/arrays in a clean way. You’d need a mapping layer which is a lot of architecting to solve that specific problem.

    •  This reminds me a lot of the ideas behind domain-driven design

      Agreed. There are a lot of principles in that particular approach that I like. I don’t use them as much as I used to, but one of the biggest takeaways for me was using the “domain language” and applying that throughout the code.

      In WordPress, we sometimes have to couple our code so tightly that it can be difficult, but it’s not something that’s impossible.

       I like that I can view the business logic independent of whatever I need to do to make it work with the application layer.

      Right — it also makes it so much easier to unit test without needing to load up an entire foundation or core application to bring along with it. I mean, sometimes that’s obviously necessary, but if you’re testing the business rules then you shouldn’t need anything else but a framework to run the tests and the classes encapsulating the data.

       In practice, this is hard to do with WordPress. Mostly because I still haven’t found a good way to dissociate entities from WordPress posts objects/arrays in a clean way. You’d need a mapping layer which is a lot of architecting to solve that specific problem.

      Same. I tend to write private helper methods, subclasses, and so on, but that really only goes so far. It doesn’t really de-couple anything so much as help to reduce the amount of code in a given class.

      Such is the nature of the platform for now.

  2. Hey Tom,

    The article you’ve posted is a brilliant piece of writing, distilling concepts from more specific frameworks like the “Hexagonal Architecture” into their fundamental principles and building blocks. And it all comes down to “Dependency Management”.

    However, I find that you’re approaching this from the wrong direction (from the “WordPress Way”). I already wrote about how I think WordPress is “merely one of the dependencies” (https://www.alainschlesser.com/is-wordpress-a-dependency/). So, if you really try to make use of these concepts, your observations should not start with “In the world of WordPress, …”. I think you’ve already missed the main point of the article, then. WordPress is one of the dependencies of your infrastructure code. It should be irrelevant when planning your business logic.

    So, provided that we’re dealing with a project large and complex enough to even justify such an approach, you would start by building a business model that reflects your business domain. All of your data stored in conceptual objects, interacting with other conceptual objects to define the logic. (without persistence, without UI/IO).

    As an example, you would have a conceptual UserRepository that lets you manipulate User objects. You shouldn’t need to consider how these are persisted, or how they are optimized for server requirements.

    These conceptual objects can then be used through concrete implementations. You might have a WPDBUserRepository that extends the conceptual UserRepository and that directly manipulates them through WP functions. Your logic code should not care whatever version of UserRepository you are using, it will just make use of whatever object fits the correct interface.

    It is clear that this will force you to create abstractions of existing WP functionality first. But that is a very straight-forward first requirement for such an architecture: Want to decouple from WP? Don’t directly use WP functionality!

    As already discussed in https://tommcfarlin.com/namespaces-in-wordpress/#comment-888291 , I split up any non-trivial functionality into general PHP code, and an additional WP integration plugin to integrate it into the WP framework. I’ve already abstracted away a lot of WordPress functionality with my custom packages, and I’m currently working on a wp-model package that is basically an abstract Doctrine ORM representation of the WP data model, that can then be implemented through either WPDB, or Doctrine DBAL. This lets me use whatever code I write against that data model with or without running WordPress in the background. So, you can have CLI commands like with hexagonal architecture frameworks like Symfony. You can have REST API backends that don’t need to load the entire WordPress architecture. You can quickly write whatever management/migration/monitoring tools you need. …

    It is sure that this entails more work and more overhead than just using PHP5.2 functions, global variables and direct SQL access. But it is the only way, in my mind, to decouple code from WordPress. There’s no point in building layer upon layer of class hierarchies, when they are all directly coupled to some WP function, global variable, or DB structure.

    Ah, I could write about these topics for hours, but I’ll stop here. Comments are not the most structured way of communicating ideas… :)

    • I think you’ve hit the nail on the head. I rarely ever see code architected this way, especially in agency projects. I’ve struggled with melding testing concepts with WP projects because of this very fact. When WP is treated as a (replaceable) dependency, testing becomes more than easier, it becomes more natural and feasible. Otherwise, the tests either have to bootstrap WP (there goes isolation and speed) or mock Core functionality (there goes your sanity and time. and isolation).

      Would love to see some of your work – the wp-model sounds awesome!

      • Hey Josh,

        Thanks for the feedback!

        The wp-model is not in a usable state right now, so the code is not yet available. I have some other packages I use in my daily WordPress work available at https://github.com/brightnucleus .

        This includes the “Injector” upon which my abstraction layers work. Using this Injector, you can properly code against interfaces, and only define what exact implementations to use at runtime.

        So, following the example above, Your code will require an object to be injected through its constructor that fulfils an interface, like UserRepositoryInterface, and at runtime, the Injector looks through its configuration to see what exact implementation it should instantiate to inject in place of this interface.

        Proper dependency injection is one of the most important steps to properly decoupled code.

        Enjoy browsing through my code, and feel free to contact me if you have any questions.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.