Clean Code Days 2016 – Opening Keynote

Clean Code Days 2016

End of June this year I had the honor to hold the Opening Keynote at the Clean Code Days 2016 in Munich. Actually my first talk on a Conference ever, I called it “The Lone Stranger, or: Why you can’t establish Clean Code on your own“.

It covers the wide range from how to convince Managers and Co-Developers to start clean coding, over to tips and tools on how to change a legacy project from sloppy code into better and one day maybe even “Clean Code”.

Opening Keynote on Youtube

Slides

I wasn’t able to watch it in full yet (boy, my voice sucks ;-), but I hope you like it!

Debug Unit Tests using the PhpStorm built-in test runner

PhpStorm comes with a handy phpunit test runner, which lets you execute your tests with just one click. Even better: if a test fails, you can just run that test also with just one click. That’s how I like it.

However I often use the debugger to debug failed tests. This is easy with phpunit and via the command line (see e.g. Remote CLI debugging). But since PhpStorm is obviously not using the command line, we have to pass the information necessary for Xdebug and PhpStorm to initiate the debug session using the Test Runners configuration.

XDEBUG_CONFIG=idekey=PHPSTORM ; PHP_IDE_CONFIG=serverName=local.dev

Needless to mention that the above values need to fit your setup. Most likely your server name will be different, and make sure to check the ide key.

But where to put it? Assuming you already setup your Run/Debug configuration, just open the configuration dialog and put the above environment variables into the “Environment variables” input field. You don’t need to add “export” or anything. Well, just have a look:

phpstorm_unit_test_runner

Now just place your breakpoints as you need them and start the Run/Debug configuration.

Modern PHP

Not many useful PHP books have been published recently (or I haven’t yet discovered them), so I really want to recommend “Modern PHP” by Josh Lockart, another quality product by O’Reilly.

Having only 270 pages, it’s easy and quick to read, and includes a lot of best practices, tips and state-of-the-art tools for writing cool PHP applications. Some topics are covered a bit briefly like e.g. Testing, but the book points you towards the right direction and gives you useful references to read further, if you are interested.

The experienced PHP developer should actually be familiar with most of the topics, so you would probably not learn too much new stuff. Still it gives the good feeling of confirming that you are somewhat up-to-date 🙂

I’m not payed for this at all, however I think that this book is really valuable for the PHP community and therefor I’d like to promote it.

Debug your Codeception tests with Xdebug and PhpStorm

I use Xdebug not only to hunt bugs, but also for every day development work. Of course I also want to use it when I write my Tests.

I one of my current projects we use Codeception for both Unit- and Acceptance tests. Debugging Codeception Unit tests is as easy as for phpUnit, you just have to make sure that the XDEBUG_SESSION is set as described in my post about CLI debugging with Xdebug.

What to test

The Acceptance tests I want to debug are basically just testing a REST API, so it’s usually firing HTTP GET/POST requests against various endpoints:

class ApiCest
{
    public function testDoStuff(ApiTester $I)
    {
        $I->sendPOST('/my/api/dostuff');

        // testing starts here
        $I->seeResponseCodeIs(200);
    }
}

In order to debug the actual “dostuff” endpoint, I have to take care of two things: the debug session Cookie and the PhpStorm debug configuration.

Set the XDEBUG_SESSION cookie

The usual way for me to start a PhpStorm session for non-CLI scripts is to enable the “Start Listening for PHP Debug Connections” in PhpStorm and initiate a request with the XDEBUG_SESSION cookie set.

I’m assuming you have PhpStorm and Xdebug set up neat and nicely, as there are enough tutorials about it out there.

This works nicely when I start a debug session using the browser, but now we don’t use a browser and send the requests via HTTP directly (Codeception uses Guzzle for that), so we have to set the Cookie somehow. There are (at least) three ways to do that with Codeception:

  1. Set the cookie manually in the Cest (Codeception acceptance test class)
    $I->setCookie('XDEBUG_SESSION', 'PHPSTORM');
    
  2. Configure Guzzle to send the Cookie via the codeception.yml

    This is described Codeception manual on the PhpBrowser module

  3. Use the codeception/remote-debug extension

    Codeception-Remotedebug on Github

    This is my preferred way, it’s actually pretty easy to set up, and this way I just send the Cookie all the time.

    extensions:
      enabled:
        - Codeception\Extension\RemoteDebug
        config:
          Codeception\Extension\RemoteDebug:
            sessionName: PHPSTORM
    
    Since the Cookie value (PHPSTORM) might be different for other developers, these settings should not be under Version control. Codeception allows several ways to achieve this, in our project we use a environment-specific setup, which is not under version control and allows use to extend or overwrite settings on the project-wide, version controlled codeception.yml. Learn more about it in the Codeception manual on Environments.

    Increase PhpStorms Max. connections

    This might cause some headache if you forget about it. When I tried to all of the above ways to set the Cookie, the debug session was always getting stuck, i.e. PhpStorm was not stopping at the breakpoints and rather did – nothing!

    phpstorm_debug_max_connections

    By default, PhpStorm is configured to handle 1 debug session at a time. However in my case, I need to handle 2 debug sessions in parallel now – one debug session for the actual Acceptance test, and one for the API.

    And that’s it. I hope this will be useful for other Codeception users as well!

A normal day, a normal bug

After fixing approx. 5 billion bugs (+/- 1 billion) in my life so far, I have a clear picture of how a bug ticket should be written to actually support the developer rather than wasting his time. Maybe this is the reason why I always get a bit mad when I read descriptions like

The form validation depends on the gender radiobuttons, which is not normal.

Normally

So, this raises the good old question: what is normal? Especially, what is normal when there are no requirements for the radiobuttons? Common sense? Whose common sense? Mine? The reporters?

By the way, the bug turned out to be a feature. Srsly.

When a ticket states that something is “not normal”, “not ok” or “totally wrong”, then it adds some sort of personal judgement. No developer is happy to receive a bug ticket, so they should be written as neutral as possible, as we already have to live with the shame.

The Minimum Information Strategy

One nasty bug I was once only able to reproduce by clicking a couple of buttons in exact the same order as the Project Manager – of course this was not part of the ticket description, so after trying to reproduce the issue for half an hour (the ticket going back and forth a couple of times meanwhile, and the tone was about to get rougher…), I gave up and asked the PM to share the screen.

Aha!

After being able to reproduce the bug, it was fixed in 5 minutes. So in total, the PM and I together lost over an hour because the ticket was missing information that could have been added to it in two minutes. Not to mention the bad mood you and others get in. And this sums up over lifetime.

Minimum – and I mean it

My favorite bug screenshot of all times:

error_occured_alert

I’m not kidding. Someone really made the effort to take a screenshot of the alert, cut it precisely to not contain any valuable information at all (Browser? URL? Any other screen context?) and attached it to a ticket (which was quite a pain with the clumsy ticket system we worked with back then).

Sure, the error message itself leaves, erm, room for improvement. However I’m always wondering why bug reporters cut the screenshots. Probably it’s fun. I should try it myself.

Common sense

So what can we developers do? Give up? No. Resist.

Every time you get a bug ticket which is not written well, assign it back and kindly ask for more information. You can’t reproduce the issue? Don’t waste your time, write back and ask for steps to reproduce please. The CSS is messed up, but the ticket only contains a small part of the actual screen and not even a browser version? Don’t let your hair turn grey, assign it back with a smile!

When searching the net on how to write bug reports, you’ll find that here there actually is some sort of common sense. Basically, you’ll find more or less the following structure:

  1. Bug title
    The bug description. Simple, concise, to the point. Not as simple as “Application broken”, however.
  2. Steps to reproduce
    Ah, my favorite. This could make life so much easier. I know it’s annoying to write, but often necessary. “Select a product and put it into the cart” is a nice start, but most likely this will not make the bug reproducable.
  3. Expected results
    What results did you expect, and why? Is there a user story, ticket or any other document which could be helpful?
  4. Actual results
    What results did you get? Point out what is happening in contrary to the expected results.
  5. Browser Info
    A classic. Which Browser did you use? Please also add the version number, especially when IE is still to be supported.
  6. Screenshots
    A screenshot is helpful. Just keep it as it is, i.e. don’t cut out anything. Especially the browser URL is very helpful, so just keep it. Dammit. Developers absolutely don’t mind if there is too much information on it. If a lot of stuff is happening on it, consider adding markers (e.g. arrows).
  7. Additional info
    Any error message could be helpful. Do you find an error in the browser console? Please just copy & paste it!

Please also see the article “Writing Issue Reports That Work” by Joe Strazzere, the man with the “I got the bug fixed in no time because of your wonderful bug ticket“-smile. Sums it up really nicely.

Thanks for reading & happy bug fixing!

Filesystem abstraction in PHP, and why it sometimes is useful!

Phase 1: Ignorance and Bias

Recently I came across Flysystem, which is a Filesystem abstraction layer for PHP. Now if you haven’t worked with a Filesystem abstraction layer before (like me), you may ask yourself:

Why on earth should I add even more overhead for something basic as the file system?

Let me explain why it will be extremely useful. Say we have to build a small app in PHP which should download files from an FTP server, process them in some way, and store the result on the servers filesystem. No doubt, this can be done with PHPs build-in functions without a problem, you might say. Sure, but don’t forget the Unit Tes… dang! See?

Phase 2: Skepticism and Curiosity

The solution for our problem once more is: Abstraction. Abstract the process from any file system. Just use the same set of operations on some sort of adapter, no matter where or how the files are stored, and let the Abstraction Layer do the rest. You guessed it already, this is where Flysystem comes into play! Let’s start with a simple file download:

<?php

namespace My\Cool\Project;

use League\Flysystem\FilesystemInterface;

class Downloader
{
    /**
     * @var FilesystemInterface
     */
    protected $remoteFileSystem;

    /**
     * @var FilesystemInterface
     */
    protected $localFileSystem;

    /**
     * @param FilesystemInterface $remoteFileSystem
     * @param FilesystemInterface $localFileSystem
     */
    public function __construct(
        FilesystemInterface $remoteFileSystem,
        FilesystemInterface $localFileSystem
    ) {
        $this->remoteFileSystem = $remoteFileSystem;
        $this->localFileSystem = $localFileSystem;
    }

    /**
     * Download files from the remote file system
     * @param string $fileName The filename
     * @return bool
     */
    public function download($fileName)
    {
        $fileDownloaded = false;
        
        // This is the actual download part!
        if (!$this->localFileSystem->has($fileName)) {
            $fileDownloaded = $this->localFileSystem->writeStream(
                $fileName,
                $this->remoteFileSystem->readStream($fileName)
            );
        }
        // Done!

        return $fileDownloaded;
    }
}

Is that it?? Aww yeah, that’s it. When it’s with Flysystem, we only need a few lines of code, because it’s so intense!

To make the code it more clear, I called the filesystems $localFileSystem and $remoteFileSystem, but of course both filesystems could be remote ones, e.g. FTP and Amazon S3. This means that by using Flysystem, you completely decouple your code from the filesystem, so you’re prepared when the Business suddenly decides to “implement some totally easy changes”.

Of course our example is not 100%ly done, since we still have to create the Filesystem adapters we pass upon instantiation. But that’s ok, we need to do the configuration somewhere anyway. Below function is part of another class, which makes use of our Downloader class:

public function downloadSomeFile()
{
    $ftpAdapter = new \League\Flysystem\Adapter\Ftp([
        'host' => 'ftp.server.com',
        'username' => '123',
        'password' => 'abc'
    ]);
    $remoteFileSystem = new \League\Flysystem\Filesystem($ftpAdapter);

    $localAdapter = new \League\Flysystem\Adapter\Local('/tmp');
    $localFileSystem = new \League\Flysystem\Filesystem($localAdapter);

    $downloader = new \My\Cool\Project\Downloader(
        $remoteFileSystem, 
        $localFileSystem
    );
    
    $downloader->download('somefile.txt');
}

This is what I also like about using Flysystem: within the Downloader class we don’t have to deal with any path settings or such. It is completely done within the code which instantiates the Downloader, i.e. in the domain where it belongs.

it's so decoupled

Phase 3: Awesomeness and Why-didn’t-I-use-it-before-ness

I assume most of you didn’t even read until here, since you’ve been totally blown away and immediately started refactoring your code, giggling slightly insane. But wait, we’re not even fully through yet. Remember the question about Unit Tests? With Flysystem, it’s a breeze:

public function testCanDownloadFileFromRemoteFileSystem()
{
    // This mocks the remote server (could e.g. be an FTP) where we want to 
    // download the file from
    $remoteAdapter = new \League\Flysystem\Vfs\VfsAdapter(new Vfs);
    $remoteFileSystem = new \League\Flysystem\Filesystem($remoteAdapter);

    // Put a file on the virtual remote filesystem
    $remoteFileSystem->put('somefile.txt', 'just some content, does not matter');

    // Virtualize our local file system also, so no need to clean up or anything, 
    // since by using vfsStream, we don't even have to take care where to store 
    // the files during our tests.
    $localAdapter = new \League\Flysystem\Vfs\VfsAdapter(new Vfs);
    $localFileSystem = new \League\Flysystem\Filesystem($localAdapter);

    $downloader = new \My\Cool\Project\Downloader(
        $remoteFileSystem, 
        $localFileSystem
    );

    $this->assertTrue($downloader->download('somefile.txt'));
    $this->assertTrue($localFileSystem->has('somefile.txt'));
}

Flysystem even provides an adapter for vfsStream, a stream wrapper for PHP which helps greatly when you have to test filesystem-related functionality.

In simple terms, it simulates a file system in memory, which many (but not all) PHP functions can use.

Check it out here if you don’t know it yet: vfsStream on Github

So here we are: we just wrote a test for the FTP download in 5 minutes – without having to change a single line in the Downloader, without relying on a real FTP server. We could exchange the remote filesystem with Dropbox or even your Grandma’s closet within two minutes. Awesome. Now get a coffee and head over to your co-worker, who’s still struggling with the Downloader class and PHPs lovely native FTP support.

npm & Windows

Again, Windows can cause problems you would not have expected. In npm versions prior to 3, npm stores dependencies in deeply nested folder structures, causing errors on running ‘npm install’ such as

npm ERR! Error: EPERM: operation not permitted,
open '/var/www/my_longnamed_app/node_modules/
gulp-angular-templatecache/node_modules/
gulp-util/node_modules/dateformat/
node_modules/meow/node_modules/redent/
node_modules/indent-string/node_modules/
repeating/node_modules/is-finite/
package.json.29c584111ad29c009da7874ac2d19f55'

Obviously, this is a ridiculously long path and exceeds 260 characters – and Windows can’t handle that. Not sure why “they” (you know … MS…) came up with that idea, and why this is still not fixed in a modern OS like Windows 7 (I did not try versions above that). I guess it is just the pure essence of evil, the same diabolic power which brought the Internet Explorer amongst us. Let them burn, let them suffer, and let even pay money for it!

Even when you run npm on Linux in a VM on Windows with a Shared folder, you will still suffer from that. Oh, you beasts from the abyss, how … ok I’ll stop.

Luckily, npm3 supports flat dependencies, i.e. all dependencies are written into the top level of the node_modules folder. So if you run into the above problem, try

npm --version

If this still says 2.x, consider updating to npm3:

npm install -g npm

Delete your node_modules folder (not sure if this is really needed, but better go sure), then run

npm install

and all dependencies get installed without errors. Yay!

If you dare, you can have a look into the node_modules folder now. You’ll find loads of folders – the beauty of flat dependencies.

Local composer package development

A new feature on composer which I really appreciate is the “Path” repository type.

Imagine you are working on your super-cool-project, and one task requires new functionality where there is no composer package existing yet – yeah, this probably is a bit hard to imagine. Now you want to create your own super-awesome-package, because we all like it nice and separated and such.

So far, I would have developed the super-awesome-package directly inside the vendor folder of my super-cool-project – which somehow did not feel right. Obviously others felt the same, so now we can use the “path” resource type for packages which you develop right at the moment!

{
  "require": {
    "my-namespace/shoppingcart": "*@dev"
  },
  "repositories": [
    {
      "type": "path",
      "url": "../shoppingcart"
    }
  ]
}

Instead of using VCS as package source, you simply specify the directory (relative or absolute path both work) where your super-cool-package is located on your machine. In my case, I just refer to the shoppingcart folder, where the package is currently developed.

Composer will then add a symlink in the vendor folder upon running composer update, so all your changes on that package can immediately be used in your super-cool-project.

Now that’s what I call convenient!