Your SlideShare is downloading. ×
2013 - Benjamin Eberlei: Hacé tu proyecto SOLID!
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

2013 - Benjamin Eberlei: Hacé tu proyecto SOLID!

109

Published on

PHP Conference Argentina

PHP Conference Argentina

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
109
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Make Your Project SOLID PHP Conference Argentina 2013 Benjamin Eberlei, @beberlei 4th October 2013
  • 2. About me Helping people to create high quality web applications. http://qafoo.com Doctrine Developer Symfony Contributor Twitter @beberlei and @qafoo
  • 3. About me Helping people to create high quality web applications. http://qafoo.com Doctrine Developer Symfony Contributor Twitter @beberlei and @qafoo
  • 4. About me Helping people to create high quality web applications. http://qafoo.com Doctrine Developer Symfony Contributor Twitter @beberlei and @qafoo
  • 5. About me Helping people to create high quality web applications. http://qafoo.com Doctrine Developer Symfony Contributor Twitter @beberlei and @qafoo
  • 6. About me Helping people to create high quality web applications. http://qafoo.com Doctrine Developer Symfony Contributor Twitter @beberlei and @qafoo
  • 7. Why Object Orientation? So, why do you want object oriented code? Manage complexity Reusable code Maintainable code
  • 8. Why Object Orientation? So, why do you want object oriented code? Manage complexity Reusable code Maintainable code
  • 9. Why Object Orientation? So, why do you want object oriented code? Manage complexity Reusable code Maintainable code
  • 10. Why Object Orientation? So, why do you want object oriented code? Manage complexity Reusable code Maintainable code
  • 11. The SOLID principles 5 essential principles of object oriented design Introduced by Robert C. Martin (Uncle Bob) not the inventor of the principles Have proven to lead to better code Scientific background (partly)
  • 12. By Example A weather loader component Fetch weather for a city Relevant data: Condition Temperature Wind Be service-agnostic Weather service come and go Data licenses may change Log service failures Make it possible to add service fallbacks later
  • 13. Single Responsibility Principle “There should never be more than one reason for a class to change.”
  • 14. The Issue 1 <?php 2 3 class GoogleWeatherService 4 { 5 public function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) 6 { $xml = $ t h i s −> getData ( $ l o c a t i o n ) ; $weather = $ t h i s −> e x t r a c t W e a t h e r ( $xml ) ; r e t u r n $weather ; 7 8 9 } 10 11 12 protected function e x t r a c t W e a t h e r ( $xml ) 13 { $weather = new Weather ( ) ; $weather −> c o n d i t i o n s = $ t h i s −> p a r s e C o n d i t i o n s ( $xml ) ; // ... $weather −>windSpeed = $ t h i s −> c o n v e r t M i l e s T o K i l o m e t e r ( $ t h i s −>parseWindSpeed ( $xml ) ); r e t u r n $weather ; 14 15 16 17 18 19 20 } 21 22 /∗ . . . ∗/ 23 24 }
  • 15. The Fix 1 <?php 2 3 class GoogleWeatherService 4 { public function construct ( H t t p C l i e n t $ c l i e n t , GoogleDataParser $ p a r s e r ) { /∗ . . . ∗/ } 5 6 7 8 public function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) 9 { 10 $xml = $ t h i s −> c l i e n t −> g e t ( s p r i n t f ( ’ h t t p : / / . . . / ? c i t y=%s ’ , $ l o c a t i o n −> c i t y ) ); r e t u r n $ t h i s −> parser −> parseWeather ( $xml ) ; 11 12 13 14 15 } 16 17 }
  • 16. Single Responsibility Principle One responsibility per class Separation of concerns Responsibilities hard to detect
  • 17. Single Responsibility Principle One responsibility per class Separation of concerns Responsibilities hard to detect
  • 18. Open/Close Principle “Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.”
  • 19. The Wrong Way 3 class WeatherLoader 4 { public function { /∗ . . . ∗/ } 5 6 construct ( $service ) 7 8 public function getWeatherForLocation ( S t r u c t L o c a t i o n $ l o c a t i o n ) 9 { 11 // ... switch ( g e t c l a s s ( $ t h i s −> s e r v i c e ) ) 12 { 10 case ’ GoogleWeatherService ’ : r e t u r n $ t h i s −> s e r v i c e −> getWeather ( $ l o c a t i o n ) ; 13 14 15 case ’ WetterComWeatherService ’ : r e t u r n $ t h i s −> s e r v i c e −> r e t r i e v e W e a t h e r ( $ l o c a t i o n −> c i t y , $ l o c a t i o n −> c o u n t r y ); // ... 16 17 18 19 20 } 21 } 22 23 }
  • 20. The Right Way 3 class WeatherLoader 4 { public function { /∗ . . . ∗/ } 5 6 c o n s t r u c t ( WeatherService $ s e r v i c e ) 7 8 public function getWeatherForLocation ( S t r u c t L o c a t i o n $ l o c a t i o n ) 9 { // ... r e t u r n $ t h i s −> s e r v i c e −> getWeatherForLocation ( $ l o c a t i o n ) ; 10 11 } 12 13 }
  • 21. Open/Close Principle Changes introduce errors Especially cascading changes Ideally: Write once, change never! Extend software only by new code New interface implementations Inheritance Aggregation
  • 22. Liskov Substitution Principle “Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.”
  • 23. A Simple Class 1 <?php 2 3 class D i s t a n c e C o n v e r t e r 4 { const FACTOR = 0 . 6 2 1 4 ; 5 6 7 public function m i l e s T o K i l o m e t e r s ( $ m i l e s ) 8 { r e t u r n $ m i l e s / s e l f : : FACTOR; 9 } 10 11 }
  • 24. Getting into Trouble 1 <?php 2 3 class F o r m a t t i n g D i s t a n c e C o n v e r t e r extends DistanceConverer 4 { 5 public function m i l e s T o K i l o m e t e r s ( $ m i l e s ) 6 { 7 i f ( $miles < 0 ) 8 { throw new I n v a l i d A r g u m e n t E x c e p t i o n ( ) ; 9 10 } 11 return s p r i n t f ( ’ %01.2 f km ’ , p a r e n t : : m i l e s T o K i l o m e t e r s ( $ m i l e s ) ); 12 13 } 14 15 }
  • 25. Liskov Substitution Principle Be less strict on input Be more strict on output
  • 26. Liskov Substitution Principle Be less strict on input Be more strict on output float milesToKilometers($miles) float
  • 27. Liskov Substitution Principle Be less strict on input Be more strict on output float >0 milesToKilometers($miles) float
  • 28. Liskov Substitution Principle Be less strict on input Be more strict on output float milesToKilometers($miles) string or float
  • 29. Liskov Substitution Principle Be less strict on input Be more strict on output float or string milesToKilometers($miles) float
  • 30. Liskov Substitution Principle Be less strict on input Be more strict on output float milesToKilometers($miles) >0 float
  • 31. Liskov Substitution Principle Do not change contracts by inheritance Methods must work as expected in derived classes Users must not distinguish between super- and subclass Subtype polymorphism
  • 32. Liskov Substitution Principle Do not change contracts by inheritance Methods must work as expected in derived classes Users must not distinguish between super- and subclass Subtype polymorphism
  • 33. Dependency Inversion Principle “A. High-level modules should not depend on low level modules. Both should depend on abstractions.” “B. Abstractions should not depend upon details. Details should depend upon abstractions.”
  • 34. Dependency Inversion Principle “A. High-level modules should not depend on low level modules. Both should depend on abstractions.” “B. Abstractions should not depend upon details. Details should depend upon abstractions.”
  • 35. The Issue 1 <?php 2 3 class WeatherLoader 4 { 6 public function construct ( GoogleWeatherService $weatherService , F i l e L o g g e r $ l o g g e r ) 7 { 5 $ t h i s −> w ea th e rS er v ic e = $weatherService ; $ t h i s −> l o g g e r = $logger ; 8 9 10 } 11 public function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) 12 { // ... $ t h i s −> l o g g e r −> l o g ( ’Some l o g message . ’ ) ; // ... $ t h i s −> l o g g e r −> w r i t e T o F i l e ( ) ; 13 14 15 16 } 17 18 }
  • 36. Doing it Right 1 <?php 2 3 class WeatherLoader 4 { 6 public function construct ( WeatherService $weatherService , Logger $ l o g g e r ) 7 { 5 $ t h i s −> w ea th e rS er v ic e = $weatherService ; $ t h i s −> l o g g e r = $logger ; 8 9 10 } 11 public function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) 12 { // ... $ t h i s −> l o g g e r −> l o g ( ’Some l o g message . ’ ) ; // ... 13 14 15 } 16 17 }
  • 37. Dependency Inversion Principle Use abstraction to encapsulate low level modules Abstractions are the APIs Abstractions hide implementation details Depend on interfaces, not realizations Define interfaces from a usage point of view Finding abstractions is not easy Dependency Injection, anyone?
  • 38. Dependency Inversion Principle Use abstraction to encapsulate low level modules Abstractions are the APIs Abstractions hide implementation details Depend on interfaces, not realizations Define interfaces from a usage point of view Finding abstractions is not easy Dependency Injection, anyone?
  • 39. Dependency Inversion Principle Use abstraction to encapsulate low level modules Abstractions are the APIs Abstractions hide implementation details Depend on interfaces, not realizations Define interfaces from a usage point of view Finding abstractions is not easy Dependency Injection, anyone?
  • 40. Dependency Inversion Principle Use abstraction to encapsulate low level modules Abstractions are the APIs Abstractions hide implementation details Depend on interfaces, not realizations Define interfaces from a usage point of view Finding abstractions is not easy Dependency Injection, anyone?
  • 41. Interface Segregation Principle “Clients should not be forced to depend upon interfaces that they do not use.”
  • 42. Suboptimal 3 class Loader 4 { public function { /∗ . . . ∗/ } 5 6 c o n s t r u c t ( WeatherService $weatherService , Logger $ l o g g e r ) 7 public function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) { /∗ . . . ∗/ } 8 9 10 } 3 a b s t r a c t class WeatherService 4 { a b s t r a c t public function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) ; 5 6 a b s t r a c t public function g e t F o r e c a s t F o r L o c a t i o n ( L o c a t i o n $ l o c a t i o n , $weekDay ) ; 7 8 }
  • 43. The Fix 1 interface LocationWeatherProvider 2 { function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) ; 3 4 } 1 a b s t r a c t class WeatherService implements L o c a t i o n W e a t h e r P r o v i d e r 2 { a b s t r a c t public function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) ; 3 4 a b s t r a c t public function g e t F o r e c a s t F o r L o c a t i o n ( L o c a t i o n $ l o c a t i o n , $weekDay ) ; 5 6 } 1 class Loader 2 { public function { /∗ . . . ∗/ } 3 4 c o n s t r u c t ( L o c a t i o n W e a t h e r P r o v i d e r $ p r o v i d e r , Logger $ l o g g e r ) 5 public function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) { /∗ . . . ∗/ } 6 7 8 }
  • 44. The Fix 1 interface LocationWeatherProvider 2 { function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) ; 3 4 } 1 a b s t r a c t class WeatherService implements L o c a t i o n W e a t h e r P r o v i d e r 2 { a b s t r a c t public function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) ; 3 4 a b s t r a c t public function g e t F o r e c a s t F o r L o c a t i o n ( L o c a t i o n $ l o c a t i o n , $weekDay ) ; 5 6 } 1 class Loader 2 { public function { /∗ . . . ∗/ } 3 4 c o n s t r u c t ( L o c a t i o n W e a t h e r P r o v i d e r $ p r o v i d e r , Logger $ l o g g e r ) 5 public function getWeatherForLocation ( L o c a t i o n $ l o c a t i o n ) { /∗ . . . ∗/ } 6 7 8 }
  • 45. Interface Segregation Principle Avoid not needed dependencies Design interfaces from a usage point of view Do not let unnecessary functionality float in
  • 46. The SOLID principles Single Responsibility Principle Open/Closed Principle Liskov Substitution Principle Interface Segregation Principle Dependency Inversion Principle

×