Dutch PHP Conference 2013: Distilled

2,752 views

Published on

A couple of our team members attended DPC13, and this is a subset of some of the interesting talks we wanted to share with the rest of the team.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Dutch PHP Conference 2013: Distilled

  1. 1. Dutch PHP Conference: Distilled Chris Saylor Stephen Young @cjsaylor @young_steveo
  2. 2. Focus of this talk PHP by the Numbers Emergent Design What's new in PHP 5.5 Unbreakable Domain Models
  3. 3. PHP by the Numbers
  4. 4. Measuring Complexity Cyclomatic complexity N-path complexity
  5. 5. Cyclomatic complexity The cyclomatic complexity of a method is the count of the number of independent decision points in the method, plus one for the method entry.
  6. 6. It's a fancy term for measuring the complexity of a method. Decision points in a method increase complexity. (e.g. if, else, foreach, etc.) Plugins will calculate it for you. (PHP Mess Detector, JSHint, Grunt!)
  7. 7. The lower, the better 1—4 low complexity, easy to maintain 5—7 moderate complexity 8—10 high complexity, hard to test 11+ ?
  8. 8. N-path complexity The number of acyclic execution paths through a function; an objective measure of complexity related to the ease with which software can be comprehensively tested
  9. 9. acyclic execution paths?
  10. 10. It's a lot like cyclomatic complexity. It measures how many straight lines you can draw through a method. A method with a single IFstatement has an N-path of 2. A method with 2 IFstatements has an N-path of 4. 3 IFstatements would make the N-path 8.
  11. 11. Another way to look at it The value of a method's N-path complexity is equal to the number of unit tests needed to ensure that you have 100% code coverage. A "quick estimate" for N-Path: 2^(cyclomaticComplexity - 1)
  12. 12. You have probably seen this Running Grunt! Running "jshint:source" (jshint) task Linting app/webroot/js/views/doesEverythingView.js... ERROR [L31:C38] W074: This function's cyclomatic complexity is too high. (18)
  13. 13. Things to avoid Violating the Single Responsibility Principle A Controller method with logic to perform CRUD operations. A Product Model with logic for formatting currency. Seperation of Concerns Too complex: A single method that executes four business rules to perform a task. Better: Four methods that each execute a single business rule.
  14. 14. Plan Ahead It's common to be handed a user story that is simple to describe but complex to implement. Take time to break the logic into the smallest possible units before writing code.
  15. 15. Emergent Design with PHPSpec
  16. 16. Topics covered 1. PHPSpec overview 2. emergent design 3. simple design & smells 4. designing composition with mocks
  17. 17. What is PHPSpec?
  18. 18. it started as a port for rspec
  19. 19. Problem PHP !== Ruby
  20. 20. in ruby everything is an object and all objects are open Also, monkey patching code at runtime is a typical practice in the Ruby world. blowling.score.should eq(0)
  21. 21. an early PHPSpec syntax example Trying to emulate ruby in PHP looks ugly $this->spec($bowling->getScore())->shouldEqual(0);
  22. 22. PHPSpec's new goals fun to work with development tool let's not get in the way enforce TDD do it the PHP way
  23. 23. Test Driven Development yellow — Write the test first red — Implement the class/method; test is failing green — Test is passing
  24. 24. How PHPUnit handles the Yellow step PHPUnit 3.7.14 by Sebastian Bergmann. PHP Fatal error: Class 'Markdown' not found in /Users/stephenyoung/Documents/projects/Lab/phpuni t/tests/MarkdownTest.php on line 8 Fatal error: Class 'Markdown' not found in /Users/stephenyoung/Documents/projects/Lab/phpunit/te sts/MarkdownTest.php on line 8
  25. 25. How PHPSpec handles the Yellow step it does this for missing methods too. > specCustomer ✘ it converts plain text to html paragraphs Class Markdown does not exist. Do you want me to create it for you? [Y/n]
  26. 26. Mocking It suffices to say that mocking is painful in PHPUnit. PHPSpec has a very easy-to-use Mocking library. Too much to go into here.
  27. 27. That's Enough about PHPSpec It's a pretty awesome tool. Go check it out.
  28. 28. Emergent Design
  29. 29. What is software design?
  30. 30. Software design is the art of describing how to to solve a problem.
  31. 31. First learn design, then learn emergent design
  32. 32. Alan Kay on Messaging "The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be."
  33. 33. $this->person->getCar()->getEngine()->ignite();
  34. 34. Focusing on messaging makes code more flexible
  35. 35. $this->person->startCar();
  36. 36. Software design is the art of describing how to to solve problems with roles, responsibilities and messages
  37. 37. Big Design Up Front It's hard to change later. We need to think about things before developing. We need to make sure we don't miss anything. This is just the way we do it.
  38. 38. Y A G N I
  39. 39. 61% of all requested features are actually delivered
  40. 40. 27% of all requested features are actually used
  41. 41. 5% to 10% are responsible for realising the envisioned benefits
  42. 42. we should design for the high priority items and make it easy to change later.
  43. 43. Agile Software design is the art of describing how to to solve problems with roles, responsibilities and messages in a change-friendly way
  44. 44. Easier said than done?
  45. 45. 1. Test 2. Code 3. Refactor 4. Repeat
  46. 46. Use simple design rules to refactor 1. All tests run and pass 2. Remove duplication 3. Remove opacity 4. Remove complexity
  47. 47. What is the result of this method in your code? It is testable. It is modular. It is expressive. It is simple.
  48. 48. What is the alternative? Viscosity Immobility, Rigidity, Fragility Unreadable Complex
  49. 49. Simple design enables smell detection
  50. 50. Simple Design 1. All tests run and pass 2. Remove duplication 3. Remove opacity 4. Remove complexity smells 1. Test smells? 2. DRY smells? 3. Opacity smells? 4. Complexity smells?
  51. 51. Test smells Lack of tests Setup is too complex Unclear exercise No expectation
  52. 52. DRY Smells Copy Pasta Logic duplication Duplicated constants Alternative classes with different interfaces
  53. 53. Opacity smells Naming not in the domain Name does not express intent Feature envy Method too long Method does more than one thing
  54. 54. Complexity smells Unnecessary else Unnecessary if Unnecessary switch Too many passed arguments
  55. 55. Use design patterns to refactor
  56. 56. What can happen in a method? return a value throw an exception delegate modify state not the final behavior print something we should probably delegate that too
  57. 57. Design delegation with mocks
  58. 58. start by defining behavior
  59. 59. internally delegate to another method
  60. 60. Finally Define new role Extract collaborators using mocks Move behavior definition to new collaborator test
  61. 61. What's new in PHP 5.5
  62. 62. Performance Performance boost compared to 5.3 -> 5.4 is not as great as 5.4 -> 5.5
  63. 63. APC replacement Zend's OPCache is now packaged with PHP 5.5 and APC is now depricated
  64. 64. array_column $keyValues = [ ['key1' => 'val1', 'key2' => 'val2'], ['key1' => 'val3', 'key2' => 'val4'] ]; var_dump(array_column($keyValues, 'key1')); // yields array('val1', 'val3')
  65. 65. Foreach with list $test = [ [1, 2], [3, 4] ]; foreach ($test as list($a, $b)) { echo "a: $a; b: $b"; } // displays: // a: 1; b: 2 // a: 3; b: 4
  66. 66. Finally a finally! try { doSomeWork(); return true; } finally { cleanUpSomeStuff(); echo "I am reachable!"; } echo "I am not reachable :( ";
  67. 67. Generators function lotsOfRecords() { while ($row = $this->db->getNext()) { yield $row['id'] => $row; } } foreach (lotsOfRecords() as $id => $row) { // do stuff }
  68. 68. Password hashing API echo password_hash('somepassword', PASSWORD_BCRYPT); // $2y$12$QjSH496pcT5CEbzjD/vtVeH03tfHKFy36d4J0Ltp3lRtee9HDxY3K password_verify( 'somepassword', '$2y$12$QjSH496pcT5CEbzjD/vtVeH03tfHKFy36d4J0Ltp3lRtee9HDxY3K' ); // true
  69. 69. Unbreakable Domain Models
  70. 70. Use objects as consistency boundaries class Customer { public function __construct($email) { if( /* ugly regex here */) { throw new InvalidArgumentException(); } $this->email = $email; } }
  71. 71. Single Responsibility Principle class Email { private $email; public function __construct($email) { if( /* ugly regex here */) { throw new InvalidArgumentException(); } $this->email = $email; } public function __toString() { return $this->email; } }
  72. 72. Customer class is now tighter class Customer { /** @var Email */ private $email; public function __construct(Email $email) { $this->email = $email; } }
  73. 73. Encapsulate state and behavior with Value Objects
  74. 74. A user story may be: "A customer orders products and pays for them."
  75. 75. Procedural $order = new Order; $order->setCustomer($customer); $order->setProducts($products); $order->setStatus(Order::UNPAID); // ... $order->setPaidAmount(500); $order->setPaidCurrency(‘EUR’); $order->setStatus(Order::PAID);
  76. 76. Improve it with object for consistency $order = new Order; $order->setCustomer($customer); $order->setProducts($products); $order->setStatus( new PaymentStatus(PaymentStatus::UNPAID) ); $order->setPaidAmount(500); $order->setPaidCurrency(‘EUR’); $order->setStatus( new PaymentStatus(PaymentStatus::PAID) );
  77. 77. Improve it with more consistency $order = new Order; $order->setCustomer($customer); $order->setProducts($products); $order->setStatus( new PaymentStatus(PaymentStatus::UNPAID) ); $order->setPaidMonetary( new Money(500, new Currency(‘EUR’)) ); $order->setStatus( new PaymentStatus(PaymentStatus::PAID) );
  78. 78. Even more $order = new Order($customer, $products); // set PaymentStatus in Order::__construct() $order->setPaidMonetary( new Money(500, new Currency(‘EUR’)) ); $order->setStatus( new PaymentStatus(PaymentStatus::PAID) );
  79. 79. Getting ridiculous now $order = new Order($customer, $products); $order->pay( new Money(500, new Currency(‘EUR’)) ); // set PaymentStatus in Order#pay()
  80. 80. Encapsulation through specification "I want to give a discount to a customer that has at least 3 orders." interface CustomerSpecification { /** @return bool */ public function isSatisfiedBy(Customer $customer); }
  81. 81. class CustomerIsPremium implements CustomerSpecification { private $orderRepository; public function __construct( OrderRepository $orderRepository ) {...} /** @return bool */ public function isSatisfiedBy(Customer $customer) { $count = $this->orderRepository->countFor($customer); return $count >= 3; } } $customerIsPremium = new CustomerIsPremium($orderRepository) if($customerIsPremium->isSatisfiedBy($customer)) { // send special offer }
  82. 82. Credits PHP By the numbers - Anthony Ferrara Emergent Design with phpspec - Marcello Duarte Unbreakable Domain Models - Mathias Verraes Let's have a look at PHP 5.5 - Julien Pauli

×