<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Moxio</title>
    <description>The latest articles on DEV Community by Moxio (@moxio).</description>
    <link>https://dev.to/moxio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1760%2F86875fa8-476d-41a6-be56-ae1461f9d350.png</url>
      <title>DEV Community: Moxio</title>
      <link>https://dev.to/moxio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/moxio"/>
    <language>en</language>
    <item>
      <title>How to load an SQLite extension in PDO?</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Thu, 28 May 2020 06:00:00 +0000</pubDate>
      <link>https://dev.to/moxio/how-to-load-an-sqlite-extension-in-pdo-b7o</link>
      <guid>https://dev.to/moxio/how-to-load-an-sqlite-extension-in-pdo-b7o</guid>
      <description>&lt;p&gt;Recently we ran into the need to load an extension for SQLite using PHP's PDO database abstraction. Unfortunately, this is not supported out of the box. Eventually we found a solution involving &lt;a href="https://www.php.net/manual/en/book.ffi.php"&gt;FFI&lt;/a&gt; and &lt;a href="https://github.com/lisachenko/z-engine"&gt;Z-Engine&lt;/a&gt;. In this blog post I will take you on a tour of our solution and the &lt;em&gt;black magic&lt;/em&gt; behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;At Moxio we make extensive use of geospatial database functions. Whether it's for infrastructural construction projects or rule management for the living environment, a lot of objects are bound to a specific geographic location and need to be queried as such. In production we run MariaDB as a database engine, which has geospatial support &lt;a href="https://mariadb.com/kb/en/geographic-geometric-features/"&gt;baked in&lt;/a&gt;. For integration tests however we use the lightweight SQLite database engine, which does not come with geospatial functions out of the box. The &lt;a href="https://www.gaia-gis.it/fossil/libspatialite/index"&gt;SpatiaLite&lt;/a&gt; extension for SQLite can be used for this.&lt;/p&gt;

&lt;p&gt;Currently we use a homemade database abstraction layer, which uses the &lt;a href="https://www.php.net/manual/en/book.sqlite3.php"&gt;&lt;code&gt;SQLite3&lt;/code&gt; PHP extension&lt;/a&gt; for communicating with SQLite. This PHP extension allows loading SQLite extensions such as SpatiaLite using the &lt;a href="https://www.php.net/manual/en/sqlite3.loadextension.php"&gt;&lt;code&gt;SQLite3::loadExtension&lt;/code&gt;&lt;/a&gt; method. So far all is well.&lt;/p&gt;

&lt;p&gt;At the moment we're looking at switching our own database abstraction layer for the &lt;a href="https://www.doctrine-project.org/projects/dbal.html"&gt;Doctrine DBAL&lt;/a&gt;. It simply doesn't make sense anymore to maintain our own. We'd rather use a battle-tested open source solution and &lt;a href="https://github.com/doctrine/dbal/issues/3963"&gt;try to contribute back&lt;/a&gt; some of our code if possible, so that everybody benefits.&lt;/p&gt;

&lt;p&gt;The problem is that the Doctrine DBAL implementation is not based on PHP's SQLite3 extension, but basically a wrapper around &lt;a href="https://www.php.net/manual/en/book.pdo.php"&gt;PDO&lt;/a&gt;, which is already a database abstraction layer. It therefore contains few SQLite-specific features. There are &lt;a href="https://www.php.net/manual/en/ref.pdo-sqlite.php"&gt;three &lt;code&gt;sqlite&lt;/code&gt;-prefixed functions&lt;/a&gt; in PDO, but the possibility to load an SQLite extension is not one of them. This is registered &lt;a href="https://bugs.php.net/bug.php?id=64810"&gt;in the PHP issue tracker&lt;/a&gt; and there's &lt;a href="https://github.com/php/php-src/pull/3368"&gt;an implementation PR on GitHub&lt;/a&gt;, but that one didn't make it into PHP 7.4. So, no Doctrine DBAL for us?&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring solutions
&lt;/h2&gt;

&lt;p&gt;Naturally, we started thinking of solutions. Even if PHP didn't expose the functionality to load extensions, maybe we could still call it directly through the SQLite C API. The &lt;a href="https://www.php.net/manual/en/book.ffi.php"&gt;Foreign Function Interface (FFI)&lt;/a&gt; introduced in PHP 7.4 would be a good candidate to do this. However, if we look at the relevant function declaration in the C API we notice a problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;sqlite3_load_extension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;sqlite3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="cm"&gt;/* Load the extension into this database connection */&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;zFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="cm"&gt;/* Name of the shared library containing extension */&lt;/span&gt;
  &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;zProc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="cm"&gt;/* Entry point.  Derived from zFile if 0 */&lt;/span&gt;
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;pzErrMsg&lt;/span&gt;       &lt;span class="cm"&gt;/* Put error message here if not 0 */&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;sqlite3_load_extension&lt;/code&gt; requires a pointer to the database connection we want to load the extension into, which we don't have in PHP. We must find some trick to obtain it from the &lt;code&gt;PDO&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;Luckily, through trips to phpCE 2018 and Bulgaria PHP 2019 I've come to know &lt;a href="https://twitter.com/lisachenko"&gt;Alexander Lisachenko&lt;/a&gt; and his work on &lt;a href="https://github.com/lisachenko/z-engine"&gt;Z-Engine&lt;/a&gt;. Z-Engine is a PHP library that uses FFI to hook into the Zend Engine, providing access to PHP's internal structures. Maybe this would allow obtaining the internal &lt;code&gt;sqlite3&lt;/code&gt; pointer behind a &lt;code&gt;PDO&lt;/code&gt; object? Indeed, after reaching out Twitter, Alexander &lt;a href="https://twitter.com/lisachenko/status/1252168616746893313"&gt;confirmed&lt;/a&gt; that this would probably be possible using Z-Engine.&lt;/p&gt;

&lt;p&gt;Hence I set out to try a solution based on Z-Engine, but soon another challenge presented itself. I had hoped that the &lt;code&gt;PDO&lt;/code&gt; object would have some sort of direct reference (something like a private variable) to the internal SQLite connection. This turned out not to be the case. Instead, the PDO implementation uses a common C trick where the &lt;code&gt;PDO&lt;/code&gt; object and its internal structures are &lt;a href="https://github.com/php/php-src/blob/d1764ca33018f1f2e4a05926c879c67ad4aa8da5/ext/pdo/php_pdo_driver.h#L510"&gt;aligned next to eachother in memory&lt;/a&gt;. In the C code they use a function &lt;a href="https://github.com/php/php-src/blob/d1764ca33018f1f2e4a05926c879c67ad4aa8da5/ext/pdo/php_pdo_driver.h#L520"&gt;&lt;code&gt;php_pdo_dbh_fetch_inner&lt;/code&gt;&lt;/a&gt; to shift in memory between the &lt;code&gt;PDO&lt;/code&gt; object and the internal struct. We cannot use this function from FFI hoewever, since it is inlined and thus not exposed as a separate function to the outside world. I reached out to Alexander once again, and he and &lt;a href="https://twitter.com/nikita_ppv"&gt;Nikita Popov&lt;/a&gt; pointed me to a trick involving &lt;code&gt;handler-&amp;gt;offset&lt;/code&gt; to obtain the correct memory offset to implement the memory shift myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;This proved to be the missing puzzle piece. It still took some time to get used to working with PHP FFI, but eventually I got a working solution. First we need to obtain a C pointer to the relevant &lt;code&gt;PDO&lt;/code&gt; object using Z-Engine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;ZEngine\Core&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;ZEngine\Reflection\ReflectionValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$pdo_refl_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ReflectionValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pdo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$pdo_obj_pointer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$pdo_refl_value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;getRawObject&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We then initialize an &lt;code&gt;FFI&lt;/code&gt; instance to traverse the relevant structures of the PDO-SQLite extension. To keep the header definitions brief, we omit all parts of C structs after the properties we're interested in. Also, we replace pointers to properties before the ones we want (and the &lt;code&gt;sqlite3&lt;/code&gt; pointer itself for now) by void pointers. This allows us to omit the headers for their real types, and doesn't matter since a pointer takes the same amount of memory regardless of what it points to. Also, we had to add a &lt;code&gt;struct&lt;/code&gt; keyword in some places to please the PHP FFI parser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$pdo_sqlite_ffi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;\FFI&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;cdef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;&amp;lt;&amp;lt;&amp;lt;CDEF
/* From https://github.com/php/php-src/blob/d1764ca33018f1f2e4a05926c879c67ad4aa8da5/ext/pdo/php_pdo_driver.h#L432 */
struct _pdo_dbh_t {
    /* replaced pdo_dbh_methods* by void* */
    const void *methods;
    void *driver_data;
    /* omitted rest of struct */
};
/* From https://github.com/php/php-src/blob/d1764ca33018f1f2e4a05926c879c67ad4aa8da5/ext/pdo/php_pdo_driver.h#L510 */
struct _pdo_dbh_object_t {
    /* had to insert struct keyword here */
    struct _pdo_dbh_t *inner;
    /* omitted `zend_object std` */
};
/* Adapted from https://github.com/php/php-src/blob/cfc704ea83c56970a72756f7d4fe464885445b5e/ext/pdo_sqlite/php_pdo_sqlite_int.h#L55 */
struct pdo_sqlite_db_handle {
    /* replaced sqlite3* by void* */
    void *db;
    /* omitted rest of struct */
};
CDEF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"pdo_sqlite.so"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With that FFI instance we can now perform the memory shift to get the PDO internal data structure corresponding to the exposed &lt;code&gt;PDO&lt;/code&gt; object. We use the &lt;code&gt;handle-&amp;gt;offset&lt;/code&gt; trick to obtain the correct memory offset for the shift:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Following https://github.com/php/php-src/blob/d1764ca33018f1f2e4a05926c879c67ad4aa8da5/ext/pdo/php_pdo_driver.h#L520&lt;/span&gt;
&lt;span class="nv"&gt;$offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$pdo_obj_pointer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$pdo_dbh_object_pointer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$pdo_sqlite_ffi&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"struct _pdo_dbh_object_t*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$pdo_sqlite_ffi&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"char*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$pdo_obj_pointer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$offset&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$pdo_dbh_pointer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$pdo_dbh_object_pointer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The driver-specific handles are in the &lt;code&gt;driver_data&lt;/code&gt; property. In case of the PDO SQLite driver this points to a &lt;code&gt;pdo_sqlite_db_handle&lt;/code&gt; object, which contains the raw SQLite connection in its &lt;code&gt;db&lt;/code&gt; property. We obtain a void pointer to that connection as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Following https://github.com/php/php-src/pull/3368/files#diff-eb26679695f7db289366ef6b03ee25daR729&lt;/span&gt;
&lt;span class="nv"&gt;$pdo_sqlite_db_handle_pointer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$pdo_sqlite_ffi&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"struct pdo_sqlite_db_handle*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$pdo_dbh_pointer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;driver_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$sqlite3_void_pointer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$pdo_sqlite_db_handle_pointer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we set up an FFI object for communicating with the SQLite C API (or at least the parts of it we want to use):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$sqlite3_ffi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;\FFI&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="na"&gt;cdef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;&amp;lt;&amp;lt;&amp;lt;CDEF
/* From https://github.com/sqlite/sqlite/blob/278b0517d88d4150830a4ee2c628a55da40d186d/src/sqlite.h.in#L249 */
typedef struct sqlite3 sqlite3;

/* From https://github.com/sqlite/sqlite/blob/278b0517d88d4150830a4ee2c628a55da40d186d/src/sqlite.h.in#L6581 */
int sqlite3_load_extension(
  sqlite3 *db,          /* Load the extension into this database connection */
  const char *zFile,    /* Name of the shared library containing extension */
  const char *zProc,    /* Entry point.  Derived from zFile if 0 */
  char **pzErrMsg       /* Put error message here if not 0 */
);
CDEF&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"sqlite3.so"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can then cast our void pointer to an actual &lt;code&gt;sqlite3&lt;/code&gt; pointer and use it to call functions on the SQLite C API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$sqlite3_pointer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$sqlite3_ffi&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"struct sqlite3*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$sqlite3_void_pointer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$sqlite3_ffi&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="na"&gt;sqlite3_load_extension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sqlite3_pointer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"mod_spatialite.so"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And &lt;em&gt;voila&lt;/em&gt;, our extension is loaded!&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;To make this solution easy to use, we published it as a &lt;a href="https://packagist.org/packages/moxio/sqlite-extended-api"&gt;Composer package&lt;/a&gt;. It hides all underlying Z-Engine and FFI logic and allows loading SQLite extensions through a simple API. We aim to grow this library to also provide access to other SQLite API's that are otherwise not available in PHP. If there are other SQLite features that you'd like to use with PHP, feel free to file a feature request or create a PR!&lt;/p&gt;

&lt;p&gt;Finally, please note that Z-Engine should not be considered stable before version 1.0.0. Use it at your own risk.&lt;/p&gt;

</description>
      <category>php</category>
      <category>sqlite</category>
      <category>pdo</category>
      <category>ffi</category>
    </item>
    <item>
      <title>What Open Source libraries would you like to have?</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Wed, 15 Jan 2020 14:11:15 +0000</pubDate>
      <link>https://dev.to/moxio/what-open-source-libraries-would-you-like-to-have-3kge</link>
      <guid>https://dev.to/moxio/what-open-source-libraries-would-you-like-to-have-3kge</guid>
      <description>&lt;p&gt;At Moxio we already have some of our code as open source on GitHub, but we've identified over 25 other parts of our codebase (mainly PHP and Javascript) that we would like to make freely available as open source. That's a lot, and it would take quite some time to release them all.&lt;/p&gt;

&lt;p&gt;We can really use your help to set priorities. Just open &lt;a href="https://docs.google.com/forms/d/e/1FAIpQLSf3Z6eLoUSoTw1YqomAGuBiOnwLkeftiqgOfUT90u3UDKiOnA/viewform"&gt;this form&lt;/a&gt; and check all components that you could use and would like to see as open source (takes less than 2 minutes). Feel free to spread the link among your fellow developers; the more voices we hear the more useful code we can release.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>opensource</category>
      <category>php</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Ignoring bulk change commits with git blame</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Thu, 17 Oct 2019 07:00:00 +0000</pubDate>
      <link>https://dev.to/moxio/ignoring-bulk-change-commits-with-git-blame-4po5</link>
      <guid>https://dev.to/moxio/ignoring-bulk-change-commits-with-git-blame-4po5</guid>
      <description>&lt;p&gt;A long-standing objection to making bulk changes to code using automated tools (e.g. to conform to a given code style) is that it clutters the output of &lt;code&gt;git blame&lt;/code&gt;. With git 2.23, this does not have to be the case anymore! In this post I will start by explaining the value of &lt;code&gt;git blame&lt;/code&gt; and how commits with style changes in bulk can be problematic. If you already understand this problem and just want a solution, you can directly skip to the new features git 2.23 has to offer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting changes into context
&lt;/h2&gt;

&lt;p&gt;A characteristic feature of legacy code is that it's often not clear why it operates the way that it does. Some of the original developers may have left or have been reassigned to another project, documentation is virtually nonexistent, &lt;br&gt;
and the few remaining developers do not remember all the details anymore. For example, one day you might stumble upon the follow piece of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;describeBottles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'There are '&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' bottles of cider on the wall.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Despite being an artificial example, this code already raises some questions. Why is the default amount of bottles being described 42? And why do we describe bottles of cider? Bottles of beer would be a more customary alternative, right? Still these choices were probably made for a good reason; it's just that we don't know that reason.&lt;/p&gt;

&lt;p&gt;It would be good if the reasoning behind these choices was documented using comments. However, as happens with legacy code, this is not the case. How can we still find out the motivation behind the current state of the code? A version control system such as &lt;a href="https://git-scm.com/"&gt;git&lt;/a&gt; (you use version control, right?) may be helpful here. If you write &lt;a href="https://chris.beams.io/posts/git-commit/"&gt;good commit messages&lt;/a&gt; that focus on the &lt;em&gt;why&lt;/em&gt; rather than the &lt;em&gt;how&lt;/em&gt;, you might be able to distill the context from there. We only need to find which commit made a given change.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://git-scm.com/docs/git-blame"&gt;&lt;code&gt;git blame&lt;/code&gt;&lt;/a&gt; command (or &lt;a href="https://csswizardry.com/2017/05/little-things-i-like-to-do-with-git/#praise-people"&gt;&lt;code&gt;git praise&lt;/code&gt;&lt;/a&gt; if you prefer a more positive mindset) can be helpful here. It shows, for each line in a file, which commit made the last change to that line, along with its timestamp and author:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git blame describeBottles.php
^8206b47 &lt;span class="o"&gt;(&lt;/span&gt;Jane Doe   2019-04-21 09:41:20 +0200 1&lt;span class="o"&gt;)&lt;/span&gt; &amp;lt;?php
b589bf1e &lt;span class="o"&gt;(&lt;/span&gt;John Smith 2019-07-03 14:42:46 +0200 2&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;function &lt;/span&gt;describeBottles&lt;span class="o"&gt;(&lt;/span&gt;int &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 42&lt;span class="o"&gt;)&lt;/span&gt;: string &lt;span class="o"&gt;{&lt;/span&gt;
2c386e07 &lt;span class="o"&gt;(&lt;/span&gt;A.N. Other 2019-09-18 16:58:24 +0200 3&lt;span class="o"&gt;)&lt;/span&gt;     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'There are '&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' bottles of cider on the wall.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
^8206b47 &lt;span class="o"&gt;(&lt;/span&gt;Jane Doe   2019-04-21 09:41:20 +0200 4&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;From this output we can see that line 3 was last changed by 'A.N. Other' in commit &lt;code&gt;2c386e07&lt;/code&gt;. If we lookup the details for that commit we may find out why this function describes bottles of cider rather than beer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git show 2c386e07
commit 2c386e07b72041af1e0c2f827ac31357829429dd
Author: A.N. Other &amp;lt;a.n.other@example.com&amp;gt;
Date:   Wed Sep 18 16:58:24 2019 +0200

    Change drink

    Extensive user testing has shown that our customers like
    cider better than beer.

    Jira: BOT-123

diff &lt;span class="nt"&gt;--git&lt;/span&gt; a/describeBottles.php b/describeBottles.php
index ef2b0fd..9336895 100644
&lt;span class="nt"&gt;---&lt;/span&gt; a/describeBottles.php
+++ b/describeBottles.php
@@ &lt;span class="nt"&gt;-1&lt;/span&gt;,5 +1,5 @@
 &amp;lt;?php
 &lt;span class="k"&gt;function &lt;/span&gt;describeBottles&lt;span class="o"&gt;(&lt;/span&gt;int &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 42&lt;span class="o"&gt;)&lt;/span&gt;: string &lt;span class="o"&gt;{&lt;/span&gt;
-    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'There are '&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' bottles of beer on the wall.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
+    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'There are '&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' bottles of cider on the wall.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="o"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Bingo! We have found the exact commit in which we swapped beer for cider, and more importantly: we know why. We even have a link to a Jira ticket where we can find more information. Perhaps it contains the full user testing results, providing us with even more context. This makes &lt;code&gt;git blame&lt;/code&gt; an absolute life saver in legacy projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: bulk changes
&lt;/h2&gt;

&lt;p&gt;The team behind the &lt;code&gt;describeBottles&lt;/code&gt;-function has always used their own coding standards, with opening braces on the same line and 'CRLF' line endings. One day they decide to adopt the &lt;a href="https://www.php-fig.org/psr/psr-2/"&gt;PSR-2&lt;/a&gt; coding style guide that has become popular in the PHP community. Luckily there are tools like &lt;a href="https://github.com/FriendsOfPHP/PHP-CS-Fixer"&gt;PHP-CS-Fixer&lt;/a&gt; and &lt;a href="https://github.com/squizlabs/PHP_CodeSniffer/wiki/Fixing-Errors-Automatically"&gt;phpcbf&lt;/a&gt; to automatically convert the whole codebase to the new standard. There are similar tools for almost all other programming languages.&lt;/p&gt;

&lt;p&gt;Now the team has one huge commit with style changes in their repository. It touches every line without altering the meaning or intent of the code. If we would now use &lt;code&gt;git blame&lt;/code&gt; to find the background for a line of code, the output would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git blame describeBottles.php
df0ee6b0 &lt;span class="o"&gt;(&lt;/span&gt;Regina Phalange 2019-09-26 16:51:58 +0200 1&lt;span class="o"&gt;)&lt;/span&gt; &amp;lt;?php
df0ee6b0 &lt;span class="o"&gt;(&lt;/span&gt;Regina Phalange 2019-09-26 16:51:58 +0200 2&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;function &lt;/span&gt;describeBottles&lt;span class="o"&gt;(&lt;/span&gt;int &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 42&lt;span class="o"&gt;)&lt;/span&gt;: string
df0ee6b0 &lt;span class="o"&gt;(&lt;/span&gt;Regina Phalange 2019-09-26 16:51:58 +0200 3&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
df0ee6b0 &lt;span class="o"&gt;(&lt;/span&gt;Regina Phalange 2019-09-26 16:51:58 +0200 4&lt;span class="o"&gt;)&lt;/span&gt;     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'There are '&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' bottles of cider on the wall.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
df0ee6b0 &lt;span class="o"&gt;(&lt;/span&gt;Regina Phalange 2019-09-26 16:51:58 +0200 5&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As we can guess, the last commit that touched line 4 does not give us any useful context anymore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git show df0ee6b0
commit df0ee6b006ee0f90cccc18b71ced290f6cae18d9 &lt;span class="o"&gt;(&lt;/span&gt;HEAD -&amp;gt; master&lt;span class="o"&gt;)&lt;/span&gt;
Author: Regina Phalange &amp;lt;r.phalange@example.com&amp;gt;
Date:   Thu Sep 26 16:51:58 2019 +0200

    Fix line endings

diff &lt;span class="nt"&gt;--git&lt;/span&gt; a/describeBottles.php b/describeBottles.php
index 17f0657..d9c9f99 100644
&lt;span class="nt"&gt;---&lt;/span&gt; a/describeBottles.php
+++ b/describeBottles.php
@@ &lt;span class="nt"&gt;-1&lt;/span&gt;,5 +1,5 @@
-&amp;lt;?php
&lt;span class="nt"&gt;-function&lt;/span&gt; describeBottles&lt;span class="o"&gt;(&lt;/span&gt;int &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 42&lt;span class="o"&gt;)&lt;/span&gt;: string
-&lt;span class="o"&gt;{&lt;/span&gt;
-    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'There are '&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' bottles of cider on the wall.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
-&lt;span class="o"&gt;}&lt;/span&gt;
+&amp;lt;?php
+function describeBottles&lt;span class="o"&gt;(&lt;/span&gt;int &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 42&lt;span class="o"&gt;)&lt;/span&gt;: string
+&lt;span class="o"&gt;{&lt;/span&gt;
+    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'There are '&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' bottles of cider on the wall.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
+&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Because these bulk changes render &lt;code&gt;git blame&lt;/code&gt; useless, many teams refrain from applying automated style changes of this magnitude. That means they have to live with either a coding standard that they would rather not have, or with a codebase that does not follow their standards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git 2.23 to the rescue!
&lt;/h2&gt;

&lt;p&gt;To limit the impact of such 'unimportant' bulk commits, git 2.23 adds a new option to &lt;code&gt;git blame&lt;/code&gt;. Using &lt;a href="https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revltrevgt"&gt;&lt;code&gt;--ignore-rev&lt;/code&gt;&lt;/a&gt;, one can specify a commit to be ignored by &lt;code&gt;git blame&lt;/code&gt;. Lines changed by the ignored commit will be attributed to the previous commit touching that line instead. This means that even after our bulk style change, we can get back a meaningful context for the 'real' changes to our function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git blame &lt;span class="nt"&gt;--ignore-rev&lt;/span&gt; df0ee6b0 describeBottles.php
^8206b47 &lt;span class="o"&gt;(&lt;/span&gt;Jane Doe   2019-04-21 09:41:20 +0200 1&lt;span class="o"&gt;)&lt;/span&gt; &amp;lt;?php
b589bf1e &lt;span class="o"&gt;(&lt;/span&gt;John Smith 2019-07-03 14:42:46 +0200 2&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;function &lt;/span&gt;describeBottles&lt;span class="o"&gt;(&lt;/span&gt;int &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 42&lt;span class="o"&gt;)&lt;/span&gt;: string
b589bf1e &lt;span class="o"&gt;(&lt;/span&gt;John Smith 2019-07-03 14:42:46 +0200 3&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
2c386e07 &lt;span class="o"&gt;(&lt;/span&gt;A.N. Other 2019-09-18 16:58:24 +0200 4&lt;span class="o"&gt;)&lt;/span&gt;     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'There are '&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' bottles of cider on the wall.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
^8206b47 &lt;span class="o"&gt;(&lt;/span&gt;Jane Doe   2019-04-21 09:41:20 +0200 5&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Note how even line 3, which was added by the ignored commit, is attributed to commit &lt;code&gt;b589bf1e&lt;/code&gt;, which originally added the brace on the line above.&lt;/p&gt;

&lt;p&gt;When multiple bulk commits were added over time, it takes quite some effort to add a &lt;code&gt;--ignore-rev&lt;/code&gt; for each of them in order to get a 'clean' output for &lt;code&gt;git blame&lt;/code&gt;. Luckily, git also provides a way to make this easier on us. In your repository, create a file to hold commit hashes of commits to be ignored by &lt;code&gt;git blame&lt;/code&gt;. Naming this file &lt;code&gt;.git-blame-ignore-revs&lt;/code&gt; seems to be a common convention.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .git-blame-ignore-revs 
&lt;span class="c"&gt;# Conversion to PSR-2 code style&lt;/span&gt;
237de8a6367a88649a3f161112492d0d70d83707

&lt;span class="c"&gt;# Fix line endings&lt;/span&gt;
df0ee6b006ee0f90cccc18b71ced290f6cae18d9
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The file should contain the full (40 char) commit hashes. Lines starting with a &lt;code&gt;#&lt;/code&gt; are considered comments and can be used to explain what makes the given commit(s) unimportant. Now we can call &lt;code&gt;git blame&lt;/code&gt; with the &lt;a href="https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revs-fileltfilegt"&gt;&lt;code&gt;--ignore-revs-file&lt;/code&gt;&lt;/a&gt; option to ignore all these commits at once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git blame &lt;span class="nt"&gt;--ignore-revs-file&lt;/span&gt; .git-blame-ignore-revs describeBottles.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.git-blame-ignore-revs&lt;/code&gt; can be versioned inside the repository, so that all developers can use (and maintain) the same list of ignored commits. To avoid typing the extra option with every command, we can set the &lt;a href="https://git-scm.com/docs/git-config#Documentation/git-config.txt-blameignoreRevsFile"&gt;&lt;code&gt;blame.ignoreRevsFile&lt;/code&gt;&lt;/a&gt; configuration variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git config blame.ignoreRevsFile .git-blame-ignore-revs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This causes git to automatically ignore the commits specified in that file for every call to &lt;code&gt;git blame&lt;/code&gt;. If you stick to the &lt;code&gt;.git-blame-ignore-revs&lt;/code&gt; naming convention you can even set this configuration variable globally, so that it applies to all your repositories, each with their own &lt;code&gt;.git-blame-ignore-revs&lt;/code&gt; file. Be aware however that git currently gives an error when this setting is configured globally but a repository has no &lt;code&gt;.git-blame-ignore-revs&lt;/code&gt; file yet. I &lt;br&gt;
hope that this is considered a bug and will be fixed in an upcoming version.&lt;/p&gt;

&lt;p&gt;Another limitation to be aware of is that platforms like GitHub and GitLab do not yet support files with commits to ignore for the 'blame'-button in their user interface. It would be awesome if they added such a feature soon.&lt;/p&gt;

&lt;p&gt;One last thing: be aware that you need at least version 2.23 of git to use these new features. On the &lt;a href="https://git-scm.com/downloads"&gt;git downloads page&lt;/a&gt; you can find out how to obtain the latest git for your platform. But even if you cannot upgrade yet for some reason, you can already start building a &lt;code&gt;.git-blame-ignore-revs&lt;/code&gt; file with commits you would like to hide from &lt;code&gt;git blame&lt;/code&gt;. That way you can hit the ground running when it's time to upgrade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Git 2.23 contains an absolute game changer that is not even mentioned in the &lt;a href="https://github.blog/2019-08-16-highlights-from-git-2-23/"&gt;release highlights&lt;/a&gt;. Fear of polluting the &lt;code&gt;git blame&lt;/code&gt; output no longer has to be a blocker for applying style changes in bulk: these commits can now be ignored. You can even share a list of ignored commits with your entire team. So go ahead and switch over to that new coding standard; git won't hold you back anymore.&lt;/p&gt;

</description>
      <category>git</category>
      <category>legacy</category>
      <category>versioncontrol</category>
      <category>codestyle</category>
    </item>
    <item>
      <title>Mutation testing in PHP</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Wed, 17 Jul 2019 22:00:00 +0000</pubDate>
      <link>https://dev.to/moxio/mutation-testing-in-php-45ph</link>
      <guid>https://dev.to/moxio/mutation-testing-in-php-45ph</guid>
      <description>&lt;p&gt;Recently I spent an afternoon experimenting with &lt;em&gt;mutation testing&lt;/em&gt; in PHP. In this post I would like to share the background, the main idea of mutation testing, and the lessons I’ve learned from it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AMM2MfxFwWD5TMibwWu2gBQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AMM2MfxFwWD5TMibwWu2gBQ.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Moxio Academy
&lt;/h3&gt;

&lt;p&gt;At &lt;a href="https://www.moxio.com" rel="noopener noreferrer"&gt;Moxio&lt;/a&gt; we regularly schedule a &lt;em&gt;Moxio Academy&lt;/em&gt; session. That means we put our normal work aside for an afternoon to learn something new or experiment with the latest technologies. You can choose any topic, as long as it benefits your personal development and thus your role at the company. There are just a few rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have to decide on a topic and announce it in advance. This is meant to improve synergy within the team: maybe someone already knows a lot about the topic and has some resources to recommend. If multiple people want to learn about the same thing, maybe they can combine their efforts and learn together.&lt;/li&gt;
&lt;li&gt;You must create a plan for how to approach your topic. This does not have to be very extensive, just a rough sketch is enough. The idea is that this forces you to focus your learning efforts rather than just reading random resources without any sense of a general direction.&lt;/li&gt;
&lt;li&gt;You should work towards some kind of deliverable. Ideally this is something that can be shared with the rest of the team: a tool, wiki article, some proof-of-concept, blogpost or lunch-and-learn presentation. Again this helps to focus the process, to have some concrete end result, and to spread the acquired knowledge within the team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We usually conclude the afternoon together to present our process and results, and (for those who want) have a pizza.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mutation testing
&lt;/h3&gt;

&lt;p&gt;At the latest Moxio Academy I wanted to experiment with &lt;em&gt;mutation testing&lt;/em&gt; in PHP. I had already heard about mutation testing and &lt;a href="https://infection.github.io/" rel="noopener noreferrer"&gt;Infection&lt;/a&gt; as a tool to do so a few times, but never got around to play with it hands-on. This seemed like a good opportunity.&lt;/p&gt;

&lt;p&gt;In essence, &lt;em&gt;mutation testing&lt;/em&gt; is a way of measuring the quality of a test suite. A tool generates a number of copies (&lt;em&gt;mutants&lt;/em&gt;) of your source code under test, but modifies each of them in a small way. These small modifications are basically just errors that you as a programmer could have made, such as replacing a &lt;code&gt;&amp;lt;&lt;/code&gt; with a &lt;code&gt;&amp;lt;=&lt;/code&gt;. A high-quality testsuite would detect these modifications (&lt;em&gt;kill the mutant&lt;/em&gt;) by failing one or more tests. In a suboptimal test suite it might happen that the tests remain green despite the modification to the source code. In such a case we speak about an &lt;em&gt;escaped mutant&lt;/em&gt;. These present an opportunity to improve the test suite by adding a test that fails in the presence of the given modification. The &lt;em&gt;Mutation Score Indicator&lt;/em&gt; (MSI, the percentage of mutants detected by the test set) provides a metric for the quality of the test suite.&lt;/p&gt;

&lt;p&gt;My plan was to apply Infection to one of our internal libraries. I picked this library because of its high (line-based) code coverage, which would imply a high-quality test suite. Therefore I wondered what ‘leaks’ Infection could still find in it. The idea was to convert the escaped mutations found by Infection to new tests, working towards a PR to increase the MSI of the project as the main deliverable. This blog post wasn’t part of the original plan, but arose as an extra way of sharing some of the lessons learned along the way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lessons learned
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Mutation testing is awesome!
&lt;/h4&gt;

&lt;p&gt;My main takeaway was that mutation testing can really help you to improve your test suite. Even on a project with 96% line coverage, Infection found multiple scenarios that were not actually covered by the test suite.&lt;/p&gt;

&lt;p&gt;One simplified example of this is the following. Suppose we have a function to generate a description for the amount of bottles of beer on the wall:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;describeBottles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$amount&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' bottles of beer on the wall'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We could already have a test for this function like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DescribeBottlesTest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testDescribesTheAmountOfBottlesOfBeer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'42 bottles of beer on the wall'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;describeBottles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At first sight it may seem that this fully tests the function, and indeed the function shows up with all lines covered in a code coverage report. However, our tests do not check the default value for the argument. This means that some behavior of our function, i.e. that by default it describes 99 bottles, is not verified. Infection can uncover this when it produces a mutation like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;12) /tmp/bottles.php:2    [M] DecrementInteger
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;--- Original
&lt;/span&gt;&lt;span class="gi"&gt;+++ New
&lt;/span&gt;&lt;span class="p"&gt;@@ @@&lt;/span&gt;
&amp;lt;?php
&lt;span class="gd"&gt;- function describeBottles(int $amount = 99): string {
&lt;/span&gt;&lt;span class="gi"&gt;+ function describeBottles(int $amount = 98): string {
&lt;/span&gt;      return $amount . ' bottles of beer on the wall';
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here the &lt;code&gt;DecrementInteger&lt;/code&gt; mutator has decremented an integer literal occurring in the source code, an error we could have made ourselves if we hit the wrong key on our keyboard. This would currently go unnoticed, but we can fix that by adding a test like:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DescribeBottlesTest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testDescribes99BottlesByDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'99 bottles of beer on the wall'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;describeBottles&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Other untested aspects commonly found by Infection were exception messages and some uncovered paths through complex logic. I added tests or assertions for most of these. For the logic, this is also a sign that the (cyclomatic/N-path) complexity is too high. Those pieces of code should be refactored, but I scheduled that for later.&lt;/p&gt;

&lt;p&gt;On the first Infection run, without any changes to the test suite, it produced a 89% MSI. This is already quite good, but with some additions to the test suite I managed to raise the MSI to 93%.&lt;/p&gt;
&lt;h4&gt;
  
  
  ‘False positives’
&lt;/h4&gt;

&lt;p&gt;Getting the MSI much higher proved to be difficult though. Sometimes escaped mutants had changes to parts of the code that are nonessential details. In our view, these details do not constitute relevant behavior and are not part of the ‘contract’ of that unit. Why are they in the code then? Well, sometimes they have to be due to syntactical constraints. Take for example the following piece of code that may throw an exception:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$database&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;executeSql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DuplicateDatabaseKeyException&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserAlreadyExistsExeption&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"User &lt;/span&gt;&lt;span class="nv"&gt;$username&lt;/span&gt;&lt;span class="s2"&gt; already exists"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As explained in a previous blog post, we think it is important that exceptions are thrown at the right level of abstraction:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/moxio" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1760%2F86875fa8-476d-41a6-be56-ae1461f9d350.png" alt="Moxio"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F17944%2Fd423308c-04dd-470d-8ed4-4e731321b678.jpg" alt=""&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/moxio/best-practices-for-php-exception-handling-j5i" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Best practices for PHP exception handling&lt;/h2&gt;
      &lt;h3&gt;Arnout Boks for Moxio ・ Jan 10 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#php&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#exceptions&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#oop&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#softwaredesign&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;This requires catching and re-throwing exceptions like in the above code snippet. In that post, I also mentioned that we want to maintain the connection with the root cause by setting the &lt;code&gt;$previous&lt;/code&gt;-parameter of the new exception. Due to PHP's syntax this requires one to also provide the &lt;code&gt;$code&lt;/code&gt;-parameter, which we do not really use. We usually set it to &lt;code&gt;0&lt;/code&gt; (the default), but honestly couldn't care less about its value.&lt;/p&gt;

&lt;p&gt;Now the same &lt;code&gt;DecrementInteger&lt;/code&gt; mutator could come along and produce this mutation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;53) /tmp/exception.php:289   [M] DecrementInteger
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="gd"&gt;--- Original
&lt;/span&gt;&lt;span class="gi"&gt;+++ New
&lt;/span&gt;&lt;span class="p"&gt;@@ @@&lt;/span&gt;
  } catch (DuplicateDatabaseKeyException $e) {
&lt;span class="gd"&gt;-     throw new UserAlreadyExistsExeption("User $username already exists", 0, $e); 
&lt;/span&gt;&lt;span class="gi"&gt;+     throw new UserAlreadyExistsExeption("User $username already exists", -1, $e); 
&lt;/span&gt;  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This mutation will not get caught by our test suite (because we do not assert the code of produced exceptions), so the mutant will escape. In this case we do not care however. We don’t expect our test suite to detect this, as (to us) the mutated code is just as fine as the original. We could add assertions for the exception code, but that would just be extra work without yielding extra value.&lt;/p&gt;

&lt;p&gt;I think this is something to be aware of when doing mutation testing. Not all escaped mutants are necessarily bad. For each of them you have to ask yourself the question “Would it be bad if I made this ‘error’ in my code?”. If the answer is no, don’t bother about the escaped mutant.&lt;/p&gt;

&lt;h4&gt;
  
  
  What test to add?
&lt;/h4&gt;

&lt;p&gt;One of the main difficulties when trying to kill a mutant was figuring out what kind of test to add. Just from seeing a changed line in the code it is not always clear how to write a test that would fail on the given line. This was further amplified by the fact that the codebase I worked with was written by a colleague, and I did not know it inside out yet.&lt;/p&gt;

&lt;p&gt;I learned that the HTML code coverage report generated by PHPUnit can be of tremendous help here. If you hover over a covered line of code there, it shows you which tests cover that line. This way you can lookup which tests already exercise the mutated line of code. The test you want to add to kill the mutant is probably a variation of one of them. This reduces your problem to analyzing these ‘example’ tests and reasoning about what you could change in them to fail when the mutation is present.&lt;/p&gt;

&lt;h4&gt;
  
  
  It improves your code too
&lt;/h4&gt;

&lt;p&gt;Not only the test suite got some updates during my experiments with mutation testing; the production code improved as well. Sometimes the mutants generated by Infection were actually better than the original version! One such case looked somewhat like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;createWithInMemoryDatabase&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$database&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SqliteDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;':memory:'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Among the generated mutations there was one that removed the &lt;code&gt;$database ??&lt;/code&gt; null coalesce operator. This is actually an improvement, as the null coalesce operator is useless here! At the start of the function, &lt;code&gt;$database&lt;/code&gt; is always null, so the operator always resolves to its right-hand side, creating a new database. This code was an artifact from a moment when the method was named differently and allowed injecting a custom database through a &lt;code&gt;$database&lt;/code&gt; parameter. Now that parameter has been removed, we can get rid of the null coalesce as well. While other static analysis tools could have found this dead code as well, at least Infection brought it to our attention.&lt;/p&gt;

&lt;p&gt;Another example where the mutant turned out to be better was the removal of a &lt;code&gt;trim()&lt;/code&gt; function. At that spot in the code there could never be any significant or problematic whitespace. The &lt;code&gt;trim()&lt;/code&gt;-call thus was unnecessary and could be removed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Once you’ve had some practice with mutation testing, it can really help with improving both your test suite and code. Infection is straightforward to setup and use, and makes it fairly simple to get started in PHP. Just keep in mind that not all escaped mutants are a problem and blindly striving for 100% MSI does not add value. Try it out, and let me know what your experiences are!&lt;/p&gt;

</description>
      <category>php</category>
      <category>testing</category>
      <category>codequality</category>
      <category>learning</category>
    </item>
    <item>
      <title>Best practices for PHP exception handling</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Wed, 09 Jan 2019 23:00:00 +0000</pubDate>
      <link>https://dev.to/moxio/best-practices-for-php-exception-handling-j5i</link>
      <guid>https://dev.to/moxio/best-practices-for-php-exception-handling-j5i</guid>
      <description>&lt;p&gt;Handling errors or other non-’happy path’ situations is essential when creating robust PHP applications. While &lt;a href="http://php.net/manual/en/language.errors.php"&gt;errors&lt;/a&gt; were the main construct to do so in PHP 4, &lt;a href="http://php.net/manual/en/language.exceptions.php"&gt;exceptions&lt;/a&gt; have been around since PHP 5. They should nowadays be considered the main mechanism for handling alternative or exceptional paths. It seems that these alternative paths still don’t always get the attention they deserve, though.&lt;/p&gt;

&lt;p&gt;Proper exception handling takes quite some effort, but will eventually result in a much more stable application. A sensible exception handling strategy makes it clear what exceptions should be expected (and thus handled!) at a given point in the code. Moreover it will maintain the encapsulation and abstraction you carefully applied to your object-oriented design. Last but not least, it should make debugging a breeze.&lt;/p&gt;

&lt;p&gt;In this post, I would like to introduce you to the set of best practices we have adopted at &lt;a href="https://www.moxio.com/home"&gt;Moxio&lt;/a&gt; over the years. We have found these to work very well for us, but keep in mind that they are &lt;em&gt;our&lt;/em&gt; best practices; your mileage may vary. The following guidelines are aimed at PHP code, but the basic principles behind them will also (with some translations) work for similar languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Types of exceptions
&lt;/h3&gt;

&lt;p&gt;We make a distinction between the two top-level types of exceptions that the PHP &lt;a href="http://php.net/manual/en/book.spl.php"&gt;SPL library&lt;/a&gt; defines. These are &lt;a href="http://php.net/manual/en/class.logicexception.php"&gt;&lt;code&gt;LogicException&lt;/code&gt;&lt;/a&gt; and &lt;a href="http://php.net/manual/en/class.runtimeexception.php"&gt;&lt;code&gt;RuntimeException&lt;/code&gt;&lt;/a&gt;. The interpretation of these two types in literature varies. We however attach the following meaning to them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;LogicException&lt;/code&gt; is an exception that should require a fix or change in code. With 'code' we do not only mean source code, but any content managed by a developer. This includes configuration and database contents that are not maintained by an end user of the system. A &lt;code&gt;LogicException&lt;/code&gt; is mainly an internal guard or assertion. In perfectly written and wired code one should never occur.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;RuntimeException&lt;/code&gt; is an exception that might also occur in code that is written and configured 'perfectly'. Such an exception may be caused by input from the end user, or an error in (the communication with) an external system. When a &lt;code&gt;RuntimeException&lt;/code&gt; is thrown, it should not require a fix in the code. If the exception ends up uncaught however, we should add some code to handle it. This may mean logging the error, using a fallback strategy, reporting the error to the user, or a combination thereof.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that this interpretation differs from the generic perception in Java, where a &lt;code&gt;RuntimeException&lt;/code&gt; is what we would call a &lt;code&gt;LogicException&lt;/code&gt;. Furthermore, in our standards we classify all exceptions into either one of these categories. We do not create exceptions as a direct subclass of &lt;code&gt;Exception&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exceptions as part of the function signature
&lt;/h3&gt;

&lt;p&gt;We see the possible variants of &lt;code&gt;RuntimeException&lt;/code&gt; that can be thrown or bubbled up from a function as part of the contract of that function. That means such exceptions should be annotated on the function using &lt;code&gt;@throws&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If the function is part of the implementation of an interface, that interface should specify that (a supertype of) the exception in case could be thrown. Annotating such an exception also on the implementation is not necessary. A function that implements an interface should never throw a runtime exception not declared on the interface. Such a case would be a violation of the &lt;a href="https://www.tomdalling.com/blog/software-design/solid-class-design-the-liskov-substitution-principle/"&gt;Liskov Substitution Principle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the contrary, we consider the different types of &lt;code&gt;LogicException&lt;/code&gt; to not be part of the contract of a function. Of course we assume a perfect implementation, but at the same time we know there can always be an error somewhere. Therefore a &lt;code&gt;LogicException&lt;/code&gt; can always be expected and unexpected at the same time. Hence annotating it using &lt;code&gt;@throws&lt;/code&gt; is not desirable. See also 'catching exceptions' below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating exception subclasses
&lt;/h3&gt;

&lt;p&gt;Under these guidelines, creating a hierarchy of subtypes under &lt;code&gt;RuntimeException&lt;/code&gt; is very desirable. The more specific the exceptions we throw (and annotate as part of our contract), the more granular we can handle them. Subclasses of &lt;code&gt;LogicException&lt;/code&gt; however are not necessary. These are not part of the contract of a function anyway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Catching exceptions
&lt;/h3&gt;

&lt;p&gt;To us, a &lt;code&gt;RuntimeException&lt;/code&gt; is a &lt;em&gt;checked&lt;/em&gt; exception. When such an exception can be thrown from a function, the calling function needs to either catch that exception or declare it as a possible exception from itself using &lt;code&gt;@throws&lt;/code&gt;. Catching a runtime exception is a good idea when the calling code can sensibly handle the exception, or when it can re-throw it at a better level of abstraction (see &lt;a href="https://www.moxio.com/blog/34/best-practices-for-php-exception-handling#rethrowing"&gt;further down&lt;/a&gt;). At least it is important to think about the handling of these exceptions when calling a function that might throw them.&lt;/p&gt;

&lt;p&gt;A logic exception should never be caught, at least not based on the type &lt;code&gt;LogicException&lt;/code&gt; or a subclass thereof. These exceptions should never occur in a correct implementation. It therefore does not make sense to try to handle them along the line. Instead, the logic that triggered the exception should be fixed.&lt;/p&gt;

&lt;p&gt;At some point it may be necessary to catch &lt;em&gt;all&lt;/em&gt; exceptions, including both variants of &lt;code&gt;RuntimeException&lt;/code&gt; and &lt;code&gt;LogicException&lt;/code&gt;. As we require PHP 7 at minimum, we do this using &lt;code&gt;Throwable&lt;/code&gt; in our &lt;code&gt;catch&lt;/code&gt;-clause, not &lt;code&gt;Exception&lt;/code&gt;. Constructs like this are exclusively meant for component entry points, and should never make assumptions about the specific cause or character of the exception. Such code will therefore never contain specific error handling logic. Instead, they are a generic catch-all for logging or reporting the error, or giving the end user feedback that something went wrong.&lt;/p&gt;

&lt;p&gt;Sometimes a catch-all like this is also used for cleaning up resources or closing open connections. A &lt;code&gt;finally&lt;/code&gt;-block is often better in such situations, especially if the exception is re-thrown at the end of the catch-block.&lt;/p&gt;

&lt;h4&gt;
  
  
  Special case: debug info
&lt;/h4&gt;

&lt;p&gt;One valid reason to catch a &lt;code&gt;LogicException&lt;/code&gt; anyway is to augment it with extra debugging information that was not available deeper in the call stack. In such a case we directly throw a new &lt;code&gt;LogicException&lt;/code&gt; with the extra data, and the original exception in &lt;code&gt;$previous&lt;/code&gt;. We preferably catch such an exception based on the most generic type possible. This may be a common base class or &lt;em&gt;marker interface&lt;/em&gt; for all &lt;code&gt;LogicException&lt;/code&gt;s that can occur in the given piece of code.&lt;/p&gt;

&lt;p&gt;The alternative for such a catch would be to pass the debug information on to the callees that eventually produce the error. We prefer not to do so if such information is only used for passing it into an exception.&lt;/p&gt;

&lt;h3&gt;
  
  
  Throwing a new exception after catching
&lt;/h3&gt;

&lt;p&gt;After catching an exception, it is of course possible to throw a new exception. Indeed, for sensible exception handling this is needed more than one may expect. Just make to always set the &lt;code&gt;$previous&lt;/code&gt;-parameter of the new exception to the original (caught) exception. This ensures the the full cause of the exception can still be derived. Because of the order of the &lt;code&gt;Exception&lt;/code&gt; constructor parameters it is then often necessary to specify a &lt;code&gt;$code&lt;/code&gt;. We don't use this parameter, so we just set it to &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Translation to the correct level of abstraction
&lt;/h4&gt;

&lt;p&gt;Catching-and-throwing is often necessary to ensure that an exception manifests itself at a suitable level of abstraction. Suppose we have a &lt;code&gt;UserRepositoryInterface&lt;/code&gt; that is implemented by a &lt;code&gt;DatabaseUserRepository&lt;/code&gt;. The latter stores users in the database, which raises a &lt;code&gt;DuplicateDatabaseKeyException&lt;/code&gt; if a user with the given username already exists. According to the rules described earlier we should use &lt;code&gt;@throws&lt;/code&gt; to annotate this exception on the interface, but that rightly feels a bit strange. Why would a generic interface, meant to abstract the storage mechanism away, know about a type of exception specific to a database? The solution is to catch the &lt;code&gt;DuplicateDatabaseKeyException&lt;/code&gt; within &lt;code&gt;DatabaseUserRepository&lt;/code&gt; and throw something like a &lt;code&gt;UserAlreadyExistsExeption&lt;/code&gt; in its place. This exception matches the level of abstraction of &lt;code&gt;UserRepositoryInterface&lt;/code&gt;: it knows about users, but not how they are persisted. It can therefore added to the signature of that interface without issues.&lt;/p&gt;

&lt;h4&gt;
  
  
  From &lt;code&gt;RuntimeException&lt;/code&gt; to &lt;code&gt;LogicException&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;It is very well possible that an exception that was a &lt;code&gt;RuntimeException&lt;/code&gt; is at some point converted into a &lt;code&gt;LogicException&lt;/code&gt;. This has to do with specific knowledge we have at that point, from which we know that the given exception should not be possible. That knowledge was not available deeper in the &lt;em&gt;call stack&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;To illustrate this, assume we have an XML reader with a method &lt;code&gt;getUniqueTagContents&lt;/code&gt;. This method reads the contents of one unique tag from an XML file based on the tag name. A lot of things can go wrong inside such a method: the XML file may be malformed, the given tag may not be present, or it may occur multiple times. These are all examples of a &lt;code&gt;RuntimeException&lt;/code&gt;. Without extra knowledge about the origin of the XML (which may be uploaded by a user) and the tag name they can also occur in a perfectly programmed application. But it is possible that we use this method on a piece of XML that we just validated against an XML schema that enforces the existence and unicity of the given tag. In such a situation we know that &lt;code&gt;getUniqueTagContents&lt;/code&gt; should not fail. The same applies when we use the method to read a configuration file that we put in VCS ourselves and which we thus fully control.&lt;/p&gt;

&lt;p&gt;In such situations we still have to catch the ‘impossible’ runtime exceptions, as we consider them &lt;em&gt;checked&lt;/em&gt;. In this &lt;code&gt;catch&lt;/code&gt;-block we then throw a &lt;code&gt;LogicException&lt;/code&gt;: this situation should never happen. Of course we save the original exception through the &lt;code&gt;$previous&lt;/code&gt; parameter.&lt;/p&gt;

&lt;p&gt;This is a pattern that occurs often. Deep in the &lt;em&gt;call stack&lt;/em&gt;, where the bigger picture is not available, many faults are a RuntimeException. As the exception bubbles up (whether translated to another level of abstraction or not), it reaches a point where we know the error should be impossible. At that point it becomes a LogicException. Note that the inverse is not possible: an unexpected error can not suddenly be expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  A grey area
&lt;/h3&gt;

&lt;p&gt;The distinction between a &lt;code&gt;RuntimeException&lt;/code&gt; and a &lt;code&gt;LogicException&lt;/code&gt; is not always 100% clear. There is a grey area where the correct type of exception depends on interpretation and the semantic constract of a function. A few examples to illustrate this:&lt;/p&gt;

&lt;h4&gt;
  
  
  Syntax error in a query
&lt;/h4&gt;

&lt;p&gt;A method &lt;code&gt;executeQuery&lt;/code&gt; to execute a database query can fail due a syntax error in that query. A first sight this looks like a &lt;code&gt;RuntimeException&lt;/code&gt;: we don't know where the query comes from and thus cannot guarantee its syntactical correctness. On the other hand it would be very strange if user input (or input from another source beyond our control) could lead to a syntax error. That smells of SQL injection. It is therefore very reasonable to state that the code calling &lt;code&gt;executeQuery&lt;/code&gt; is responsible for the syntactical correctness of the query. That makes the exception a &lt;code&gt;LogicException&lt;/code&gt;. An exemption would be if we were building an application like &lt;a href="https://www.adminer.org/"&gt;adminer&lt;/a&gt; or &lt;a href="https://www.phpmyadmin.net/"&gt;phpMyAdmin&lt;/a&gt; where we should expect errors in user-entered SQL queries.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cache item not found
&lt;/h4&gt;

&lt;p&gt;Suppose we have a cache class with a method &lt;code&gt;get($key)&lt;/code&gt; to retrieve a cache item. Of course it can happen that get is called with a key that does not exist. We assume that we have chose to communicate this via an exception (alternatives would be through the return value or a by-reference parameter). Would such an exception be a runtime or a logic exception?&lt;/p&gt;

&lt;p&gt;The answer probably depends on the other methods on the cache class and how we expect to use these. If the cache has a &lt;code&gt;has&lt;/code&gt; method we could demand that a consumer uses that method to check whether a cache item exists before retrieving it with get. In that case a &lt;code&gt;LogicException&lt;/code&gt; is reasonable. Depending on the implementation of the cache there may be a tiny chance that a cache item is deleted between the calls to &lt;code&gt;has&lt;/code&gt; and &lt;code&gt;get&lt;/code&gt;. In such cases even a perfect implementation (which checks existence first) cannot fully prevent the error. The 'correct' exception category is not very clear here. For now we tend to use a &lt;code&gt;LogicException&lt;/code&gt; for situations with rare edge cases like this.&lt;/p&gt;

&lt;h4&gt;
  
  
  Corrupt data in the database
&lt;/h4&gt;

&lt;p&gt;Another grey area is formed by errors that can only occur in case of a corrupted database. From a puristic view this is an example of a &lt;code&gt;RuntimeException&lt;/code&gt;, the database being an external factor. On the other side it is undesirable to have to take the possibility of database corruption into account everywhere in the code. This applies all the more if only the application and occasionally a developer or sysadmin writes to the database. A more pragmatic approach is to consider database corruption a &lt;code&gt;LogicException&lt;/code&gt;. Chances are that the corrupt data was caused by an implementation error in the application. Anyway, developer or sysadmin intervention is required to manually fix the data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recap
&lt;/h3&gt;

&lt;p&gt;We distinguish checked exceptions that represent inherently ‘unfixable’ situations from unchecked exceptions that represent programming errors. Therefore we know at every point in the code what exceptions we should expect, and thus handle. By catching and re-throwing exceptions we make sure that they are at the proper level of abstraction and thus not break encapsulation. Chaining the original exception using the &lt;code&gt;$previous&lt;/code&gt; parameter ensures that no debugging information is lost.&lt;/p&gt;

&lt;p&gt;Are you trying out these practices in your project? &lt;a href="https://twitter.com/moxio"&gt;Let us know&lt;/a&gt; if they work for you, if there are obstacles you run into, or if you have improvements to these guidelines. We’d love to get your feedback!&lt;/p&gt;

</description>
      <category>php</category>
      <category>exceptions</category>
      <category>oop</category>
      <category>softwaredesign</category>
    </item>
    <item>
      <title>Start testing with PHPT tests in PHPUnit</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Wed, 20 Jun 2018 22:00:00 +0000</pubDate>
      <link>https://dev.to/moxio/start-testing-with-phpt-tests-in-phpunit-2jpg</link>
      <guid>https://dev.to/moxio/start-testing-with-phpt-tests-in-phpunit-2jpg</guid>
      <description>&lt;p&gt;Over the years, automated testing has become an established practice in software development. It thus has also become an essential skill to learn for any developer. In the past few months, I have talked to several developers who had recently started with testing in PHP. Some of them expressed they found their testing framework of choice (often &lt;a href="https://phpunit.de/"&gt;PHPUnit&lt;/a&gt;) quite difficult to get started with.&lt;/p&gt;

&lt;p&gt;In a sense, this is not surprising. Getting started with testing is already challenging on its own. You have to choose units to test and learn to write testable code. You must learn to distinguish essential behavior from implementation details. At the same time you have to get to know your testing framework. Most popular and mature testing tools need quite some boilerplate and background knowledge. This adds to the already steep learning curve. As people learn best by tackling one step at a time, this is not ideal. It would be much better if we had an easy testing framework that juniors can use to learn the basics of testing without the extra overhead.&lt;/p&gt;

&lt;h3&gt;
  
  
  PHPT tests
&lt;/h3&gt;

&lt;p&gt;Enter PHPT tests. Through work on some small bug fixes in the PHP core (and &lt;a href="https://speakerdeck.com/aboks/getting-started-with-php-core-development-php-serbia-2018"&gt;speaking about that&lt;/a&gt;) I learned about the PHPT test format. This is the test format used for testing the PHP interpreter itself. It is straightforward and simple to get into. The main idea is that a test contains a PHP script that prints output, and the output expected from that script. An elementary PHPT test would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;--TEST--
Basic arithmetic - addition
--FILE--
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; &lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
--EXPECT--
int(43)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;--TEST--&lt;/code&gt; section provides a short description about what the test aims to test. The &lt;code&gt;--FILE--&lt;/code&gt; section contains a script that prints some output. In this case we output the result of adding two integers. After &lt;code&gt;--EXPECT--&lt;/code&gt; comes the output we expect from the &lt;code&gt;--FILE--&lt;/code&gt; section.&lt;/p&gt;

&lt;p&gt;Note that we use &lt;code&gt;var_dump&lt;/code&gt; for outputting the result value. If we would use echo or print the output would be just &lt;code&gt;43&lt;/code&gt;. In that case we would not know whether that was the integer 43 or the string “43”. That makes us unable to verify that the result is of the correct type. Therefore we prefer &lt;code&gt;var_dump&lt;/code&gt;: it shows the type of the value.&lt;/p&gt;

&lt;p&gt;The PHPT test format is not feature-rich. Still it supports all the constructs necessary to write sensible tests. You can use them by adding these sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--EXPECTF--&lt;/code&gt;, &lt;code&gt;--EXPECTREGEX--&lt;/code&gt;: Instead of specifying the exact desired output with &lt;code&gt;--EXPECT--&lt;/code&gt;, one can specify a pattern for the expected output. This pattern can be provided either as a printf-like string or a regular expression.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--SKIP--&lt;/code&gt;: You can add this section to describe when a test should be skipped. This can be used to check for a specific platform or the presence of a required PHP extension.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--CLEAN--&lt;/code&gt;: When the test creates some temporary artifacts (like files on disk) the code in this section can clean them up.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--INI--&lt;/code&gt;, &lt;code&gt;--ENV--&lt;/code&gt;: Sometimes a test needs to run with specific settings like php.ini directives or environment variables. You can specify those settings in these two blocks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More information about the PHPT test structure can be found on the &lt;a href="https://qa.php.net/phpt_details.php"&gt;website of the PHP QA team&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning to test with PHPT
&lt;/h3&gt;

&lt;p&gt;When learning to test, we can see the frugal feature set of PHPT as an advantage. It allows one to focus on learning the concepts of testing and testability without getting lost in features of a specific testing framework. These features are useful for developers that are already accustomed to testing. Still it is better to build understanding of how they work under the hood first. In fact, juniors will probably find a way to emulate them in a ‘naive’ way using concepts they already know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want to test that a function throws an exception? Use a &lt;code&gt;try&lt;/code&gt;-&lt;code&gt;catch&lt;/code&gt;. No need for &lt;code&gt;expectException()&lt;/code&gt; yet.&lt;/li&gt;
&lt;li&gt;Have multiple tests that look similar, but with different data? Put them in a &lt;code&gt;for&lt;/code&gt;- or &lt;code&gt;foreach&lt;/code&gt;-loop. This paves the way for a data provider later on.&lt;/li&gt;
&lt;li&gt;Sharing some initialization logic between tests? Move it to a function. Later on such a function can become a &lt;code&gt;setUp&lt;/code&gt;-method.&lt;/li&gt;
&lt;li&gt;Need a test double? Create a dummy implementation within the test yourself. This helps to learn what a mocking library does under the hood. It also encourages to keep interfaces small and method chains short. Patterns for the different types of test doubles will emerge more naturally. We don’t have them all coming from &lt;code&gt;createMock()&lt;/code&gt; anymore. This helps juniors to learn how e.g. a stub differs from a mock.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a bonus, PHPT tests make it easy to write &lt;a href="https://michaelfeathers.silvrback.com/characterization-testing"&gt;characterisation tests&lt;/a&gt;. Take any code fragment that exercises the system under test in some way and put it in the test. Then run it to get the current output and register that as the expected output. This strategy provides a great opportunity to learn how one can use characterisation tests as an aid to refactor legacy code. It also teaches how they are brittle and should eventually be replaced by tests that properly specify desired behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using PHPT tests with PHPUnit
&lt;/h3&gt;

&lt;p&gt;One little-known feature of PHPUnit is that it actually has built-in support for PHPT tests out of the box. All we have to do to enable this is to add a directory with the &lt;code&gt;.phpt&lt;/code&gt; suffix to the &lt;code&gt;phpunit.xml&lt;/code&gt; configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;phpunit&lt;/span&gt; &lt;span class="na"&gt;bootstrap=&lt;/span&gt;&lt;span class="s"&gt;"vendor/autoload.php"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;testsuites&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;testsuite&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"My Test Suite"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
            &lt;span class="c"&gt;&amp;lt;!-- (line below added) --&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;directory&lt;/span&gt; &lt;span class="na"&gt;suffix=&lt;/span&gt;&lt;span class="s"&gt;".phpt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/testsuite&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/testsuites&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/phpunit&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we have done so, PHPUnit will also look for &lt;code&gt;.phpt&lt;/code&gt; files in the &lt;code&gt;test&lt;/code&gt; directory, and execute them as PHPT tests. With this configuration we can start mixing ‘normal’ PHPUnit tests and PHPT tests. Still we can run them as if there were no difference. We just support both test formats side-by-side without any extra infrastructure or tooling.&lt;/p&gt;

&lt;p&gt;This means developers experienced with testing can still write their usual PHPUnit tests. Developers that have recently started out with testing now have a simpler way of writing tests though. Instead of the following test from the &lt;a href="https://phpunit.readthedocs.io/en/7.1/writing-tests-for-phpunit.html"&gt;PHPUnit manual&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PHPUnit\Framework\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StackTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testPushAndPop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nb"&gt;array_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;array_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you can write this equivalent PHPT test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;--TEST--
Array as a stack
--FILE--
&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="nv"&gt;$stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nb"&gt;array_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;array_pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stack&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; 
&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
--EXPECT--
int(0)
string(3) "foo"
int(1)
string(3) "foo"
int(0)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the differences in boilerplate/prerequisites to understand the two tests. For the PHPUnit test one needs to know about the PHPUnit &lt;code&gt;TestCase&lt;/code&gt; class and have a basic understanding of OOP. Also you have to know that methods starting with &lt;code&gt;test&lt;/code&gt; are invoked by the PHPUnit test runner. Lastly, you need to be able to pick the appropriate assertion method.&lt;br&gt;&lt;br&gt;
 With the PHPT test juniors can take any existing snippet of PHP code that produces some output and turn it into an automated test. They might already use such a script for manual testing. Now they can convert it to a test that runs with the rest of the testsuite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;p&gt;Of course, most of us do not write tests using PHPT, but use a framework like PHPUnit, &lt;a href="https://www.phpspec.net/"&gt;phpspec&lt;/a&gt; or &lt;a href="http://atoum.org/"&gt;atoum&lt;/a&gt;. There are good reasons for that. Using the PHPT format and running it with PHPUnit has some serious limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Features. Most test frameworks have several helpful features built-in. These help to reduce the amount of code to write for certain tests or clarify why certain tests failed. Think of data providers and integration with mocking libraries. But there are also test dependencies, ways of expecting exceptions and specialized assertion methods. We have discussed that most of these can be ‘emulated’ in tests themselves. Still, having these in our test framework reduces the amount of boilerplate we need to write. It makes experienced testers much more productive.&lt;/li&gt;
&lt;li&gt;IDE support. There is no real support for PHPT tests in most IDE’s. With proper file associations the code between &lt;code&gt;&amp;lt;?php ?&amp;gt;&lt;/code&gt; tags is usually still highlighted. The PHPT sections will not be, though. Additionally, I don’t know of any IDE that can quickly run a single &lt;code&gt;.phpt&lt;/code&gt; file as a PHPT test from the editor.&lt;/li&gt;
&lt;li&gt;Unsupported sections. The PHPUnit test runner has only limited support for PHPT tests. &lt;a href="https://github.com/sebastianbergmann/phpunit/blob/f77161e67093f1bb8778ee5522e8c5e9ee0f4384/src/Runner/PhptTestCase.php#L338"&gt;Several PHPT sections&lt;/a&gt; are not supported by this runner, most of them related to simulating HTTP input.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I see no use in switching to PHPT tests if you are already experienced in writing tests. Still, using PHPT tests might be a nice way for less experienced developers to get started with testing. With little boilerplate and a small feature set, it helps them to focus on ways of testing and writing testable code. That is difficult enough in itself, and deserves their full attention. More advanced features and constructs will arise naturally and help to discover how a testing framework works under the hood.&lt;/p&gt;

&lt;p&gt;Most important: in PHPUnit, PHPT tests can be enabled alongside ‘normal’ tests with just a single line of configuration. Such a strategy provides a smooth upgrade path from basic PHPT tests to a more mature testing framework. It does not even require additional tooling. Help your developers to start testing, enable PHPT tests!&lt;/p&gt;




&lt;h5&gt;
  
  
  Enjoyed reading this post?
&lt;/h5&gt;

&lt;p&gt;My colleagues and I regularly write webdev-related blog posts like this to share the things we learn or discover. You can find all our posts on the &lt;a href="https://www.moxio.com/blog"&gt;Moxio blog&lt;/a&gt;. Get notified of new posts by following &lt;a href="https://twitter.com/arnoutboks"&gt;me&lt;/a&gt; or &lt;a href="https://twitter.com/moxio"&gt;Moxio&lt;/a&gt; on Twitter or by subscribing to our &lt;a href="https://www.moxio.com/rss/blog"&gt;RSS feed&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>beginners</category>
      <category>learning</category>
      <category>php</category>
      <category>testing</category>
    </item>
    <item>
      <title>Moving individual MySQL tables on disk</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Mon, 12 Feb 2018 23:00:00 +0000</pubDate>
      <link>https://dev.to/moxio/moving-individual-mysql-tables-on-disk-2j0a</link>
      <guid>https://dev.to/moxio/moving-individual-mysql-tables-on-disk-2j0a</guid>
      <description>&lt;p&gt;You may encounter the situation where you want to move one single MySQL database table to another (location on) disk, e.g. to free up disk space. It turns out that this process is far from straightforward. In this post I will describe several of our failed approaches (since failures are a great opportunity for learning), and the &lt;a href="https://www.moxio.com/blog/28/moving-individual-mysql-tables-on-disk#solution"&gt;solution&lt;/a&gt; we eventually came up with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why move tables on disk?
&lt;/h3&gt;

&lt;p&gt;A while ago we received an alert that disk space on one of our servers at Moxio was gradually running low. We constantly monitor our servers for factors that could threaten normal operation, and receive a first alert when the free disk space drops below 30% of the total disk size. In that way we still have plenty of time to act upon it before the disk is actually full.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---JfKyzyo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/823/0%2A1K_X4cy158Bclsjb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---JfKyzyo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/823/0%2A1K_X4cy158Bclsjb.png" alt="Graph of free disk space before moving tables"&gt;&lt;/a&gt;Graph of free disk space before moving tables&lt;/p&gt;

&lt;p&gt;Usually in such situations we could free up sufficient disk space by deleting old backups and temporary files, or moving certain file storage directories off the main hard drive to an external storage array. This time almost all disk space was taken by the MySQL database server however. Some tables had been growing steadily over time, eating up more and more disk space. Since this was data we had to keep, our only sustainable solution was to move these tables to another disk.&lt;/p&gt;

&lt;h3&gt;
  
  
  The desired situation
&lt;/h3&gt;

&lt;p&gt;Our ideal solution would be to move only the large individual tables to the external storage array. With that approach we could keep the other tables in the database on the (much faster) SSD disk, not sacrificing performance unnecessarily. So is this even possible with MySQL?&lt;/p&gt;

&lt;p&gt;Historically, MySQL used to store all table data and indices in the &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_system_tablespace"&gt;&lt;em&gt;system tablespace&lt;/em&gt;&lt;/a&gt;, represented by one or more &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_ibdata_file"&gt;ibdata files&lt;/a&gt; on disk. This means that data from multiple databases and tables was stored in the same file, making it impossible to move one of them to another location. Then MySQL 4.1.1 introduced &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-multiple-tablespaces.html"&gt;file-per-table tablespaces&lt;/a&gt; for InnoDB with the &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_file_per_table"&gt;innodb_file_per_table&lt;/a&gt; setting, which would store data and indices for newly created tables in a separate &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_ibd_file"&gt;.ibd file&lt;/a&gt; per table. This setting became enabled by default in MySQL 5.6.6.&lt;/p&gt;

&lt;p&gt;When using file-per-table tablespaces, it is possible to use the DATA DIRECTORY = 'path' clause with CREATE TABLE to &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/tablespace-placing.html"&gt;place the data for the table outside the main MySQL data directory&lt;/a&gt; as of MySQL 5.6. This means that a setup as desired would be technically possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Failed approaches
&lt;/h3&gt;

&lt;p&gt;In our case we were dealing with existing tables however. We tried several unsuccessful approaches to move these to another directory before eventually finding a satisfying solution.&lt;/p&gt;

&lt;h4&gt;
  
  
  Changing the data directory after creation
&lt;/h4&gt;

&lt;p&gt;Since a DATA DIRECTORY can be specified to change a table’s storage location when creating the table, it seems logical that it would also be possible to change this location after creation by using this same option with ALTER TABLE. Indeed, ALTER TABLE &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/alter-table.html"&gt;syntactically&lt;/a&gt; supports DATA DIRECTORY as a table option. The documentation explicitly states however that this option &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/alter-table.html#alter-table-options"&gt;is ignored&lt;/a&gt; (except when partitioning). It thus seems impossible to change DATA DIRECTORY for an existing table.&lt;/p&gt;

&lt;h4&gt;
  
  
  Symlinking the data files
&lt;/h4&gt;

&lt;p&gt;Another approach we came up with was manually moving the table’s data files to the other disk, symlinking them back to their original location inside MySQL’s main data directory. According to the documentation however, although MySQL supports symlinking &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/symbolic-links-to-databases.html"&gt;entire database directories&lt;/a&gt; or &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/symbolic-links-to-tables.html"&gt;individual MyISAM tables&lt;/a&gt;, using symbolic links to InnoDB tables &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/symbolic-links-to-tables.html"&gt;is not supported&lt;/a&gt; and may cause strange problems.&lt;/p&gt;

&lt;h4&gt;
  
  
  Creating a copy in the desired location
&lt;/h4&gt;

&lt;p&gt;Since DATA DIRECTORY can only be specified when creating a table, we also tried creating a copy of the table in the desired location, copying over all data from the old table to the new copy and renaming the new table to take the place of the old one. This would look somewhat like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`table_name`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This returns the CREATE TABLE statement that would create the table structure of table_name. We now execute that exact statement, but substitute a new table name and append a DATA DIRECTORY clause:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`table_name_new`&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt; &lt;span class="n"&gt;DIRECTORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/path/to/desired/location'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have an empty copy of table_name, in schema that is. We then copy all data over from the existing table to the new one and issue an &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/rename-table.html"&gt;atomic rename&lt;/a&gt; to swap the two tables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="nv"&gt;`table_name_new`&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`table_name`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;RENAME&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`table_name`&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="nv"&gt;`table_name_old`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`table_name_new`&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="nv"&gt;`table_name`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we ran into problems however. When running the INSERT INTO ... SELECT query, MySQL failed with the error message&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR 1206 (HY000): The total number of locks exceeds the lock table size
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It turns out that when using INSERT INTO ... SELECT, MySQL needs to &lt;a href="https://www.percona.com/blog/2006/07/12/insert-into-select-performance-with-innodb-tables/"&gt;set locks on the rows read&lt;/a&gt; from the source table to ensure proper replication. These locks take up space in the &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool.html"&gt;InnoDB buffer pool&lt;/a&gt;. The size of this pool is configurable using &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_buffer_pool_size"&gt;innodb_buffer_pool_size&lt;/a&gt;, but set to 128 MB by default. Since the table we’re trying to move is quite large (more than 50 million rows), MySQL is bound to run out of its space for holding locks.&lt;/p&gt;

&lt;p&gt;Even if we could sufficiently increase innodb_buffer_pool_size to make this work, this approach is quite inefficient once you think about it. When inserting data into the new copy, MySQL has to serialize the data to disk and build indices for it, which takes a lot of time. We already have the serialized data and indices however: they’re right there for the original table! Instead of letting MySQL recreate the entire index and data file from scratch, we should look for a way to re-use the table data that is already there.&lt;/p&gt;

&lt;h3&gt;
  
  
  The solution
&lt;/h3&gt;

&lt;p&gt;Eventually we found a solution for smoothly moving tables on disk, based on a guide for copying tablespaces to another MySQL instance &lt;a href="https://dev.mysql.com/doc/refman/5.7/en/tablespace-copying.html"&gt;in the MySQL manual&lt;/a&gt;. The solution comes down to moving the existing tablespace on disk, dropping and re-creating the table with the desired DATA DIRECTORY, and then re-attaching the saved tablespace to the new table.&lt;/p&gt;

&lt;p&gt;Step-by-step, this looks as follows. First we ensure that all data is flushed from MySQL’s caches and buffers to the tablespace on disk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;FLUSH&lt;/span&gt; &lt;span class="n"&gt;TABLES&lt;/span&gt; &lt;span class="nv"&gt;`table_name`&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;EXPORT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FLUSH TABLES also locks the table for the duration of the connection or until we unlock it. The lock ensures the data in the table cannot change while we are moving the files. To maintain these locks we should keep open the MySQL connection in which we ran FLUSH TABLES .... In a new terminal window we move the tablespace files to a temporary location. In this case we use our home directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mv&lt;/span&gt; /var/lib/mysql/database_name/table_name.&lt;span class="o"&gt;{&lt;/span&gt;ibd,cfg&lt;span class="o"&gt;}&lt;/span&gt; ~
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now returning to our open MySQL session, we can release the locks (the tablespace has been safely put away in a consistent state), drop and re-create the table in its desired location:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;UNLOCK&lt;/span&gt; &lt;span class="n"&gt;TABLES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`table_name`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`table_name`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`table_name`&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt; &lt;span class="n"&gt;DIRECTORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'/path/to/desired/location'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will also create fresh tablespace files on disk (in the desired location) for the newly created table. We do not want these (because we want to put back our old tablespace files), so we discard this new tablespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`table_name`&lt;/span&gt; &lt;span class="n"&gt;DISCARD&lt;/span&gt; &lt;span class="n"&gt;TABLESPACE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this moment we can copy the saved original tablespace files to the location where MySQL now expects them, making sure to preserve ownership and permissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; ~/table_name.&lt;span class="o"&gt;{&lt;/span&gt;ibd,cfg&lt;span class="o"&gt;}&lt;/span&gt; /path/to/desired/location
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final step is to let MySQL import the original tablespace files back from disk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;`table_name`&lt;/span&gt; &lt;span class="n"&gt;IMPORT&lt;/span&gt; &lt;span class="n"&gt;TABLESPACE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Except for copying the tablespace files to the other disk, this whole process is very fast, as MySQL just takes the original table data and indices and does not have to rebuild these.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recap
&lt;/h3&gt;

&lt;p&gt;After several failed attempts (in which we did learn a lot about MySQL internals though), we eventually found a solution for efficiently moving tables to another location on disk. Using this approach we moved some of our largest and fastest-growing tables to an external storage array, freeing up the diskspace necessary to keep our server going.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vSxwuDxM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/828/0%2AIDJHzccNPmcY6iFG.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vSxwuDxM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/828/0%2AIDJHzccNPmcY6iFG.png" alt="Graph of free disk space after moving tables"&gt;&lt;/a&gt;Graph of free disk space after moving tables&lt;/p&gt;

&lt;p&gt;Another thing to remember: if you know that a database table will become large, plan its location on disk in advance. When creating the table, specifying a custom location on disk (using DATA DIRECTORY) is simple and saves you the hassle of the process described in this post down the road.&lt;/p&gt;




&lt;h5&gt;
  
  
  Enjoyed reading this post?
&lt;/h5&gt;

&lt;p&gt;My colleagues and I regularly write webdev-related blog posts like this to share the things we learn or discover. You can find all our posts on the &lt;a href="https://www.moxio.com/blog"&gt;Moxio blog&lt;/a&gt;. Get notified of new posts by following &lt;a href="https://twitter.com/arnoutboks"&gt;me&lt;/a&gt; or &lt;a href="https://twitter.com/moxio"&gt;Moxio&lt;/a&gt; on Twitter or by subscribing to our &lt;a href="https://www.moxio.com/rss/blog"&gt;RSS feed&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>sql</category>
      <category>mysql</category>
      <category>devops</category>
      <category>database</category>
    </item>
    <item>
      <title>PHP Central Europe conference 2017</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Mon, 18 Dec 2017 19:36:44 +0000</pubDate>
      <link>https://dev.to/moxio/php-central-europe-conference-2017-2j7</link>
      <guid>https://dev.to/moxio/php-central-europe-conference-2017-2j7</guid>
      <description>&lt;p&gt;Early November I attended the first edition of &lt;a href="https://2017.phpce.eu/"&gt;phpCE&lt;/a&gt;, a new PHP community conference in Central Europe, originating from a merger between PHPCon Poland and Brno PHP conference. In this blog post I would like to share some of my experiences and things I have learned during that event, in terms of interesting content, delivering two talks myself, and interactions with the community.&lt;/p&gt;

&lt;h2&gt;
  
  
  Content
&lt;/h2&gt;

&lt;p&gt;A conference is nothing without great content, and phpCE surely lived up to its expectations. Of course I cannot describe everything I've learned in a single blog post, but there were certainly some personal highlights I'd like to share.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/heiglandreas"&gt;Andreas Heigl&lt;/a&gt; kicked off the conference with his keynote '&lt;a href="https://joind.in/event/php-central-europe-conference/how-to-get-the-most-out-of-a-tech-conference"&gt;How to get the most out of a tech conference!&lt;/a&gt;', containing some practical tips for both first-time as well as seasoned conference visitors. Not only did he give advice for attending talks, but also for social interactions in the &lt;em&gt;hallway track&lt;/em&gt; (including the &lt;a href="http://ericholscher.com/blog/2017/aug/2/pacman-rule-conferences/"&gt;Pac-Man rule&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/s_bergmann"&gt;Sebastian Bergmann&lt;/a&gt; presented '&lt;a href="https://joind.in/event/php-central-europe-conference/domain-specific-assertions"&gt;Domain-Specific Assertions&lt;/a&gt;', about how using the ubiqitous language of the domain in PHPUnit assertions can help to make them more understandable to your coworkers, your future self, and even non-developers. His talk wasn't actually limited to assertions, making a plea for understandable programs (and against the term 'code') in general.&lt;/p&gt;

&lt;p&gt;In '&lt;a href="https://joind.in/event/php-central-europe-conference/the-gdpr-is-coming-are-you-ready"&gt;The GDPR is coming, are you ready?&lt;/a&gt;', &lt;a href="https://twitter.com/DragonBe"&gt;Michelangelo van Dam&lt;/a&gt; talked about the General Data Protection Regulation from the EU, which will be effective as of May 25, 2018. As this topic had not received that much attention in the Netherlands yet (as far as I know), for me this talk really was an eye-opener to start reading up on it and taking measures. Michelangelo's talk already contained a lot of practical hints for implementing compliant systems.&lt;/p&gt;

&lt;p&gt;Another really interesting session was &lt;a href="https://twitter.com/nikolaposa"&gt;Nikola Poša&lt;/a&gt; talking about best practices for exception handling in '&lt;a href="https://joind.in/event/php-central-europe-conference/journey-through-unhappy-path---dealing-with-exceptional-conditions"&gt;Journey through "unhappy path"&lt;/a&gt;'. I actually wasn't able to attend this talk myself (due to speaking at the same time), but I heard a lot of really positive reactions and talked a bit with Nikola about this subject afterwards. We really value well-designed exception handling at Moxio (especially with &lt;a href="https://www.moxio.com/blog/14/understanding-exceptional-flow"&gt;the research Tom has done in his thesis project&lt;/a&gt;), so it's nice to see this topic getting some well-deserved attention at conferences.&lt;/p&gt;

&lt;p&gt;Microservices and event-driven architectures were popular topics at phpCE, with both &lt;a href="https://twitter.com/mariuszgil"&gt;Mariusz Gil&lt;/a&gt; ('&lt;a href="https://joind.in/event/php-central-europe-conference/modeling-complex-processes-and-time-with-saga-pattern"&gt;Modeling complex processes and time with Saga pattern&lt;/a&gt;') and &lt;a href="https://twitter.com/giveupalready"&gt;Christopher Riley&lt;/a&gt; ('&lt;a href="https://joind.in/event/php-central-europe-conference/microservices-vs-the-distributed-monolith"&gt;Microservices vs The Distributed Monolith&lt;/a&gt;') speaking about this subject. They both described how microservices done right require an asynchrononous event-based approach, and how failure handling in such an architecture (rather than trying distributed, long-lived transactions) means embracing eventual consistency. The Saga pattern can be seen as a recipe for failure handling, describing actions to take for failure events at different steps in the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speaking
&lt;/h2&gt;

&lt;p&gt;For me, the main reason for attending phpCE 2017 was as a speaker, having been invited to present my talk '&lt;a href="https://joind.in/event/php-central-europe-conference/getting-started-with-php-core-development"&gt;Getting started with PHP core development&lt;/a&gt;' (&lt;a href="https://speakerdeck.com/aboks/getting-started-with-php-core-development-phpce-2017"&gt;slides&lt;/a&gt;). In this talk I described my own journey to my first contribution to the PHP programming language itself, from encountering a bug to writing a test, fixing the C source code and patching the documentation. With this talk I wanted to show, based on my own experiences, how any PHP programmer can contribute something back to the PHP project, even without any experience with the PHP core and/or the C programming language in which it is written. Based on the reactions I heard, I hope that some of the people attending this talk will have made their first contribution to PHP by now.&lt;/p&gt;

&lt;p&gt;Eventually I ended up doing a second session, filling in for another speaker who had to cancel. In this vacant slot I presented '&lt;a href="https://joind.in/event/php-central-europe-conference/introduction-to-the-semantic-web"&gt;Introduction to the Semantic Web&lt;/a&gt;' (&lt;a href="https://speakerdeck.com/aboks/introduction-to-the-semantic-web-phpce-2017"&gt;slides&lt;/a&gt;), a talk I did earlier at DPC17. It aims to show the audience the strengths and limitations of RDF, OWL and the other Semantic Web standards from W3C, which open up possibilities for a web of linked data that can be consumed by smart agents. After the session I got some really interesting questions about representing non-factual data in RDF, which can be done by a technique called &lt;em&gt;reification&lt;/em&gt;. I will definitely include this topic in an updated version of my talk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Community
&lt;/h2&gt;

&lt;p&gt;Although phpCE had a lot of interesting content, good content can also be found in a lot of other places: in books, videos and blog posts. What really sets a great conference apart is the interactions with fellow community members. From that viewpoint, the remoteness of the conference venue (in Ossa, about an hour's drive from Warsaw) was actually ideal. While at other conferences quite some attendees leave the venue after the day programme (to spend the night at home or at a hotel downtown), at phpCE almost all delegates stayed in the Ossa hotel. This gave many opportunities for great discussions and socializing with fellow developers before and after the main conference programme. I got to meet new friends and gained many interesting insights during the meals, late night drinks in the hotel bar, and the newly discovered sport &lt;em&gt;off-by-one bowling&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zCgQM42b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.moxio.com/documents/gfx/blog/20171205_phpce_1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zCgQM42b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.moxio.com/documents/gfx/blog/20171205_phpce_1.jpg" alt="Warsaw on a rainy November afternoon"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A disadvantage of a remote location can be that there isn't actually much to see around there. To make up for that, the phpCE team organised an opening day for speakers in Warsaw the day before the conference. We spent the day with a tour guide and an old bus from the communist time, walking and driving around the city center. It was a great occasion to see some of the cultural and historical highlights of Warsaw, learn a bit or two about Poland, and meet fellow speakers before the start of the conference. &lt;/p&gt;

&lt;h2&gt;
  
  
  To conclude
&lt;/h2&gt;

&lt;p&gt;I really enjoyed attending phpCE 2017. The conference was packed with great content from which I learned a lot, I met many really nice people, and just generally had a great time. I can highly recommend to attend the next edition of this conference, which will be in Prague in the fall of 2018.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://www.moxio.com/blog/22/php-central-europe-conference-2017"&gt;the Moxio blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>community</category>
      <category>conference</category>
      <category>speaking</category>
    </item>
    <item>
      <title>On type safety without generics, and the role of package design</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Fri, 02 Jun 2017 11:23:24 +0000</pubDate>
      <link>https://dev.to/moxio/on-type-safety-without-generics-and-the-role-of-package-design</link>
      <guid>https://dev.to/moxio/on-type-safety-without-generics-and-the-role-of-package-design</guid>
      <description>&lt;p&gt;Despite recent discussions in the PHP community about whether type hints are to be considered &lt;a href="https://laracasts.com/series/php-bits/episodes/1" rel="noopener noreferrer"&gt;'visual debt'&lt;/a&gt; &lt;a href="https://ocramius.github.io/blog/eliminating-visual-debt/" rel="noopener noreferrer"&gt;or&lt;/a&gt; &lt;a href="https://engineering.facile.it/blog/eng/visual-debt-typehints/" rel="noopener noreferrer"&gt;not&lt;/a&gt;, at &lt;a href="https://www.moxio.com" rel="noopener noreferrer"&gt;Moxio&lt;/a&gt; we still strongly value adding types to our code. Writing type-safe code lets us catch bugs early, enables &lt;a href="https://www.moxio.com/blog/tags/static%20analysis" rel="noopener noreferrer"&gt;static analysis&lt;/a&gt;, and serves a self-documenting purpose. Still it can be a challenge to write type-safe code in PHP, especially as it lacks a feature known as 'generics'. In this blog post I will show how (lack of) generics influences type-safe design, how parameter types and return types may change when extending a class or interface, and how we can keep our package design sound while doing so.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extension and return type hints
&lt;/h2&gt;

&lt;p&gt;Suppose we have an interface that represents a file, from which we can get the raw contents. Instances of this interface are created by a file reader, which accepts a filepath and returns an object corresponding to that file on disk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getContents&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;FileReader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$filepath&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;File&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These interfaces (and their implementations) may be part of our own code, or they could be defined by some vendor package. Either way, we would like to extend &lt;code&gt;File&lt;/code&gt; with some functionality specific for PHP files, like retrieving its PHP Abstract Syntax Tree (AST):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PhpAst&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* (omitted) */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PhpFile&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getAst&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;PhpAst&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now how does this relate to our &lt;code&gt;FileReader&lt;/code&gt; interface? What should the interface for a class that reads and returns PHP files look like? Can we use such a PHP file reader in places where a &lt;code&gt;FileReader&lt;/code&gt; is expected?&lt;/p&gt;

&lt;h2&gt;
  
  
  With generics
&lt;/h2&gt;

&lt;p&gt;Languages that have generics, &lt;a href="https://docs.oracle.com/javase/tutorial/java/generics/index.html" rel="noopener noreferrer"&gt;like Java&lt;/a&gt;, allow an elegant solution to this problem. We can just parameterize the &lt;code&gt;FileReader&lt;/code&gt; interface with the type of file returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PhpAst&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getContents&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PhpFile&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;PhpAst&lt;/span&gt; &lt;span class="nf"&gt;getAst&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;FileReader&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now a reader that returns instances of &lt;code&gt;PhpFile&lt;/code&gt; implements &lt;code&gt;FileReader&amp;lt;PhpFile&amp;gt;&lt;/code&gt;, while readers that (are only guaranteed to) return more generic &lt;code&gt;File&lt;/code&gt; objects are a &lt;code&gt;FileReader&amp;lt;File&amp;gt;&lt;/code&gt;. If some code needs just any (generic) file reader it can just declare it as &lt;code&gt;FileReader&amp;lt;? extends File&amp;gt;&lt;/code&gt;. It can then accept both &lt;code&gt;FileReader&amp;lt;File&amp;gt;&lt;/code&gt; and &lt;code&gt;FileReader&amp;lt;PhpFile&amp;gt;&lt;/code&gt; (or any other reader that returns a subtype of &lt;code&gt;File&lt;/code&gt;), having the guarantee that the objects returned from it are always a &lt;code&gt;File&lt;/code&gt; and thus at least have a &lt;code&gt;getContents()&lt;/code&gt; method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Without generics
&lt;/h2&gt;

&lt;p&gt;In languages without generics, like PHP, this is a bit more difficult. We could of course just create a separate interface for a PHP file reader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PhpFileReader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$filepath&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;PhpFile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, can we declare such an interface as an extension of &lt;code&gt;FileReader&lt;/code&gt;, and thus pass it wherever a &lt;code&gt;FileReader&lt;/code&gt; is required, despite the signature of &lt;code&gt;readFile&lt;/code&gt; not being exactly equal? In (type) theory, the answer would be 'yes'. After all, a &lt;code&gt;FileReader&lt;/code&gt; is something obeying the contract that we can call &lt;code&gt;readFile()&lt;/code&gt; on with a filename to receive a &lt;code&gt;File&lt;/code&gt;, in which a &lt;code&gt;File&lt;/code&gt; is an object guaranteed to have a &lt;code&gt;getContents()&lt;/code&gt; method returning a string. Our &lt;code&gt;PhpFileReader::readFile()&lt;/code&gt; method returns a &lt;code&gt;PhpFile&lt;/code&gt;, which is (a particular specialization of) a &lt;code&gt;File&lt;/code&gt;. This makes a &lt;code&gt;PhpFileReader&lt;/code&gt; obey the contract of a &lt;code&gt;FileReader&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This type-theoretical principle is called &lt;strong&gt;covariance&lt;/strong&gt;: when extending a type (class or interface), we are allowed to 'tighten' the types of the values returned by each method (to a more specific subtype) without breaking its contract. Consumers calling such a method when they expect to deal with the parent type will still get an object of the type they desire, having all the methods they expect to find on that object. Subtypes may thus be stricter in what they return than their parent types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fwa3h3nhx2lt57eqo0hme.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fwa3h3nhx2lt57eqo0hme.png" alt="Covariance of return types"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Does this mean we can just write &lt;code&gt;interface PhpFileReader extends FileReader&lt;/code&gt;? The practical answer is, unfortunately, 'no'. PHP only supports covariance  when extending or implementing classes or interfaces in the specific situation where the parent type has no return type hint on the method and the subtype adds one. We can view this as tightening the return type from literally anything to a specific type. In all other situations, it requires any return type hints to be identical between the parent and the child. This does not allow us to use our &lt;code&gt;PhpFileReader&lt;/code&gt; where a &lt;code&gt;FileReader&lt;/code&gt; is required without removing type hints, making our code less type-safe. I will show a solution to this problem in a while. First, let's look at how subtypes affect the &lt;em&gt;input&lt;/em&gt; parameters of methods.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extension and parameter type hints
&lt;/h2&gt;

&lt;p&gt;Suppose that in our system we also have rules operating on files, e.g. for checking coding standards or detecting bugs. We could model such a rule on a generic file using a type-safe interface like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;FileRule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;File&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rules implementing this interface can retrieve the contents of the file they receive using &lt;code&gt;getContents()&lt;/code&gt;, and then for example check for "&lt;a class="mentioned-user" href="https://dev.to/todo"&gt;@todo&lt;/a&gt;" markers or trailing whitespace. But what if we want to write rules that are specific to PHP files, using the more powerful information available inside the AST?&lt;/p&gt;

&lt;h2&gt;
  
  
  With generics
&lt;/h2&gt;

&lt;p&gt;In languages with generics we have an easy solution: we parameterize the interface again, this time by the type of the file argument we intend to check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;FileRule&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A rule that operates on PHP files then implements &lt;code&gt;FileRule&amp;lt;PhpFile&amp;gt;&lt;/code&gt;, can only be called with instances of &lt;code&gt;PhpFile&lt;/code&gt; and has access to the &lt;code&gt;getAst()&lt;/code&gt; method on the file object. A rule that checks any type of file can implement &lt;code&gt;FileRule&amp;lt;File&amp;gt;&lt;/code&gt; and will accept any &lt;code&gt;File&lt;/code&gt; instance, but will not know about methods like &lt;code&gt;getAst()&lt;/code&gt;, which are specific to the &lt;code&gt;PhpFile&lt;/code&gt; subtype. &lt;/p&gt;

&lt;p&gt;If part of our code needs to accept (e.g. as a parameter) a rule that can check a PHP file, this must include instances of &lt;code&gt;FileRule&amp;lt;File&amp;gt;&lt;/code&gt;. After all, since a &lt;code&gt;PhpFile&lt;/code&gt; is just a specific example of a &lt;code&gt;File&lt;/code&gt;, it can be given in any place where a &lt;code&gt;File&lt;/code&gt; is expected. This means that a &lt;code&gt;FileRule&amp;lt;File&amp;gt;&lt;/code&gt; can also check a &lt;code&gt;PhpFile&lt;/code&gt;, and thus is a valid replacement for a &lt;code&gt;FileRule&amp;lt;PhpFile&amp;gt;&lt;/code&gt;. To allow the rule parameter to accept both a &lt;code&gt;FileRule&amp;lt;PhpFile&amp;gt;&lt;/code&gt; and a &lt;code&gt;FileRule&amp;lt;File&amp;gt;&lt;/code&gt; we can declare it as a &lt;code&gt;FileRule&amp;lt;? super PhpFile&amp;gt;&lt;/code&gt;, i.e. "any rule that will check a &lt;code&gt;PhpFile&lt;/code&gt;".&lt;/p&gt;

&lt;h2&gt;
  
  
  Without generics
&lt;/h2&gt;

&lt;p&gt;In PHP we cannot resort to the solution we would have used in a language that does support generics. Also for this situation we can create a separate interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;PhpFileRule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;PhpFile&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again we can ask what the relationship between &lt;code&gt;FileRule&lt;/code&gt; and &lt;code&gt;PhpFileRule&lt;/code&gt; is. Is &lt;code&gt;PhpFileRule&lt;/code&gt; an extension (subtype) of &lt;code&gt;FileRule&lt;/code&gt;? We can see fairly easily that it isn't. After all, a &lt;code&gt;FileRule&lt;/code&gt; is something that can check any &lt;code&gt;File&lt;/code&gt; object, while &lt;code&gt;PhpFileRule&lt;/code&gt; will not accept (for example) a &lt;code&gt;PythonFile&lt;/code&gt;. This violates the Liskov Substitution Principle and establishes that &lt;code&gt;PhpFileRule&lt;/code&gt; is not a proper subtype of &lt;code&gt;FileRule&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What most people find confusing and suprising is that the (type-theoretical) relationship between &lt;code&gt;FileRule&lt;/code&gt; and &lt;code&gt;PhpFileRule&lt;/code&gt; is actually the other way around: &lt;code&gt;FileRule&lt;/code&gt; is a subtype of &lt;code&gt;PhpFileRule&lt;/code&gt;! It makes sense though, given that &lt;code&gt;FileRule&lt;/code&gt; will accept anything that a &lt;code&gt;PhpFileRule&lt;/code&gt; accepts as a parameter (i.e. all instances of &lt;code&gt;PhpFile&lt;/code&gt;, which are all a &lt;code&gt;File&lt;/code&gt; by inheritance). This type-theoretical principle is called &lt;strong&gt;contravariance&lt;/strong&gt;: when extending a type we are allowed to loosen the types of all input parameters of methods in the subtype. Subtypes thus may be more liberal in what they accept than their parent types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4rm5pmx6ye4xnwo9izab.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4rm5pmx6ye4xnwo9izab.png" alt="Contravariance of parameter types"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Does that mean that in practice we could (and should) write &lt;code&gt;interface FileRule extends PhpFileRule&lt;/code&gt; in PHP? The answer is (two times) 'no'. First, PHP does not support contravariance of method parameters when extending or implementing a class or interface. This means that, for now, the type hints on method parameters need to be identical between parent type and subtype. An &lt;a href="https://wiki.php.net/rfc/parameter-no-type-variance" rel="noopener noreferrer"&gt;RFC&lt;/a&gt; which will allow one specific type of contravariance (completely dropping the type constraint from a parameter, allowing any input value) has been accepted for PHP 7.2. This RFC is mainly intended for library authors to start adding scalar type hints to interfaces without breaking subclasses. Full covariance and contravariance support in PHP is not expected in the short term, as their implementation requires changes to autoloading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Package Dependency Principles
&lt;/h2&gt;

&lt;p&gt;Still, even if PHP supported it, it would not be a good idea to declare that &lt;code&gt;FileRule&lt;/code&gt; extends &lt;code&gt;PhpFileRule&lt;/code&gt;. This has to do with the &lt;a href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod" rel="noopener noreferrer"&gt;principles of package design as described by Robert "Uncle Bob" Martin&lt;/a&gt;. If we think of the functionality and interfaces for generic files as being in one package and the ones for PHP files belonging to another, the 'php files' package has a dependency on the 'generic files' package, as &lt;code&gt;PhpFile&lt;/code&gt; extends &lt;code&gt;File&lt;/code&gt;. If we would let &lt;code&gt;FileRule&lt;/code&gt; extend &lt;code&gt;PhpFileRule&lt;/code&gt; we would also introduce a dependency the other way around, creating a package dependency cycle and thus violating the Acyclic Dependencies Principle. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fp3823sakeyjb1ptcymg3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fp3823sakeyjb1ptcymg3.png" alt="Package dependency cycle introduced by explicitly declaring  raw `FileReader` endraw  a subtype of  raw `PhpFileReader` endraw "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Stable Dependencies Principle ("Depend in the direction of stability") and the Stable Abstractions Principle ("Abstractness increases with stability") point us in the 'correct' direction of dependence. Since the 'generic files' package is more abstract than the 'php files' package (and thus more stable), 'php files' can depend on 'generic files'. Dependencies the other way around should be avoided. We can even imagine that the 'generic files' package is a third party library that we use. We are in no position to ask that library's author to make his &lt;code&gt;FileRule&lt;/code&gt; interface extend our &lt;code&gt;PhpFileRule&lt;/code&gt; interface. &lt;/p&gt;

&lt;h2&gt;
  
  
  Adapter pattern to the rescue!
&lt;/h2&gt;

&lt;p&gt;Then how are we supposed to use a &lt;code&gt;FileRule&lt;/code&gt; where a &lt;code&gt;PhpFileRule&lt;/code&gt; is expected, or pass a &lt;code&gt;PhpFileReader&lt;/code&gt; to a method that wants a &lt;code&gt;FileReader&lt;/code&gt;? It turns out we can solve all our problems with a simple &lt;a href="https://sourcemaking.com/design_patterns/adapter" rel="noopener noreferrer"&gt;Adapter design pattern&lt;/a&gt;. We create two small classes. One adapts &lt;code&gt;FileRule&lt;/code&gt; to the interface of &lt;code&gt;PhpFileRule&lt;/code&gt;, and the other adapts &lt;code&gt;PhpFileReader&lt;/code&gt; to a &lt;code&gt;FileReader&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhxr76guv7aacoe6nokur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fhxr76guv7aacoe6nokur.png" alt="Adapting a  raw `FileRule` endraw  to a  raw `PhpFileRule` endraw "&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FileRuleAsPhpFileRule&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;PhpFileRule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$file_rule&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;FileRule&lt;/span&gt; &lt;span class="nv"&gt;$file_rule&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;file_rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$file_rule&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;PhpFile&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;file_rule&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9v2ezdhs3qsyrcoqlpxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9v2ezdhs3qsyrcoqlpxk.png" alt="Adapting a  raw `PhpFileReader` endraw  to a  raw `FileReader` endraw "&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PhpFileReaderAsFileReader&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;FileReader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$php_file_reader&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;PhpFileReader&lt;/span&gt; &lt;span class="nv"&gt;$php_file_reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;php_file_reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$php_file_reader&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$filepath&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;File&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;php_file_reader&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$filepath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we now want to use a &lt;code&gt;FileRule&lt;/code&gt; where a &lt;code&gt;PhpFileRule&lt;/code&gt; is asked for we can just pass &lt;code&gt;new FileRuleAsPhpFileRule($file_rule)&lt;/code&gt;. Similarly we can use &lt;code&gt;new PhpFileReaderAsFileReader($php_file_reader)&lt;/code&gt; to have a reader for PHP files act as a generic file reader. This allows us to adapt between our related interfaces in a type-safe way and, since the adapters are both part of the 'php files' package, prevents dependency cycles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fea7mdsiw8riqser736pi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fea7mdsiw8riqser736pi.png" alt="Acyclic package dependencies achieved by introducing adapters"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course there is a small downside to this approach. Using this pattern requires two additional adapter classes and two PHP-file-specific interfaces to be written (when compared to the implementation with generics) and the delegation calls inside the adapters incur a very small runtime overhead. We consider these disadvantages negligible however when compared to the benefits of type safety and proper package dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;When extending a type, the subtype may widen the types of input parameters (&lt;strong&gt;contravariance&lt;/strong&gt;) and narrow down the types of return values (&lt;strong&gt;covariance&lt;/strong&gt;). In other words, the subtype may be more liberal in what it accepts and more strict in what it returns.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In languages without generics, type-safe programming may require creating separate interfaces that are covariant or contravariant.&lt;/li&gt;
&lt;li&gt;PHP only allows covariance and contravariance in a very limited set of cases.&lt;/li&gt;
&lt;li&gt;Adding an explicit &lt;code&gt;extends&lt;/code&gt; clause for contravariance situations may break package design principles.&lt;/li&gt;
&lt;li&gt;An Adapter pattern is an easy solution to overcome these situations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://www.moxio.com/blog/17/on-type-safety-without-generics-and-the-role-of-package-design" rel="noopener noreferrer"&gt;the Moxio blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>typesafety</category>
      <category>oop</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Review Roulette: Everyone is a winner!</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Thu, 30 Mar 2017 22:00:00 +0000</pubDate>
      <link>https://dev.to/moxio/review-roulette-everyone-is-a-winner-2599</link>
      <guid>https://dev.to/moxio/review-roulette-everyone-is-a-winner-2599</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AFFFxaa8gac_EMwOKoPQt_g.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AFFFxaa8gac_EMwOKoPQt_g.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In an earlier blog post I &lt;a href="https://www.moxio.com/blog/8/introducing-review-roulette" rel="noopener noreferrer"&gt;introduced our idea of Review Roulette&lt;/a&gt;, a process of randomized code reviews with the aim to foster learning and increase collective code ownership. I explained that we would try this idea out as an experiment for two months and evaluate afterwards. I also promised to share the results of that evaluation. In this post I will do so, and describe the steps we took to make Review Roulette work even better for us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Evaluate…
&lt;/h3&gt;

&lt;p&gt;For evaluation we asked all participants to fill out a short questionnaire with questions from three different viewpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Experiences as reviewer&lt;/li&gt;
&lt;li&gt;Experiences as reviewee&lt;/li&gt;
&lt;li&gt;General impressions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The questions focused on the (perceived) usefulness of Review Roulette as a means of finding defects, improving internal quality and sharing knowledge. Additionally we asked about some aspects we identified as potential obstacles for a well-functioning process, like time consumption and communicational aspects.&lt;/p&gt;

&lt;p&gt;From the results we can conclude that, overall, Review Roulette received really positive feedback. 100% of the participants agreed that we should continue the experiment as a structural process, and the statement “I think that doing Review Roulette is useful” received a score of 4.75 out of 5 on average. For us, this was sufficient to decide to continue doing Review Roulette, which we still do up to this day. Based on the feedback, we made some small adaptations, though.&lt;/p&gt;

&lt;h3&gt;
  
  
  …and adjust
&lt;/h3&gt;

&lt;p&gt;In the questionnaire results we noticed that the statement “The commits I got assigned were useful to review” received an average score of only 3.38 out of 5, with 63% of participants scoring it a 3 or lower. This was mainly caused by commits with trivial one-line textual changes being randomly selected for review. To improve on this, we added a filter that only selects commits with at least 3 changed lines in relevant source files (php, js, css, json, etc.) as eligible for review. Implementation of such a filter was fairly straightforward using &lt;a href="http://linuxcommand.org/man_pages/diffstat1.html" rel="noopener noreferrer"&gt;diffstat&lt;/a&gt; to analyze the commits. This should weed out most trivial changes, leaving only the more interesting commits for review. As a side-effect, this also fixes the issue where an import of a binary file was put up for review.&lt;/p&gt;

&lt;p&gt;Another obstacle that we identified was the time needed for doing Review Roulette. Although we agreed a time limit of one hour per week when starting the experiment, the statement “I was able to find sufficient time to review the commits assigned to me” only scored 3 out of 5 on average, with 63% of participants scoring it a 3 or lower. This was mainly influenced by our relatively large number of &lt;a href="https://www.moxio.com/vacatures/werkstudent#" rel="noopener noreferrer"&gt;student employees&lt;/a&gt;, who work 1 or 2 days a week besides their studies. While one hour a week may be almost negligible on a full-time work week, it is a significant time investment when your work week is only 8–16 hours. Based on this feedback, we introduced a bi-weekly schedule for part-timers (only assigning them a review once per two weeks), while keeping the full-time employees on the original weekly schedule. This ensures that we can still benefit from bi-directional knowledge sharing with our student employees, while limiting the amount of time they need to spend on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  One last observation
&lt;/h3&gt;

&lt;p&gt;An interesting observation from the questionnaire results was that the perceived usefulness of Review Roulette was higher from the perspective as a reviewee than from the perspective as a reviewer, both in terms of bugs found (3.38 vs. 2.63 out of 5) and improved design (4.50 vs. 3.13 out of 5). The lesson to draw from this is that we must not underestimate the value of the feedback that we give to others. Things that may seem trivial or charted territory to ourselves may be entirely new to colleagues. This is exactly the type of knowledge sharing that we aim to amplify using Review Roulette.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;This experiment and evaluation bears a lot of similarities with agile software development: it is often useful to start with a small and simple experiment, then evaluate and adjust. We have been using Review Roulette with the mentioned improvements for about 4 months now, and are very happy with the added value it brings.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://www.moxio.com/blog/15/review-roulette-everyone-is-a-winner" rel="noopener noreferrer"&gt;&lt;em&gt;www.moxio.com&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on March 30, 2017.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>codereview</category>
      <category>codequality</category>
      <category>knowledgesharing</category>
      <category>learning</category>
    </item>
    <item>
      <title>Detecting hidden bugs in PHP code using PHP_CodeSniffer</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Thu, 01 Dec 2016 08:00:00 +0000</pubDate>
      <link>https://dev.to/moxio/detecting-hidden-bugs-in-php-code-using-phpcodesniffer-2kf7</link>
      <guid>https://dev.to/moxio/detecting-hidden-bugs-in-php-code-using-phpcodesniffer-2kf7</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AbZImz4zCSge6Cb1uO5gQGA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AbZImz4zCSge6Cb1uO5gQGA.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although PHP serves us well as a programming language, we cannot deny that some of its behavior can be very surprising. If one is not aware of these pitfalls, this can easily lead to hidden bugs in PHP code. In fact, we have ran into a fair share of these issues ourselves, but try to take measures to prevent being struck by them again. In this post we will look into two potential pitfalls in PHP, and how these can be detected and avoided using our open-sourced collection of sniffs for PHP_CodeSniffer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fool me once, shame on you
&lt;/h3&gt;

&lt;p&gt;Quick, what does the following code do?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php 
$chars = str_split("The quick brown fox jumps over the lazy dog."); foreach ($chars as $char) {
    switch (strtoupper($char)) {
        case "A": 
        case "E": 
        case "I": 
        case "O": 
        case "U": 
        case "Y": 
            continue; 
    }

print $char; 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s not strange to think that this code fragment will print the input string with all vowels removed. However, it will in fact just print the original string, including the vowels (&lt;a href="https://3v4l.org/qBcK4" rel="noopener noreferrer"&gt;see it for yourself&lt;/a&gt;). This behavior is caused by the fact that PHP &lt;a href="http://php.net/manual/en/control-structures.continue.php" rel="noopener noreferrer"&gt;considers a&lt;/a&gt;&lt;a href="http://php.net/manual/en/control-structures.continue.php" rel="noopener noreferrer"&gt;switch-statement a looping structure&lt;/a&gt; for the purpose of continue. The continue thus jumps to the end of the switch-statement (rather than to the end of the foreach-body) and all vowels are still printed. If we want to skip printing the vowels in the example above, we would have to use continue 2 to jump to the end of the foreach-body.&lt;/p&gt;

&lt;p&gt;I recently bumped into this bug feature interesting behavior in a piece of code. Even though I had seen an example similar to the one above before, and thus should have known this intricacy, I still spent way too much time trying to find out why my code did not produce the desired results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fool me twice, shame on me
&lt;/h3&gt;

&lt;p&gt;To prevent getting bitten by this quirk again, we decided to implement something for automated detection of the above situation and warn us about its unexpected behavior. For this purpose we chose to write a custom &lt;em&gt;sniff&lt;/em&gt; for &lt;a href="https://github.com/squizlabs/PHP_CodeSniffer" rel="noopener noreferrer"&gt;PHP_CodeSniffer&lt;/a&gt;, which we already used for enforcing coding standards. The token- and scope-based approach used by PHP_CodeSniffer makes it easy to check all switch-cases for top-level continue-statements (i.e. not within a nested looping structure) and see if they have a numeric 'level'-argument. We disallow any such continue-statements without an explicit number of looping levels to jump over:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
for ($i = 1; $i &amp;lt; 10; $i++) {
    switch ($x) {
        case "foo": 
            continue; // NOT OK, probably a bug 
        case "bar": 
            foreach ($a as $k =&amp;gt; $v) {
                continue; // OK, inside a nested 'foreach' 
            }
            continue 2; // OK, explicit 'level'-argument 
    } 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This warns us about potential hidden bugs like the one above. If we get an error from PHP_CodeSniffer but the behavior of continue is actually what we want (although I cannot imagine why one would not use break in such a case), we can always replace the continue by continue 1 to confirm that we have thought this case through and suppress the error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fool me three times, …
&lt;/h3&gt;

&lt;p&gt;If only this was the sole hidden pitfall when working with PHP… Due to all problems that come with non-strict comparisons we already have a check in place to enforce strict comparison operators (=== etc.) over their non-strict counterparts (== etc.). However, there are still some PHP functions that will surprise you with non-strict comparison behavior by default, like &lt;a href="https://twitter.com/fabpot/status/460707769990266880" rel="noopener noreferrer"&gt;in_array&lt;/a&gt; and array_search.&lt;/p&gt;

&lt;p&gt;That’s why we have also implemented a PHP_CodeSniffer sniff that requires the $strict-parameter to such functions to be set explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php 
in_array("foo", [0]); // NOT OK, might introduce hidden bugs in_array("foo", [0], true); // OK, strict comparison
in_array("foo", [0], false); // OK, you have probably thought about this
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although we can still opt in to the non-strict behavior, this should prevent us from having to deal with the intricacies of non-strict comparison if we have not explicitly asked for them.&lt;/p&gt;

&lt;h3&gt;
  
  
  … release as open-source
&lt;/h3&gt;

&lt;p&gt;To help the rest of the PHP community avoid these pitfalls, we have decided to open-source &lt;a href="https://github.com/Moxio/php-codesniffer-sniffs" rel="noopener noreferrer"&gt;our PHP_CodeSniffer sniffs&lt;/a&gt;. They can easily be added as a development dependency into other projects using the &lt;a href="https://packagist.org/packages/moxio/php-codesniffer-sniffs" rel="noopener noreferrer"&gt;Composer package&lt;/a&gt;, either as a standalone ruleset or by integrating them into your own PHP_CodeSniffer standard.&lt;/p&gt;

&lt;p&gt;We have a backlog of more PHP pitfalls that we want to implement checks for, so stay tuned (by following us on &lt;a href="https://twitter.com/moxio" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or subscribing to our &lt;a href="https://www.moxio.com/rss/blog" rel="noopener noreferrer"&gt;RSS feed&lt;/a&gt;) for more sniffs!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://www.moxio.com/blog/10/detecting-hidden-bugs-in-php-code-using-php-codesniffer" rel="noopener noreferrer"&gt;&lt;em&gt;www.moxio.com&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>codequality</category>
      <category>staticanalysis</category>
      <category>php</category>
      <category>programming</category>
    </item>
    <item>
      <title>Introducing Review Roulette</title>
      <dc:creator>Arnout Boks</dc:creator>
      <pubDate>Tue, 20 Sep 2016 07:00:00 +0000</pubDate>
      <link>https://dev.to/moxio/introducing-review-roulette-57b8</link>
      <guid>https://dev.to/moxio/introducing-review-roulette-57b8</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F813%2F1%2Al0cszOg2FUShauNqL6dayA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F813%2F1%2Al0cszOg2FUShauNqL6dayA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At Moxio we recently started an experiment we called ‘Review Roulette’: a process of randomized code reviews. We believe this emphasizes code reviews as a means of bidirectional learning and helps onboarding junior developers, and thus improves upon our previous review ‘policy’. In this post I would like to sketch the background behind this experiment, explain the idea of Review Roulette and present some preliminary results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Our old situation
&lt;/h3&gt;

&lt;p&gt;We already did a fair share of code reviews before the introduction of Review Roulette. About four years ago we set up a &lt;a href="https://www.reviewboard.org/" rel="noopener noreferrer"&gt;ReviewBoard&lt;/a&gt; server on our local network and started using it to discuss and review code. Review would be done in the tool, taking the discussion offline if desired. So far we did not have a formal policy around what and how to review: putting changes up for review was opt-in and the author chose the reviewer(s) and the timing (pre- or post-commit). Sometimes a review request was just a rough idea for discussion; at other times there would be a full implementation to verify.&lt;/p&gt;

&lt;p&gt;This approach made it easy to start doing code reviews and ensured that their introduction was more or less resistance-free. It also kept the review burden and bureaucratic overhead low, making it easy to do small fixes and improvements (in the spirit of the &lt;a href="http://programmer.97things.oreilly.com/wiki/index.php/The_Boy_Scout_Rule" rel="noopener noreferrer"&gt;Boy Scout Rule&lt;/a&gt;) without having to go through a formal review process.&lt;/p&gt;

&lt;p&gt;However, such a lax structure also had its disadvantages. In practice, opt-in code reviews meant that most subjects posted for review were the more difficult or ‘controversial’ changes, that were bound to spark a fair amount of discussion (which they regularly did). This gave code reviews too much an air of cumbersome discussions and hard decisions. Moreover, changes that the author thought to be straightforward were usually not reviewed, even though someone else on the team may have spotted some overlooked difficult case. Also, a free choice of reviewers caused most reviews to be assigned to a fixed group of 2–5 more senior developers, creating a sort of unofficial hierarchy of reviewers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do code reviews?
&lt;/h3&gt;

&lt;p&gt;In order to understand the undesirable effects of this situation, let’s take a step backward and look at the reasons to do code reviews. The most obvious motivation is to find and correct bugs. As Steve McConnell notes in his book Code Complete, research has shown code reviews to achieve a 45%-70% defect detection rate, more than any type of automated testing. A second reason is that code reviews can improve design and thus make code more maintainable.&lt;/p&gt;

&lt;p&gt;It is not only the code that benefits from reviews. When done properly, code reviews can also make team members learn from eachother and let them become familiar with parts of the code base that they do not work on often. Note that this works both ways: just like the original author can benefit from the feedback given by the reviewer, the reviewer can learn from the way the author has approached the problem at hand and discover methods and classes they were unfamiliar with. This all fosters shared code ownership and continuous learning, and makes code reviews a great way to onboard new or junior developers.&lt;/p&gt;

&lt;p&gt;Our old review ‘policy’ missed some opportunities regarding this aspect of knowledge sharing. The &lt;em&gt;de facto&lt;/em&gt; review hierarchy meant that juniors did not often get the opportunity to review (and thus learn from) code written by more senior developers. To emphasize code reviews as a means of bidirectional learning (as opposed to verification and supervision) requires a sense of reciprocity. Not reviewing changes that the author considered straightforward also missed out on opportunities for knowledge exchange, as a reviewer may see improvements that the author did not consider or (conversely) learn something new from the authors approach. Although we think that reviewing &lt;em&gt;all&lt;/em&gt; changes would consume too much time and work aversely, we decided that all changes should be &lt;em&gt;eligible for&lt;/em&gt; review.&lt;/p&gt;

&lt;h3&gt;
  
  
  Review Roulette
&lt;/h3&gt;

&lt;p&gt;The considerations above brought us to the idea of &lt;em&gt;Review Roulette&lt;/em&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every week, every developer is assigned one random commit (from the previous week) written by a random colleague to review, to the extent possible.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The randomness aspect eliminates any kind of fixed reviewer hierarchy and ensures reciprocity, while also ensuring that every commit is eligible for review, precluding any assumptions about what other team members could learn or teach about a given subject. Another essential aspect is the clause “to the extent possible”. With Review Roulette it is unavoidable that sooner or later someone will be assigned to review a difficult commit in an unfamiliar part of the code base. While that person will probably not understand everything, and will not be able to review the change as thorough as someone else would, they can usually still give useful remarks on certain parts of it, point out low-level logic errors and suggest changes to naming and documentation that would make the code easier to understand for an ‘outsider’. Just let them indicate what they could and could not review. A fresh pair of eyes often gives very useful insights that someone knee-deep in that codebase would not notice. This provides circumstances in which every developer can participate: if you write code, you’re in.&lt;/p&gt;

&lt;p&gt;We agreed to give this approach a try as an experiment, adding to (not replacing) the code reviews that we already did. To keep a limit on the time invested, especially for larger commits assigned to a reviewer not familiar in that area, we decided to not spend more than an hour per week on our Review Roulette. In a couple of hours I put together a simple script to retrieve all commits from the week before, filter out things like merge commits, generate a random assignment of reviewers to commits and post the review requests to our ReviewBoard server. We run the script every monday and do the reviews during the following week. Evaluation was planned two months into the experiment, when we will decide whether we continue Review Roulette and if any adjustments are necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preliminary results
&lt;/h3&gt;

&lt;p&gt;At the time of writing, we have been trying out Review Roulette for 6 weeks, so there is no real evaluation yet (I will blog about that later —  &lt;strong&gt;UPDATE&lt;/strong&gt; : &lt;a href="https://www.moxio.com/blog/15/review-roulette-everyone-is-a-winner" rel="noopener noreferrer"&gt;I have&lt;/a&gt;). Still, there are some personal observations that I would already like to share at this moment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The vibe around Review Roulette seems to be mostly positive. People are enthousiastic about doing code reviews and sharing views about development.&lt;/li&gt;
&lt;li&gt;Most changes, even the ones that seem fairly trivial at first sight, turn out to have something interesting in them if you (are forced to) look closely enough. Even in reviews of simple one-line commits I have seen useful discussions about the surrounding code, UX matters or testing styles arise. It seems that team members really see the reviews as an opportunity to learn and teach and try to get the best out of this interaction.&lt;/li&gt;
&lt;li&gt;Some sort of filter on the list of commits eligible for review is still necessary. I have seen an occasion where someone was asked to review a new import of a compiled binary file. Oops!&lt;/li&gt;
&lt;li&gt;For myself, I noticed that doing Review Roulette made me pay more care to the commit messages I write. I often found myself thinking “If this commit would be chosen for review, would my colleague understand it?” and deciding that some more context would be useful.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, I would highly recommend to try out Review Roulette with your team! It is a great chance to deepen everyones knowledge of the codebase and let both the code and the developers benefit from bidirectional learning.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://www.moxio.com/blog/8/introducing-review-roulette" rel="noopener noreferrer"&gt;&lt;em&gt;www.moxio.com&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>learning</category>
      <category>softwaredevelopment</category>
      <category>knowledgesharing</category>
      <category>codequality</category>
    </item>
  </channel>
</rss>
