Deprecated code in Open Source (with WordPress functions)
Tags: opensource, wordpress, php, architecture
Published: 2023-01-18 11:57:43

<!-- wp:paragraph -->
<p>Keeping a codebase organized always requires some changes: functions, files, structures, everything someday needs a new name or place. <strong>How do we make a change without breaking anything?</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Open-source codebases come with several advantages but some specific challenges. Different from a service that simply provides a more strict API, like a REST API, for example, <strong>others can call almost anything in your code</strong>. That said, you must be cautious even while renaming the simplest function.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Although all this can sound painful, it is not. <strong>Keeping your codebase organized is worth it!</strong></p>
<!-- /wp:paragraph -->

<!-- wp:uagb/table-of-contents {"block_id":"c1391a33","classMigrate":true,"headingTitle":"Table of Contents","leftPadding":30,"rightPadding":30,"topPadding":30,"bottomPadding":30,"overallBorderTopWidth":1,"overallBorderLeftWidth":1,"overallBorderRightWidth":1,"overallBorderBottomWidth":1,"overallBorderTopLeftRadius":6,"overallBorderTopRightRadius":6,"overallBorderBottomLeftRadius":6,"overallBorderBottomRightRadius":6,"overallBorderStyle":"solid"} /-->

<!-- wp:heading -->
<h2 class="wp-block-heading" id="faca-a-limpeza-em-fases">Make the change in phases</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Simply renaming the function is not a good idea: any solution depending on it will suddenly break. You need to <strong>warn that action will be needed</strong> and, after enough time, really implement the new solution.</p>
<!-- /wp:paragraph -->

<!-- wp:quote {"align":"center","className":"is-style-plain","fontSize":"medium"} -->
<blockquote class="wp-block-quote has-text-align-center is-style-plain has-medium-font-size"><!-- wp:paragraph -->
<p>To define what and when needs to be changed, we can use <strong>Semantic Versioning</strong>.</p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading" id="versionamento-semantico"><strong>Semantic Versioning</strong></h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p><strong><a href="https://semver.org/" target="_blank" rel="noreferrer noopener nofollow">Semantic Versioning</a> gives meaning to the numbers of a software version</strong>, aligning expectations of what can happen in each new release.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The following table summarizes what would be the <strong>major, minor, and patch</strong> version number of a software in its 2.4.3 release, in addition to what we could expect from the upcoming 2.4.4, 2.5.0, or 3.0.0 releases.</p>
<!-- /wp:paragraph -->

<!-- wp:table {"hasFixedLayout":true,"className":"is-style-stripes"} -->
<figure class="wp-block-table is-style-stripes"><table class="has-fixed-layout"><tbody><tr><td class="has-text-align-center" data-align="center"><strong>Major </strong>(<strong>2.</strong>4.3)</td><td class="has-text-align-center" data-align="center"><strong>Minor</strong> (2.<strong>4.</strong>3)</td><td class="has-text-align-center" data-align="center"><strong>Patch </strong>(2.4.<strong>3</strong>)</td></tr><tr><td class="has-text-align-center" data-align="center">Changes that <strong>do break</strong> backward compatibility</td><td class="has-text-align-center" data-align="center">New features that <strong>do not break </strong>backward compatibility</td><td class="has-text-align-center" data-align="center">Bug fixes only</td></tr><tr><td class="has-text-align-center" data-align="center">Updating to <strong>version 3.0.0</strong> requires attention, as the current solution can break</td><td class="has-text-align-center" data-align="center">Updating to <strong>version 2.5.0</strong> means that everything continues to work but with some new functionality</td><td class="has-text-align-center" data-align="center">Updating to <strong>version 2.4.4</strong> means some bugs were fixed</td></tr></tbody></table></figure>
<!-- /wp:table -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading" id="exemplo-pratico">Practical Example</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Keeping both the function rename example and our 2.4.3 version in mind, let's see how we could plan that out. Let's split the process into some steps and define their release versions.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4 class="wp-block-heading" id="versao-2-5-0-implementar-o-codigo-novo-e-alterar-o-codigo-velho-sem-quebrar">Version 2.5.0: Implement new code and change the old code without breaking it</h4>
<!-- /wp:heading -->

<!-- wp:list {"ordered":true} -->
<ol><!-- wp:list-item -->
<li><strong>Implement the new code.</strong> It doesn't matter if it is a renamed function or a brand-new method, the new code needs to be there so people can do the switch;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li><strong>Change the old code.</strong> In case it is just a simple switch, the old code needs to become a wrapper of the new function with a warning about the (now) wrong usage;</li>
<!-- /wp:list-item --></ol>
<!-- /wp:list -->

<!-- wp:code {"className":"php"} -->
<pre class="wp-block-code php"><code>
function new_name( $parameter ) {
	// Do something
}

function old_name( $parameter ) {
	_deprecated_function( __FUNCTION__, '2.5.0', 'new_name' );
	new_name( $parameter );
}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Note that calling <code>old_name()</code> still works but a warning was added there saying that starting from version 2.5.0 <code>new_name()</code> is the function that should be called.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":4} -->
<h4 class="wp-block-heading" id="versao-3-0-0-remover-o-codigo-velho">Version 3.0.0: Remove the old code</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p><strong>After warning for long enough, you can remove the old code.</strong> Attention: this removal is expected to happen in a <em>major</em> version.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>You do not need to remove the code in the immediate following version, though. Depending on your user base and your release calendar you can wait for any major version, like 4.0.0 or 5.0.0, for example.</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>A project that just releases a major version per year can have a slightly different approach from a project that releases a major version per month.</p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading" id="arquivos-com-codigos-obsoletos">Move deprecated code into separate files</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>One of the intentions behind these changes is to keep your codebase clean and organized. With that in mind, keeping these functions in your main files can make you uncomfortable as things can actually look messier than before.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Some development teams <strong>move these pieces of code to specific files</strong>, named <code>deprecated.php</code>, for example. In addition to a readability increase, this also helps when you need to identify which code can be removed while launching 3.0.0.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading" id="quanto-mais-comunicacao-melhor">The more you communicate, the better</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>In the example above we called the <code>_deprecated_function()</code> WordPress function but that will only have an effect if the <code>WP_DEBUG</code> constant is set to true.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Unfortunately, quite often these warnings are useless: in many cases, people are not paying any attention to logs. <strong>You also need to warn your users in an accessible and human-readable way.</strong></p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><!-- wp:paragraph -->
<p>Inform your users about important changes in all ways possible: logs warnings, items in your changelog, blog posts, and even social media if needed.</p>
<!-- /wp:paragraph --></blockquote>
<!-- /wp:quote -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading" id="changelog-ou-registro-de-alteracoes">Changelog</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>The best place to communicate changes in your software is in its <em>changelog</em>. In WordPress, this type of log is kept in a specific section of the <em>readme.txt</em> file and is displayed on both the plugin page and in a modal inside the Dashboard.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Using Akismet as an example, this is the link to see the next version's details.</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":2593,"width":677,"height":150,"sizeSlug":"full","linkDestination":"media"} -->
<figure class="wp-block-image aligncenter size-full is-resized"><a href="https://felipeelia.com.br/wp-content/uploads/2023/01/image.png"><img src="https://felipeelia.com.br/wp-content/uploads/2023/01/image.png" alt="" class="wp-image-2593" width="677" height="150"/></a><figcaption class="wp-element-caption">Plugins list in WordPress's Dashboard. The yellow notice is delayed when there is a new version of the plugin.</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Clicking on the link will open a modal with the <em>changelog</em>:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":2594,"width":492,"height":420,"sizeSlug":"full","linkDestination":"media"} -->
<figure class="wp-block-image aligncenter size-full is-resized"><a href="https://felipeelia.com.br/wp-content/uploads/2023/01/image-1.png"><img src="https://felipeelia.com.br/wp-content/uploads/2023/01/image-1.png" alt="" class="wp-image-2594" width="492" height="420"/></a><figcaption class="wp-element-caption">Modal with the plugin's changelog. Versions are usually ordered from the newest to the oldest.</figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>WordPress gets that information from the <code>== Changelog ==</code> section of the readme.txt plugin's file, hosted in WP.org official repository:</p>
<!-- /wp:paragraph -->

<!-- wp:image {"align":"center","id":2595,"width":617,"height":184,"sizeSlug":"full","linkDestination":"media"} -->
<figure class="wp-block-image aligncenter size-full is-resized"><a href="https://felipeelia.com.br/wp-content/uploads/2023/01/image-2.png"><img src="https://felipeelia.com.br/wp-content/uploads/2023/01/image-2.png" alt="" class="wp-image-2595" width="617" height="184"/></a><figcaption class="wp-element-caption"><a href="https://plugins.trac.wordpress.org/browser/akismet/tags/5.0.2/readme.txt" target="_blank" rel="noreferrer noopener nofollow">Akismet's readme.txt file</a></figcaption></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Usually, changelogs are divided into sections, separating what was added, changed, fixed, removed, and deprecated. An example of this division can be seen in both <a href="https://github.com/10up/ElasticPress/releases/tag/4.4.1" target="_blank" rel="noreferrer noopener">ElasticPress's release notes</a> and its changelog.</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3 class="wp-block-heading" id="funcoes-do-wordpress">WordPress Functions</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>WordPress has some functions that help to inform the usage of deprecated code. Here is the list:</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>_deprecated_function( $function, $version, $replacement = '' )</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>This function is in the example we used before. <strong>A simple way to mark a function as deprecated.</strong></p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>apply_filters_deprecated( $hook_name, $args, $version, $replacement = '', $message = '' )</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>This and the next are wrappers for <code>_deprecated_hook()</code>, which is not part of this list, as it should not be called directly. As the name says, this function <strong>applies a filter</strong> but also informs it is deprecated and, if available, provides its proper replacement.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>do_action_deprecated( $hook_name, $args, $version, $replacement = '', $message = '' )</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Similar to the last one but <strong>applied to an action</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>_doing_it_wrong( $function, $message, $version )</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>Although not necessarily related to deprecated code, I'm adding <code>_doing_it_wrong()</code> to the list as it can be super <strong>useful when the change requires more attention than a simple name change</strong>.  </p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>_deprecated_argument( $function, $version, $message = '' )</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>As the name implies, this is for a <strong>change in an argument</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Although always related to an argument, there are a couple of different scenarios where this function can be used:</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><!-- wp:list-item -->
<li>A change in the expected value of an argument like <code>'blacklist_keys'</code> that is now <code>'disallowed_keys'</code>;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>An argument that does not exist anymore;</li>
<!-- /wp:list-item -->

<!-- wp:list-item -->
<li>An index of an array argument. Let's say, before <code>$args['cat']</code> was expected but now it is <code>$args['taxonomy']</code>.</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->

<!-- wp:code -->
<pre class="wp-block-code"><code>_deprecated_file( $file, $version, $replacement = '', $message = '' )</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p><strong>Marks an entire file as deprecated.</strong> Usage examples are renamed files or files that are not needed anymore. The <code>wp-includes/class-json.php</code> file calls that function, as since WP 5.3.0 the native PHP extension is required.</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>_deprecated_constructor( $class, $version, $parent_class = '' )</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>This is <strong>related to object constructors</strong>. Years ago, constructors methods in PHP had their class name but since PHP 5.4 the recommended way is using the magic <code>__construct()</code> method. Class name constructors are deprecated since PHP 7.0 and should not be used anymore.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading" id="sobre-os-termos-em-portugues">Obsolete vs. deprecated</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Each language has its own specificity. For Brazilian Portuguese, for example, we don't have a specific word for "deprecated". People quite often wrongly translate that as "depreciated." So, we use obsolete and deprecated interchangeably.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In English, those two words refer to different states of the code: deprecated code is still functional and present, obsolete code usually doesn't work anymore, and/or was removed from the codebase.</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading" id="conclusao">Conclusion</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Keeping your codebase clean and organized is essential. To make the needed changes and keep retro compatibility you need to plan the <strong>changes in phases</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Semantic Versioning</strong> can help you to plan which changes are shipped in which versions, so your users are not caught off guard.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Communicating changes through your <strong><em>changelogs</em> </strong>also brings more visibility to actions your users will need to take. Specific sections listing those changes help even more.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>We also saw some <strong>WordPress functions</strong> that can help to inform changes in several different scenarios.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Lastly, we saw how these terms can vary in different languages and the <strong>difference between deprecated and obsolete</strong>.</p>
<!-- /wp:paragraph -->