Using A Config To Write Reusable Code

This is the first part of a series of articles. ( Part 2, Part 3 )

Object orientation lures you with the promise of making code reusable, letting you write source code once and then reusing it over and over in all of your projects. However, if you start delving into OOP territory, you’ll probably notice rather soon that wrapping code in classes does not in and of itself make the code reusable. There are several things you need to take into consideration to produce truly project-independent objects.

One of the issues you’re facing is that you’ll often end up with classes that contain a wild mixture of boilerplate code, that just takes care of the necessary plumbing, actual application logic that takes care of whatever you are trying to achieve, and also “business logic”, that guides the technical concerns into whatever direction that is needed to address the actual business needs.

Your goal should not be to make the entirety of this mess reusable, but rather only the subset of boilerplate code and application logic. The business logic is per definition tied to a specific business need, so it cannot be reusable across different projects and clients.

Throughout this article series, we will use a basic settings page containing two text fields as an example to try different approaches. The settings page itself does not do anything meaningful, it only serves as an example.

A broken example

Let’s go through an example of a naïve OOP implementation of a settings page using the WordPress Settings API to see what the actual problem is.

GitHub Repository:
 Example Code: Settings Page – Broken Implementation v1

This is a first try at implementing our basic Settings page. It uses a SettingsPage class that does all the work of setting up the page. This is proper OOP, right?

No, not really. It is more or less procedural code wrapped in a class syntax.

Let’s dig deeper into the code to see what the issue is.

As you can see in the code linked above, we have a class that uses the WordPress Settings API to implement a settings page with 2 sections and a total of 4 settings. This class gets instantiated in lines 39-44 of the src/Plugin.php file and hooked up to the WordPress life-cycle.

public function init_settings_page() {
    // Initialize settings page.
    $settings_page = new SettingsPage();
    // Register dependencies.
    add_action( 'init', [ $settings_page, 'register' ] );
}

As we have a class that manages our settings, can we already reuse this code in a different project?

No, not really. It is true that we can reuse this class in a different project, but it will always take care of the exact same business needs. In this particular case, we can only reuse this class in a different project if we want to have a “as-settings-broken-v1” options page with the title “Broken Settings v1 Settings Page”, and which collects the first and last names to store them within the assb1_settings option…

As an example, let’s examine the method SettingsPage::options_page() (lines 114-128 of the file src/SettingsPage.php).

public function options_page() {
    ?>
    

<form action='options.php' method='post'>

<h2>Broken Settings v1 Settings Page</h2>



        <?php settings_fields( 'pluginPage' ); do_settings_sections( 'pluginPage' ); submit_button(); ?>

    </form>


    <?php
}

Almost any options page built through the Settings API will have a form to be posted, that includes a heading, the registered settings sections and fields, as well as a submit button. However, the actual text of the heading will vary from project to project, as will the identifier of the fields and sections to render.

Although our class is “technically” reusable, it is so limited in scope and flexibility that it will only ever be useful for reuse in the exact same project. This should make it obvious that OOP syntax in and of itself does not provide reusable code.

Object-oriented syntax in and of itself does not make your code reusable. Click To Tweet

Different Types Of Logic

We can’t easily reuse any of our source code from the example linked to above because we have wildly mixed both boilerplate code and business- or project-specific logic.

Conceptual drawing of code mixing both reusable code and project-specific code.

If we take a more detailed look at the class we wrote for the SettingsPage (the file src/SettingsPage.php), and try to find out for each specific statement and element, whether it is reusable, or project-specific, we can quickly see that there’s no clear separation between these at all.

Source code for SettingsPage class, with each word color-coded to distinguish between reusable and project-specific code.

Any piece of code that contains project-specific data or logic is per definition not reusable across projects. What’s more, if we want to reuse code without copy-pasting, this means we need to be able to separate reusable and project-specific at the granularity level that is dictated by the way we pull in this code. This being a PHP example, we would most likely want to pull in this code via Composer, making our granularity level match a Composer package. If we intended to make a reusable “Settings Page” Composer package, the entire package must be completely devoid of project-specific data or logic.

It becomes imperative then, that we have a very clear separation between reusable and non-reusable code, and we need to design our code so that these two types of logic are not intermingled.

Conceptual drawing of code where reusable and project-specific parts are properly separated.

Design your code so that the reusable parts and the project-specific parts never intermingle. Click To Tweet

Once we’ve managed to fulfil this requirement, it is very easy to split out the reusable part of the code into a separate package, and, provided we’ve done everything right, the project-specific part of the code will not even need to be changed to work with an external package instead of the included reusable part.

Conceptual drawing of code where the reusable part has been split out into an external package.

How To Achieve This Separation

In the next part of this series, we will try to think of the possible ways of achieving this separation of reusable and project-specific code, and examine the concept of Config files more closely.

As always, any feedback or questions are more than welcome! Just head over to the comments section and type away!

This is the first part of a series of articles. ( Part 2, Part 3 )

Leave a Comment