Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
@asgrim
Please clone & composer install:
https://github.com/asgrim/quality-tutorial
WiFi: php2019 / php2019
Best practices...
@asgrim
Best practices for crafting high
quality PHP apps
James Titcumb
php[world] 2019
Please clone & composer install:
h...
$ whoami
James Titcumb
www.jamestitcumb.com
www.roave.com
@asgrim
Please clone & composer install:
https://github.com/asgr...
@asgrim
Please clone & composer install:
https://github.com/asgrim/quality-tutorial
WiFi: php2019 / php2019
@asgrim
What is “quality”?
@asgrim
photo: Rob Allen https://flic.kr/p/qmGpsq
@asgrim
@asgrim
@asgrim
Quality.
@asgrim
"The best code is no code at all”
-- Jeff Atwood
source: https://blog.codinghorror.com/the-best-code-is-no-code-at...
@asgrim
Trade-offs.
@asgrim
Prototyping & short-lived apps/sites
@asgrim
Products
Long-lived projects. Open source software.
@asgrim
What is quality in applications?
@asgrim
What about time/cost…?
@asgrim
“A freelancer at $25 an hour for 100 hours still
costs more than a freelancer at $150 an hour that
takes 10 hours ...
@asgrim
Get an expert in.
@asgrim
Complexity
@asgrim
Processes
@asgrim
This talk...
● Planning
● Development
● Testing
● Continuous integration
● Code reviews
● Deployments
@asgrim
Planning
@asgrim
Planning is communication
@asgrim
Use business terminology
@asgrim
Explore and discover
@asgrim
Build a model of the business
@asgrim
@asgrim
Event Storming
Practical Exercise
@asgrim
Event Storming - Practical Exercise
● Booking a hotel room
● Customer must select dates
● Rooms must be paid for w...
@asgrim
@asgrim
The model must be fluid.
@asgrim
Feature Planning
Practical Exercise
@asgrim
Feature Planning
Feature: Booking a room for a hotel
Scenario: Making a successful booking
Given ...
When ...
Then...
@asgrim
“Estimates”
@asgrim
Development
@asgrim
Care about code
@asgrim
“There are only two hard things in Computer
Science: cache invalidation and naming things.”
-- Phil Karlton
source...
@asgrim
SimpleBeanFactoryAwareAspectInstanceFactory
@asgrim
Loader
@asgrim
Describe intent
@asgrim
“Give awkward names to awkward concepts”
-- Eric Evans
source: https://skillsmatter.com/conferences/8231-ddd-excha...
@asgrim
SOLID
@asgrim
SOLID Violation Example
interface Thing {
public function doStuff() : void;
}
final class ImplementationOfThing im...
@asgrim
KISS
@asgrim
Object Calisthenics - Practical
● One level of indentation in a method
● Avoid “else” keyword
● Wrap primitive typ...
@asgrim
Avoid early abstraction
@asgrim
“Code for your use-case,
not for your re-use-case”
-- Marco Pivetta
source: https://ocramius.github.io/extremely-d...
@asgrim
Care about your API
@asgrim
A public method is like a child:
once you've written it,
you are going to maintain it
for the rest of its life!
--...
@asgrim
Strict type declarations.
Use declare(strict_types=1); by default
@asgrim
Immutable value objects
declare(strict_types=1);
use AssertAssertion; // beberlei/assert library !
final class Pos...
@asgrim
Value objects are valid!
declare(strict_types=1);
final class Thing {
public function assignPostalCode(PostalCode ...
@asgrim
Types & Value Objects
Practical
@asgrim
Static Analysis with phpstan / Psalm
Practical
@asgrim
Implement a Domain
Practical
@asgrim
Testing
@asgrim
Testing is NOT a separate line item
@asgrim
Testing should be an assumption
@asgrim
You’re already testing.
@asgrim
Still need convincing?
@asgrim
How?
@asgrim
Reduce complexity
@asgrim
Reduce complexity
public function process(Stuff a, string b, int c) : MoreStuff
{
// lots of complicated code
// l...
@asgrim
Reduce complexity
public function meaningfulThing(Stuff a, string b, int c) : More
{
// call nicer, meaningful met...
@asgrim
More complexity = more tests
@asgrim
Testing Legacy Code
Yes it’s possible… but harder
@asgrim
Test coverage
@asgrim
Line coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate cov...
@asgrim
Line coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate cov...
@asgrim
Branch coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate c...
@asgrim
Branch coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate c...
@asgrim
Branch coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate c...
@asgrim
Branch coverage
<?php
function foo(bool $a, bool $b) {
if ($a) {
echo "A";
}
if ($b) {
echo "B";
}
}
// generate c...
@asgrim
Branch vs Line Coverage
@asgrim
Prevent coverage leaking
@asgrim
Prevent coverage leaking
<?php
namespace Foo;
/**
* @covers FooBar
*/
final class BarTest extends TestCase
{
// wr...
@asgrim
Prevent coverage leaking
@asgrim
Are the tests testing?
@asgrim
Example of a test not testing…
public function testPurchaseTickets()
{
$event = Event::create(uniq('event', true)
...
@asgrim
Assert you’re asserting
public function testPurchaseTickets()
{
$event = Event::create(uniq('event', true)
$custom...
@asgrim
Test the tests are testing!
@asgrim
Infection PHP
@asgrim
Mutation testing
function add(int $a, int $b) : int {
return $a + $b;
}
function testAdd() {
$result = add(2, 3);
...
@asgrim
Mutation testing
function add(int $a, int $b) : int {
return $a - $b;
}
function testAdd() {
$result = add(2, 3);
...
@asgrim
Mutation testing
function add(int $a, int $b) : int {
return $a - $b;
}
function testAdd() {
$result = add(2, 3);
...
@asgrim
What about other tests?
@asgrim
Integration tests
@asgrim
Behaviour tests
@asgrim
BAD! Do not do this.
Feature: Ability to print my boarding pass
Scenario: A checked in passenger can print their b...
@asgrim
Better Behaviour test
Feature: Ability to print my boarding pass
Policies:
- Boarding passes are only available wh...
@asgrim
Why is this important?
@asgrim
Automate these tests
@asgrim
Automated tests
Application (and UI, API, etc.)
Domain / Business Logic
Infrastructure (DBAL, APIs, etc.)
@asgrim
Automated tests
Application (and UI, API, etc.)
Domain / Business Logic
Infrastructure (DBAL, APIs, etc.)
@asgrim
Testing at domain layer
Application (UI, API, etc.)
Domain / Business Logic
Infrastructure (DB, APIs, etc.)
// Tes...
@asgrim
Some UI testing is okay!!!
Feature: Ability to print my boarding pass
Policies:
- Boarding passes are only availab...
@asgrim
Automate all the things!
@asgrim
Continuous Integration
@asgrim
Tests cost money to run
(manually)
@asgrim
Travis-CI.com
@asgrim
Jenkins
@asgrim
What to automate?
@asgrim
The goal?
@asgrim
Code reviews
@asgrim
What to look for in code review?
@asgrim
What to look for in code review?
Code style.
@asgrim
What to look for in code review?
Small, atomic changes.
@asgrim
What to look for in code review?
Composer versions.
@asgrim
What to look for in code review?
Structure & good practices.
@asgrim
What to look for in code review?
Tests.
@asgrim
What to look for in code review?
Documentation.
@asgrim
What to look for in code review?
Security.
@asgrim
What to look for in code review?
Insight.
@asgrim
It takes practice.
Some ideas:
https://asgrim.github.io/code-review-checklist/
@asgrim
Deployments
@asgrim
Automate deployments!
@asgrim
One-click deployments
@asgrim
Easy Deployment Example
Using Heroku (not sponsored)
@asgrim
“Move fast and break things”
-- a stupid Facebook mantra
@asgrim
“Move fast and break things with stable infra”
-- Facebook mantra since 2014
@asgrim
Continuous Delivery & Deployment
@asgrim
Better quality
@asgrim
Better quality = Higher confidence
@asgrim
Better quality = Higher confidence = Happy customers
Any questions?
https://joind.in/talk/f74a3
James Titcumb
@asgrim
@asgrim
Resources
● Event Storming - Alberto Brandolini
○ http://ziobrando.blogspot.co.uk/2013/11/introducing-event-stormi...
Upcoming SlideShare
Loading in …5
×

of

Best practices for crafting high quality PHP apps (php[world] 2019) Slide 1 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 2 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 3 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 4 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 5 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 6 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 7 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 8 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 9 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 10 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 11 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 12 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 13 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 14 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 15 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 16 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 17 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 18 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 19 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 20 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 21 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 22 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 23 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 24 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 25 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 26 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 27 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 28 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 29 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 30 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 31 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 32 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 33 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 34 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 35 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 36 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 37 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 38 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 39 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 40 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 41 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 42 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 43 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 44 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 45 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 46 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 47 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 48 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 49 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 50 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 51 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 52 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 53 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 54 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 55 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 56 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 57 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 58 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 59 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 60 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 61 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 62 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 63 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 64 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 65 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 66 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 67 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 68 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 69 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 70 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 71 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 72 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 73 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 74 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 75 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 76 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 77 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 78 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 79 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 80 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 81 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 82 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 83 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 84 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 85 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 86 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 87 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 88 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 89 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 90 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 91 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 92 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 93 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 94 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 95 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 96 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 97 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 98 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 99 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 100 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 101 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 102 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 103 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 104 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 105 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 106 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 107 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 108 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 109 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 110 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 111 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 112 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 113 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 114 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 115 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 116 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 117 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 118 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 119 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 120 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 121 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 122 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 123 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 124 Best practices for crafting high quality PHP apps (php[world] 2019) Slide 125
Upcoming SlideShare
What to Upload to SlideShare
Next
Download to read offline and view in fullscreen.

0 Likes

Share

Download to read offline

Best practices for crafting high quality PHP apps (php[world] 2019)

Download to read offline

The Best Practices for Crafting Quality PHP Applications workshop is an interactive exploration into some conventions, processes, and habits that help make better quality software. Whilst there is no single silver bullet, we will spend time discussing, supported by some practical exercises, what improvements we can make. We’ll focus on three core areas; planning, development, and testing; using a variety of practical explorations, group discussion and showing you discoveries from my own experience.

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all
  • Be the first to like this

Best practices for crafting high quality PHP apps (php[world] 2019)

  1. 1. @asgrim Please clone & composer install: https://github.com/asgrim/quality-tutorial WiFi: php2019 / php2019 Best practices for crafting high quality PHP apps
  2. 2. @asgrim Best practices for crafting high quality PHP apps James Titcumb php[world] 2019 Please clone & composer install: https://github.com/asgrim/quality-tutorial WiFi: php2019 / php2019
  3. 3. $ whoami James Titcumb www.jamestitcumb.com www.roave.com @asgrim Please clone & composer install: https://github.com/asgrim/quality-tutorial WiFi: php2019 / php2019
  4. 4. @asgrim Please clone & composer install: https://github.com/asgrim/quality-tutorial WiFi: php2019 / php2019
  5. 5. @asgrim What is “quality”?
  6. 6. @asgrim photo: Rob Allen https://flic.kr/p/qmGpsq
  7. 7. @asgrim
  8. 8. @asgrim
  9. 9. @asgrim Quality.
  10. 10. @asgrim "The best code is no code at all” -- Jeff Atwood source: https://blog.codinghorror.com/the-best-code-is-no-code-at-all/
  11. 11. @asgrim Trade-offs.
  12. 12. @asgrim Prototyping & short-lived apps/sites
  13. 13. @asgrim Products Long-lived projects. Open source software.
  14. 14. @asgrim What is quality in applications?
  15. 15. @asgrim What about time/cost…?
  16. 16. @asgrim “A freelancer at $25 an hour for 100 hours still costs more than a freelancer at $150 an hour that takes 10 hours to do the same task” -- Brandon Savage source: http://www.brandonsavage.net/earning-more-money-as-a-php-freelancer/
  17. 17. @asgrim Get an expert in.
  18. 18. @asgrim Complexity
  19. 19. @asgrim Processes
  20. 20. @asgrim This talk... ● Planning ● Development ● Testing ● Continuous integration ● Code reviews ● Deployments
  21. 21. @asgrim Planning
  22. 22. @asgrim Planning is communication
  23. 23. @asgrim Use business terminology
  24. 24. @asgrim Explore and discover
  25. 25. @asgrim Build a model of the business
  26. 26. @asgrim
  27. 27. @asgrim Event Storming Practical Exercise
  28. 28. @asgrim Event Storming - Practical Exercise ● Booking a hotel room ● Customer must select dates ● Rooms must be paid for when booking ● Stripe is the chosen payment provider ● Payment must only be taken once room is reserved ● Room availability is checked & reserved via 3rd party API ● All rooms & dates cost the same (e.g. $100 per night) ● Notify the customer (e.g. email) on a successful reservation ● Customer can cancel a booking ● On cancellation, full refund if more than 48 hours before the stay
  29. 29. @asgrim
  30. 30. @asgrim The model must be fluid.
  31. 31. @asgrim Feature Planning Practical Exercise
  32. 32. @asgrim Feature Planning Feature: Booking a room for a hotel Scenario: Making a successful booking Given ... When ... Then ... Scenario: Cancelling an existing booking Given ... When ... Then ... Scenario: If a room is booked by the time payment is made, do not charge the card or reserve the room Given ... When ... Then ...
  33. 33. @asgrim “Estimates”
  34. 34. @asgrim Development
  35. 35. @asgrim Care about code
  36. 36. @asgrim “There are only two hard things in Computer Science: cache invalidation and naming things.” -- Phil Karlton source: https://martinfowler.com/bliki/TwoHardThings.html
  37. 37. @asgrim SimpleBeanFactoryAwareAspectInstanceFactory
  38. 38. @asgrim Loader
  39. 39. @asgrim Describe intent
  40. 40. @asgrim “Give awkward names to awkward concepts” -- Eric Evans source: https://skillsmatter.com/conferences/8231-ddd-exchange-2017
  41. 41. @asgrim SOLID
  42. 42. @asgrim SOLID Violation Example interface Thing { public function doStuff() : void; } final class ImplementationOfThing implements Thing { public function doStuff() : void { ... } public function moreStuff() : void; } class ConsumerOfThing { /** @var Thing */ private $thing; public function woo() { $this->thing->moreStuff(); } }
  43. 43. @asgrim KISS
  44. 44. @asgrim Object Calisthenics - Practical ● One level of indentation in a method ● Avoid “else” keyword ● Wrap primitive types (e.g. strings, int) ● First class collections (instead of Thing[]) ● One object operator (Law of Demeter) ● Avoid abbreviations (naming!) ● Keep classes small ● Avoid more than 2 instance variables ● No getters/setters
  45. 45. @asgrim Avoid early abstraction
  46. 46. @asgrim “Code for your use-case, not for your re-use-case” -- Marco Pivetta source: https://ocramius.github.io/extremely-defensive-php/#/39
  47. 47. @asgrim Care about your API
  48. 48. @asgrim A public method is like a child: once you've written it, you are going to maintain it for the rest of its life! -- Stefan Priebsch
  49. 49. @asgrim Strict type declarations. Use declare(strict_types=1); by default
  50. 50. @asgrim Immutable value objects declare(strict_types=1); use AssertAssertion; // beberlei/assert library ! final class PostalCode { private const VALIDATION_EXPRESSION = '(GIR 0AA)|((([A-Z-[QVX]][0-9][0-... /** @var string */ private $value; public function __construct(string $value) { $this->assertValidPostalCode($value); $this->value = $value; } private function assertValidPostalCode(string $value) : string { Assertion::regex($value, self::VALIDATION_EXPRESSION); } public function __toString() : string { return $this->value; } }
  51. 51. @asgrim Value objects are valid! declare(strict_types=1); final class Thing { public function assignPostalCode(PostalCode $postalCode) : void { // ... we can trust $postalCode is a valid postal code } } // 12345 is not valid - EXCEPTION! $myThing->assignPostalCode(new PostalCode('12345')); // assignPostalCode is happy $myThing->assignPostalCode(new PostalCode('PO1 1AA')); // With STRICT types, this will also FAIL $myThing->assignPostalCode(new PostalCode(12345));
  52. 52. @asgrim Types & Value Objects Practical
  53. 53. @asgrim Static Analysis with phpstan / Psalm Practical
  54. 54. @asgrim Implement a Domain Practical
  55. 55. @asgrim Testing
  56. 56. @asgrim Testing is NOT a separate line item
  57. 57. @asgrim Testing should be an assumption
  58. 58. @asgrim You’re already testing.
  59. 59. @asgrim Still need convincing?
  60. 60. @asgrim How?
  61. 61. @asgrim Reduce complexity
  62. 62. @asgrim Reduce complexity public function process(Stuff a, string b, int c) : MoreStuff { // lots of complicated code // lots of complicated code // lots of complicated code // lots of complicated code // lots of complicated code // lots of complicated code // lots of complicated code // lots of complicated code // lots of complicated code // lots of complicated code // lots of complicated code // lots of complicated code // lots of complicated code // lots of complicated code
  63. 63. @asgrim Reduce complexity public function meaningfulThing(Stuff a, string b, int c) : More { // call nicer, meaningful methods below } private function throwStuffIntoFire(Stuff a) : Fire { // smaller, meaningful chunk of code } private function combineStringWithFire(Fire a, string b) : string { // simple, lovely code! } private function postFlowersToSpain(int c) : void
  64. 64. @asgrim More complexity = more tests
  65. 65. @asgrim Testing Legacy Code Yes it’s possible… but harder
  66. 66. @asgrim Test coverage
  67. 67. @asgrim Line coverage <?php function foo(bool $a, bool $b) { if ($a) { echo "A"; } if ($b) { echo "B"; } } // generate coverage using calls: foo(true, false); foo(false, true);
  68. 68. @asgrim Line coverage <?php function foo(bool $a, bool $b) { if ($a) { echo "A"; } if ($b) { echo "B"; } } // generate coverage using calls: foo(true, false); foo(false, true);
  69. 69. @asgrim Branch coverage <?php function foo(bool $a, bool $b) { if ($a) { echo "A"; } if ($b) { echo "B"; } } // generate coverage using calls: foo(true, false); foo(false, true);
  70. 70. @asgrim Branch coverage <?php function foo(bool $a, bool $b) { if ($a) { echo "A"; } if ($b) { echo "B"; } } // generate coverage using calls: foo(true, false); foo(false, true);
  71. 71. @asgrim Branch coverage <?php function foo(bool $a, bool $b) { if ($a) { echo "A"; } if ($b) { echo "B"; } } // generate coverage using calls: foo(true, false); foo(false, true); foo(false, false); // NEW TEST!!!
  72. 72. @asgrim Branch coverage <?php function foo(bool $a, bool $b) { if ($a) { echo "A"; } if ($b) { echo "B"; } } // generate coverage using calls: foo(true, false); foo(false, true); foo(false, false); // NEW TEST!!! foo(true, true); // NEW TEST!!!
  73. 73. @asgrim Branch vs Line Coverage
  74. 74. @asgrim Prevent coverage leaking
  75. 75. @asgrim Prevent coverage leaking <?php namespace Foo; /** * @covers FooBar */ final class BarTest extends TestCase { // write some tests! }
  76. 76. @asgrim Prevent coverage leaking
  77. 77. @asgrim Are the tests testing?
  78. 78. @asgrim Example of a test not testing… public function testPurchaseTickets() { $event = Event::create(uniq('event', true) $customer = Customer::create(uniq('name', true)); $shop->purchaseTicket(1, $event, [$customer]); } @asgrim
  79. 79. @asgrim Assert you’re asserting public function testPurchaseTickets() { $event = Event::create(uniq('event', true) $customer = Customer::create(uniq('name', true)); $receipt = $shop->purchaseTicket(1, $event, [$customer]); self::assertSame($event, $receipt->event()); $customersInReceipt = $receipt->customers(); self::assertCount(1, $customersInReceipt); self::assertContains($customer, $customersInReceipt); } @asgrim
  80. 80. @asgrim Test the tests are testing!
  81. 81. @asgrim Infection PHP
  82. 82. @asgrim Mutation testing function add(int $a, int $b) : int { return $a + $b; } function testAdd() { $result = add(2, 3); // self::assertSame(5, $result); }
  83. 83. @asgrim Mutation testing function add(int $a, int $b) : int { return $a - $b; } function testAdd() { $result = add(2, 3); // self::assertSame(5, $result); }
  84. 84. @asgrim Mutation testing function add(int $a, int $b) : int { return $a - $b; } function testAdd() { $result = add(2, 3); self::assertSame(5, $result); // /// test will now fail with mutation }
  85. 85. @asgrim What about other tests?
  86. 86. @asgrim Integration tests
  87. 87. @asgrim Behaviour tests
  88. 88. @asgrim BAD! Do not do this. Feature: Ability to print my boarding pass Scenario: A checked in passenger can print their boarding pass Given I have a flight booked And I have checked in When I visit the home page And I click the ".manage-booking" button And I enter "CJM23L" in the ".bref-ipt-fld" field And I click the "Find Booking" button Then I should see the ".booking-ref.print" button When I click the ".booking-ref.print" button Then I should see the print dialogue
  89. 89. @asgrim Better Behaviour test Feature: Ability to print my boarding pass Policies: - Boarding passes are only available when already checked in - If customer cannot print boarding pass, they can collect at The airport - more business rules etc... Scenario: A checked in passenger can print their boarding pass Given I have a flight booked for LHR-MIA on 24th May And I have previously checked in for the flight When I display my booking reference "CJM23L" Then I should be able to print my boarding pass And the boarding pass should display flight details correctly
  90. 90. @asgrim Why is this important?
  91. 91. @asgrim Automate these tests
  92. 92. @asgrim Automated tests Application (and UI, API, etc.) Domain / Business Logic Infrastructure (DBAL, APIs, etc.)
  93. 93. @asgrim Automated tests Application (and UI, API, etc.) Domain / Business Logic Infrastructure (DBAL, APIs, etc.)
  94. 94. @asgrim Testing at domain layer Application (UI, API, etc.) Domain / Business Logic Infrastructure (DB, APIs, etc.) // Testing via the UI public function iDisplayMyBookingReference(string $reference) { $page = $this->getSession()->getPage(); $page->click(".manage-booking"); $page->findField(".bref-ipt-fld")->setValue($reference); $page->click("Find Booking"); } // Using the domain layer directly in tests public function iDisplayMyBookingReference(string $reference) { $this->booking = $this->retrieveBooking($reference); }
  95. 95. @asgrim Some UI testing is okay!!! Feature: Ability to print my boarding pass Policies: - Boarding passes are only available when already checked in - If customer cannot print boarding pass, they can collect at The airport - more business rules etc... @ui Scenario: A checked in passenger can print their boarding pass Given I have a flight booked for LHR-OTP on 24th May And I have previously checked in for the flight When I display my booking reference "CJM23L" Then I should be able to print my boarding pass And the boarding pass should display flight details correctly
  96. 96. @asgrim Automate all the things!
  97. 97. @asgrim Continuous Integration
  98. 98. @asgrim Tests cost money to run (manually)
  99. 99. @asgrim Travis-CI.com
  100. 100. @asgrim Jenkins
  101. 101. @asgrim What to automate?
  102. 102. @asgrim The goal?
  103. 103. @asgrim Code reviews
  104. 104. @asgrim What to look for in code review?
  105. 105. @asgrim What to look for in code review? Code style.
  106. 106. @asgrim What to look for in code review? Small, atomic changes.
  107. 107. @asgrim What to look for in code review? Composer versions.
  108. 108. @asgrim What to look for in code review? Structure & good practices.
  109. 109. @asgrim What to look for in code review? Tests.
  110. 110. @asgrim What to look for in code review? Documentation.
  111. 111. @asgrim What to look for in code review? Security.
  112. 112. @asgrim What to look for in code review? Insight.
  113. 113. @asgrim It takes practice. Some ideas: https://asgrim.github.io/code-review-checklist/
  114. 114. @asgrim Deployments
  115. 115. @asgrim Automate deployments!
  116. 116. @asgrim One-click deployments
  117. 117. @asgrim Easy Deployment Example Using Heroku (not sponsored)
  118. 118. @asgrim “Move fast and break things” -- a stupid Facebook mantra
  119. 119. @asgrim “Move fast and break things with stable infra” -- Facebook mantra since 2014
  120. 120. @asgrim Continuous Delivery & Deployment
  121. 121. @asgrim Better quality
  122. 122. @asgrim Better quality = Higher confidence
  123. 123. @asgrim Better quality = Higher confidence = Happy customers
  124. 124. Any questions? https://joind.in/talk/f74a3 James Titcumb @asgrim
  125. 125. @asgrim Resources ● Event Storming - Alberto Brandolini ○ http://ziobrando.blogspot.co.uk/2013/11/introducing-event-storming.html ● “Good Design is Imperfect Design” - Eric Evans ○ https://skillsmatter.com/skillscasts/9171-good-design-is-imperfect-design ● “Writing code that lasts” - Rafael Dohms ○ https://www.youtube.com/watch?v=I0y5jU61pS4 ● Object Calisthenics - William Durand ○ https://williamdurand.fr/2013/06/03/object-calisthenics/ ● “Driving Design through Examples” - Ciaran McNulty ○ https://www.youtube.com/watch?v=83GbyDpJDI4 ● Code Review Checklist ○ https://asgrim.github.io/code-review-checklist/

The Best Practices for Crafting Quality PHP Applications workshop is an interactive exploration into some conventions, processes, and habits that help make better quality software. Whilst there is no single silver bullet, we will spend time discussing, supported by some practical exercises, what improvements we can make. We’ll focus on three core areas; planning, development, and testing; using a variety of practical explorations, group discussion and showing you discoveries from my own experience.

Views

Total views

228

On Slideshare

0

From embeds

0

Number of embeds

0

Actions

Downloads

8

Shares

0

Comments

0

Likes

0

×