Don't Be STUPID, Grasp SOLID - DrupalCon Prague

5,891 views

Published on

Slides from my talk at DrupalCon Prague 2013: https://prague2013.drupal.org/session/dont-be-stupid-grasp-solid

Published in: Technology, Education
  • Be the first to comment

Don't Be STUPID, Grasp SOLID - DrupalCon Prague

  1. 1. Don’t Be STUPID Grasp SOLID! Anthony Ferrara
  2. 2. Let’s Talk Object Oriented Programming
  3. 3. What Is An Object?
  4. 4. Classic View Object == Physical “Thing”
  5. 5. Classic View Object == Physical “Thing” Methods == Actions on “Thing”
  6. 6. Classic View Object == Physical “Thing” Methods == Actions on “Thing” Properties == Description of “Thing”
  7. 7. Animal MammalBird Fish CatCow Dog Lion Feline Cheetah
  8. 8. Classic View $lion = new Lion; $lion->roar(); $lion->walkTo($point); $lion->hunt($zebra); $lion->sleep();
  9. 9. Is This Realistic?
  10. 10. Classic View $lion = new Lion; $lion->roar(); $lion->walkTo($point); $lion->hunt($zebra); $lion->sleep();
  11. 11. (9 Months Later)
  12. 12. Classic View $lion = new Lion; $lion->roar(); $lion->walkTo($point); $lion->hunt($zebra); $lion->sleep();
  13. 13. Classic View $lion = new Lion; $lion->roar(); $lion->walkTo($point); $lion->hunt($zebra); $lion->sleep(); Does A Lion Have A Button To Make It Roar?
  14. 14. Classic View $lion = new Lion; $lion->roar(); $lion->walkTo($point); $lion->hunt($zebra); $lion->sleep(); Does A Lion Have A Button To Make It Roar?What Does It Mean For An Object To “Hunt”?
  15. 15. Classic View $lion = new Lion; $lion->roar(); $lion->walkTo($point); $lion->hunt($zebra); $lion->sleep(); Does A Lion Have A Button To Make It Roar?What Does It Mean For An Object To “Hunt”? What Is A Lion In Relation To Our Application?
  16. 16. The Classical Model Is Easy To Understand
  17. 17. The Classical Model Is Completely Impractical
  18. 18. “Modern” View Object == Collection Of (Related) Behaviors
  19. 19. “Modern” View Object == Collection Of (Related) Behaviors Methods == Behavior
  20. 20. “Modern” View Object == Collection Of (Related) Behaviors Methods == Behavior Properties == Details Of Behavior
  21. 21. Classic View == “(conceptually) is a” Modern View == “behaves as a”
  22. 22. interface Number { function getValue(); function __toString(); function add(Number $n); function subtract(Number $n); function equals(Number $n); function isLessThan(Number $n); function isGreaterThan(Number $n); }
  23. 23. Number IntegerFloat Decimal longshort long long unsigned signed
  24. 24. But Wait!
  25. 25. We Don’t Even Need Inheritance
  26. 26. All We Need Is Polymorphism And Encapsulation
  27. 27. Polymorphism Behavior Is Determined Dynamically “Dynamic Dispatch”
  28. 28. Procedural Code if ($a instanceof Long) { return new Long($a->getValue() + 1); } elseif ($a instanceof Float) { return new Float($a->getValue() + 1.0); } elseif ($a instanceof Decimal) { return new Decimal($a->getValue() + 1.0); }
  29. 29. Polymorphic Code return $int->add(new Integer(1));
  30. 30. Polymorphic Code class Integer implements Number { public function add(Number $a) { return new Integer( $this->getValue() + (int) $a->getValue() ); } }
  31. 31. Polymorphic Code class Float implements Number { public function add(Number $a) { return new Float( $this->getValue() + (float) $a->getValue() ); } }
  32. 32. Encapsulation Behavior Is Completely Contained By The Object’s API (Information Hiding)
  33. 33. Procedural Code if (5 == $number->value) { print “Number Is 5”; } else { print “Number Is Not 5”; }
  34. 34. Encapsulated Code if ($number->equals(new Integer(5))) { print “Number Is 5”; } else { print “Number Is Not 5”; }
  35. 35. Encapsulated Code class Decimal implements Number { protected $intValue; protected $exponent; public function equals(Number $a) { if ($a instanceof Decimal) { // Compare Directly } else { // Cast } }
  36. 36. Behavior Is Defined By The API
  37. 37. Two Types Of Primitive APIs Interfaces (Explicit)
  38. 38. Two Types Of Primitive APIs Interfaces (Explicit) Duck Typing (Implicit)
  39. 39. If an Object Is A Collection Of Behaviors...
  40. 40. What Is A Collection Of Classes/Objects?
  41. 41. APIs Method
  42. 42. APIs Method MethodMethod Class
  43. 43. APIs Method MethodMethod Class ClassClass Package
  44. 44. APIs Method MethodMethod Class ClassClass Package PackagePackage Library
  45. 45. APIs Method MethodMethod Class ClassClass Package PackagePackage Library Framework LibraryLibrary
  46. 46. What Makes A Good API?
  47. 47. A Good API Does One Thing
  48. 48. A Good API Never Changes
  49. 49. A Good API Behaves Like Its Contract
  50. 50. A Good API Has A Narrow Responsibility
  51. 51. A Good API Depends Upon Abstractions
  52. 52. And That’s SOLID Code
  53. 53. S - Single Responsibility Principle O- L - I - D- A Good API Does One Thing
  54. 54. S - Single Responsibility Principle O- Open / Closed Principle L - I - D- A Good API Never Changes
  55. 55. S - Single Responsibility Principle O- Open / Closed Principle L - Liskov Substitution Principle I - D- A Good API Behaves Like Its Contract
  56. 56. S - Single Responsibility Principle O- Open / Closed Principle L - Liskov Substitution Principle I - Interface Segregation Principle D- A Good API Has A Narrow Responsibility
  57. 57. S - Single Responsibility Principle O- Open / Closed Principle L - Liskov Substitution Principle I - Interface Segregation Principle D- Dependency Inversion Principle A Good API Depends Upon Abstractions
  58. 58. S - Single Responsibility Principle O- Open / Closed Principle L - Liskov Substitution Principle I - Interface Segregation Principle D- Dependency Inversion Principle
  59. 59. Note That SOLID Does Not Dictate What Is Good OOP
  60. 60. SOLID Emerges From Good OOP
  61. 61. So, What Makes A Bad API?
  62. 62. Global Variables (Spooky Action At A Distance)
  63. 63. Depending On Specifics Of An Implementation
  64. 64. Hidden Dependencies
  65. 65. Unhealthy Focus On Performance
  66. 66. Poorly Named APIs
  67. 67. Duplication
  68. 68. And That’s STUPID Code
  69. 69. S - Singletons T - U - P - I - D- Global Variables (Spooky Action At A Distance)
  70. 70. S - Singletons T - Tight Coupling U - P - I - D- Depending On Specifics Of An Implementation
  71. 71. S - Singletons T - Tight Coupling U - Untestable Code P - I - D- Hidden Dependencies
  72. 72. S - Singletons T - Tight Coupling U - Untestable Code P - Premature Optimization I - D- Unhealthy Focus On Performance
  73. 73. S - Singletons T - Tight Coupling U - Untestable Code P - Premature Optimization I - Indescriptive Naming D- Poorly Named APIs
  74. 74. S - Singletons T - Tight Coupling U - Untestable Code P - Premature Optimization I - Indescriptive Naming D- Duplication Duplication Duplication DuplicationDuplication Duplication Duplication Duplication Duplication
  75. 75. S - Singletons T - Tight Coupling U - Untestable Code P - Premature Optimization I - Indescriptive Naming D- Duplication
  76. 76. STUPID Embodies Lessons Learned From Bad OOP
  77. 77. What Good OOP Gives You Modular Code Reusable Code Extendable Code Easy To Read Code Maintainable Code Easy To Change Code Easy To Understand Code Clean Abstractions (mostly)
  78. 78. What Good OOP Costs You Tends To Have More “Layers” Tends To Be Slower At Runtime Tends To Have Larger Codebases Tends To Result In Over-Abstraction Tends To Require More Effort To Write Tends To Require More Tacit Knowledge
  79. 79. Let’s Look At Some Code!
  80. 80. interface Car { public function turnLeft(); public function turnRight(); public function goFaster(); public function goSlower(); public function shiftUp(); public function shiftDown(); public function start(); }
  81. 81. interface Steerable { public function steer($angle); } interface Acceleratable { public function accelerate($amt); } interface Shiftable { public function shiftDown(); public function shiftUp(); }
  82. 82. Let’s Look At Drupal Code!
  83. 83. interface MailSystemInterface { public function format(array $message); public function mail(array $message); }
  84. 84. interface MailSystemInterface { public function format(array $message); public function mail(array $message); } What Responsibility?
  85. 85. interface MailSystemInterface { public function format(array $message); public function mail(array $message); } What Responsibility? Formatting Messages
  86. 86. interface MailSystemInterface { public function format(array $message); public function mail(array $message); } What Responsibility? Formatting Messages Encoding Messages
  87. 87. interface MailSystemInterface { public function format(array $message); public function mail(array $message); } What Responsibility? Formatting Messages Encoding Messages Assembling Headers
  88. 88. interface MailSystemInterface { public function format(array $message); public function mail(array $message); } What Responsibility? Formatting Messages Encoding Messages Assembling Headers Calling Sendmail
  89. 89. interface MailSystemInterface { public function format(array $message); public function mail(array $message); } What Responsibility? Formatting Messages Encoding Messages Assembling Headers Calling Sendmail Setting INI settings…?
  90. 90. interface MailSystemInterface { public function format(array $message); public function mail(array $message); } What Responsibility? Open For Extension?
  91. 91. interface MailSystemInterface { public function format(array $message); public function mail(array $message); } What Responsibility? Open For Extension? Edits Require Copy/Paste
  92. 92. interface MailSystemInterface { public function format(array $message); public function mail(array $message); } What Responsibility? Open For Extension? Liskov Substitution...
  93. 93. interface MailSystemInterface { public function format(array $message); public function mail(array $message); } What Responsibility? Open For Extension? Liskov Substitution... One Interface... Many Responsibilites
  94. 94. interface MailSystemInterface { public function format(array $message); public function mail(array $message); } What Responsibility? Open For Extension? Liskov Substitution... One Interface... What Dependencies?
  95. 95. interface MessageFormatter { public function format(Message $message); } interface MessageEncoder { public function encode(Message $message); } interface MessageTransport { public function send(Message $message); }
  96. 96. class MailSystem { public function __construct( MessageFormatter $messageFormatter, MessageEncoder $messageEncoder, MessageTransport $messageTransport ) {} public function mail(Message $message); }
  97. 97. Principle Of Good Enough
  98. 98. Anthony Ferrara bit.ly/prague-solid-talk @ircmaxell blog.ircmaxell.com me@ircmaxell.com youtube.com/ircmaxell

×