Building rock
solid software
in the real world
Improving team
workflow to
improve your
software
Omni Adams
@omnicolor
Mashery
http://omni-spot.blogspot.com
https://joind.in/event/dallasphp-201503
Process matters
BSOD ATM
Development cycle
Workflow diagram
Planning
dis mite be gud time to switch to plan b
Coding
Coding Drunk O'Reilly Cover
Automated checks
Computer says no
Code reviews
Dr House face palming
Submitting your code
I thought the finish line was ribbon
After code is submitted
Every time you break the build God kills a kitten
Automated checks
Hal 9000
Automated checks
Hal 9000
sorry dave,
I can't let
you do that
Automated checks
Automated checks: lint
Belly button lint
Automated checks: lint
        <?php
        // test.php
        echo 'foo'
        echo 'bar';
    

$ php -l test.php
Errors parsing test.php
$ php test.php
PHP Parse error:  syntax error, unexpected 'echo' (T_ECHO), expecting ',' or ';' in test.php on line 3
    
Automated checks: phpunit
PHPUnit
Automated checks: phpunit
$ phpunit
PHPUnit 4.2.6 by Sebastian Bergmann.
........................................  63 / 315 ( 20%)
........................................ 126 / 315 ( 40%)
........................................ 189 / 315 ( 60%)
........................................ 252 / 315 ( 80%)
........................................ 315 / 315 (100%)

Time: 3.36 seconds, Memory: 6.75Mb
OK (315 tests, 348 assertions)
Automated checks: phpunit
$ phpunit --enforce-time-limit
PHPUnit 4.5.0 by Sebastian Bergmann.
.E......................................  63 / 315 ( 20%)
........................................ 126 / 315 ( 40%)
........................................ 189 / 315 ( 60%)
........................................ 252 / 315 ( 80%)
........................................ 315 / 315 (100%)

Time: 1.42 seconds, Memory: 7.00Mb

There was 1 error:

1) CharacterTest::testSetArchetype
PHP_Invoker_TimeoutException: Execution aborted after 1 second

tests/CharacterTest.php:65
FAILURES! Tests: 315, Assertions: 347, Errors: 1.
Automated checks: phpunit
class Foo {
    public function bar() {
        return true;
    }
}

class FooTest extends PHPUnit_Framework_TestCase {
    public function testBar() {
        (new Foo())->bar();
    }
}
Automated checks: phpunit
$ phpunit --coverage-text test.php
PHPUnit 4.5.0 by Sebastian Bergmann and contributors.
.

Time: 104 ms, Memory: 7.75Mb
OK (1 test, 0 assertions)

Code Coverage Report:
  2015-03-06 10:14:31

 Summary:
  Classes: 100.00% (1/1)
  Methods: 100.00% (1/1)
  Lines:   100.00% (1/1)

Foo
  Methods: 100.00% ( 1/ 1)   Lines: 100.00% (  1/  1)
Automated checks: phpunit
$ phpunit --report-useless-tests --coverage-text test.php
PHPUnit 4.5.0 by Sebastian Bergmann and contributors.
R

Time: 106 ms, Memory: 7.75Mb

OK, but incomplete, skipped, or risky tests!
Tests: 1, Assertions: 0, Risky: 1.

Code Coverage Report:
  2015-03-06 10:20:03

 Summary:
  Classes:  0.00% (0/1)
  Methods:  0.00% (0/1)
  Lines:    0.00% (0/1)
Automated checks: phpunit
class Foo {
    function bar() {
        echo 'FFF';
        return true;
    }
}

class FooTest extends PHPUnit_Framework_TestCase {
    public function testBar() {
        $foo = new Foo();
        $this->assertTrue($foo->bar());
    }
}
Automated checks: phpunit
$ phpunit test.php
PHPUnit 4.5.0 by Sebastian Bergmann and contributors.

.FFF

Time: 76 ms, Memory: 3.25Mb

OK (1 test, 1 assertion)
Automated checks: phpunit
$ phpunit --disallow-test-output --verbose test.php
PHPUnit 4.5.0 by Sebastian Bergmann and contributors.

RFFF

Time: 47 ms, Memory: 3.25Mb

There was 1 risky test:

1) FooTest::testBar
This test printed output: Moo

OK, but incomplete, skipped, or risky tests!
Tests: 1, Assertions: 1, Risky: 1.
Automated checks: PHPCode_Sniffer
Here. Smell deez...
Automated checks: PHPCode_Sniffer
$ phpcs skill.php

FILE: skill.php
----------------------------------------------------------
FOUND 9 ERROR(S) AND 1 WARNING(S) AFFECTING 4 LINE(S)
----------------------------------------------------------
  4 | WARNING | PHP version not specified
  4 | ERROR   | Missing @category tag in file comment
  4 | ERROR   | Missing @package tag in file comment
  4 | ERROR   | Missing @author tag in file comment
 50 | ERROR   | Short PHP opening tag used with echo; expected "<?php echo
    |         | htmlentities ..." but found "<?= htmlentities ..."
 52 | ERROR   | Expected "foreach (...) {\n"; found "foreach (...) {"
 52 | ERROR   | Closing brace must be on a line by itself
----------------------------------------------------------

Time: 33 ms, Memory: 3.00Mb
    
Automated checks: PHPMD
Messy kitchen
Automated checks: PHPMD
$ phpmd UnknownElement.php text design,codesize,cleancode

UnknownElement.php:72
    Avoid using static access to class 'Task' in method
    'maybeConfigure'.
UnknownElement.php:92
    Avoid using static access to class 'BuildException' in
    method 'main'.
UnknownElement.php:95
    Avoid using static access to class 'Task' in method
    'main'.
UnknownElement.php:118
    Avoid using static access to class 'TaskAdapter' in
    method 'handleChildren'.
    
Automated checks: PHPCPD
God uses copy/paste... a lot
Automated checks: PHPCPD
$ phpcpd .
phpcpd 2.0.0 by Sebastian Bergmann.

Found 1 exact clones with 20 duplicated lines in 1 files:

  -     tests/CharacterControllerTest.php:262-282
        tests/CharacterControllerTest.php:312-332

0.55% duplicated lines out of 3651 total lines of code.

Time: 740 ms, Memory: 5.25Mb
    
Automated checks: PHPDCD
Cemetary dead end
Automated checks: PHPDCD
<?php
if (false) {
    echo 'This never runs';
}
function uncalled() {
    echo 'Nothing calls this';
}
exit(0);
echo 'More uncalled code';
    
Automated checks: PHPDCD
$ phpdcd test.php
phpdcd 1.0.1 by Sebastian Bergmann.

  - uncalled()
    LOC: 3, declared in test.php:7

Time: 20 ms, Memory: 3.00Mb
    
Automated checks: Code coverage
OMG!!! Her angles are uncovered
Automated checks: Code coverage
Code coverage example
Code reviews
You're doing it wrong
Code reviews: Review Board
Review Board
Code reviews: codereview.appspot.com
Codereview.appspot.com screen shot
Code reviews: Atlassian Crucible
Atlassian Crucible
Code reviews: Atlassian Stash
Atlassian Stash
Code reviews
Minority Report
Code reviews
Dexter Morgan
Code reviews
Code quality measurement: WTFs/minute
Code reviews

What tools can't catch:

  • Logic errors
  • Off-by-one errors
  • Obvious performance problems
  • Refactoring opportunities
  • Bad/misleading documentation

What tools missed:

  • Style problems
  • Syntax errors
  • Typos
  • Unreachable code
  • Useless tests
  • Missing tests
Style guides
Helicopter style
Style guides
Dos Equis Guy
Style guides
Style guides
Trailer home Taj Mahal
Style guides
McMansions
Style guides
Submitting code
Is there life after death?
Submitting code
Fish hooks
Submitting code
Fish hook
Submitting code
None shall pass
Submitting code
#!/usr/bin/env php
<?php
echo 'None shall pass', PHP_EOL;
exit(1);
    
Submitting code
Remember, if all else fails
Submitting code
foo(000) /$ touch test
foo(100) /$ git add test
foo(100) /$ git commit
None shall pass
foo(100) /$
    
Submitting code
#!/usr/bin/env php
<?php
$directory = new RecursiveDirectoryIterator(
    '.', FilesystemIterator::SKIP_DOTS
);
$iterator = new RecursiveIteratorIterator($directory);
$regexIterator = new RegexIterator(
    $iterator, '/^.+\.php$/i',
    RecursiveRegexIterator::GET_MATCH
);
Submitting code
$success = true;
foreach ($regexIterator as $file) {
    $output = exec('php -l ' . escapeshellarg($file[0]),
        $unused, $return);
    if ($return) {
        echo $output, PHP_EOL;
        $success = false;
    }
}
if (!$success) {
    exit(1);
}
Submitting code
foo(200) /$ git commit
Errors parsing ./test.php
Errors parsing ./test/foo.php
foo(200) /$
    
After submitting
Continuous build map
After submitting
Traffic cone man
After submitting
Green build orb
Omni Adams
@omnicolor
Mashery
http://omni-spot.blogspot.com
https://joind.in/event/dallasphp-201503

  /