SOLID PHP & Code Smell Wrap-Up
description
Transcript of SOLID PHP & Code Smell Wrap-Up
![Page 1: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/1.jpg)
1
SOLID PHP & Code Smell Wrap-Up
LSP: Liskov substitution principleISP: Interface segregation principle
DIP: Dependency inversion principle
![Page 2: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/2.jpg)
2
SOLID PHP & Code Smell Wrap-Up
LSP: Liskov substitution principleDIP: Dependency inversion principleISP: Interface segregation principle
![Page 3: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/3.jpg)
3
Review
• SOLID is an acronym for a set of design principles by Robert “Uncle Bob” Martin
• SRP: Single Responsibility principle – Objects should only have one responsibility
• OCP: Open/closed principle – Objects open for extension but closed for modification
![Page 4: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/4.jpg)
4
LSP: Liskov substitution principle
• Objects should always be able to stand-in for their ancestors
• Named after Barbara Liskov who first introduced the principal
![Page 5: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/5.jpg)
5
DIP: Dependency inversion principle
• Define interfaces from the bottom-up, not top-down
• Depend on interfaces, not on concrete classes
![Page 6: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/6.jpg)
6
ISP: Interface segregation principle
• “many client specific interfaces are better than one general purpose interface.”
![Page 7: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/7.jpg)
7
LSP Example: Rectangle & Square
• The Rectangle and Square are the “standard” example of an LSP problem.
• A Square IS-A Rectangle which happens to have the same width and height:
Square RectangleIS-A
![Page 8: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/8.jpg)
8
LSP Example: Rectangle & Square
• Lets look at an implementation and unit test
• Squares don’t BEHAVE like rectangles, so they violate LSP
Square RectangleBEHAVIOUR
![Page 9: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/9.jpg)
9
More Obvious LSP Violationsclass FooMapper {
function fetchAll() {return array('a588ea995c5c74827a24d466d14a72101'=>'Alpha', 'z4c853bae4a5e427a8d6b9bf33140bb2e'=>'Omega');}
} class BarMapper extends FooMapper {
function fetchAll() {$result = new stdClass();$result->a588ea995c5c74827a24d466d14a72101 = 'Alpha';$result->z4c853bae4a5e427a8d6b9bf33140bb2e = 'Omega';return $result;}
}
![Page 10: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/10.jpg)
10
More Obvious LSP Violations
class FooView {function display(FooModel $foo) { /* ...
*/ }} class BarView extends FooView {
function display(BarModel $bar) { /* ... */ }}
![Page 11: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/11.jpg)
11
More Obvious LSP Violations
• Removing functionality from an ancestor:
class DecoyDuck extends Duck{ function fly() { throw new Exception( "Decoy ducks can't fly!"); }}
![Page 12: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/12.jpg)
12
Is this an LSP Violation?
class Foo {function getMapper() {return new FooMapper();}
} class Bar extends Foo {
function getMapper() {return new BarMapper();}
}
![Page 13: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/13.jpg)
13
Preventing LSP Violations
• Design by Contract with Unit Tests
• Think in terms of BEHAVES-LIKE instead of IS-A when creating subclasses
• Don’t remove functionality from ancestors
![Page 14: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/14.jpg)
14
Preventing LSP Violations
• Method parameters should be the same or less restrictive in what they will accept (invariant or contravariant)
• Method return values should be the same or more restrictive in what is returned (invariant or covariant)
![Page 15: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/15.jpg)
15
Smells like an LSP Violation
• Any time you need to know the type of an object (instanceof, is_a, etc)
• When the parameters or return type of an overridden method are different from its ancestor
• Throwing new exceptions
![Page 16: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/16.jpg)
16
DIP: What is Inversion?
Conventional MVC Dependencies:
Controller
Model View
Storage
![Page 17: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/17.jpg)
17
DIP: What is Inversion?
Inverted MVC Dependencies:
Controller
Model View
Storage
Model ServiceInterface
View ServiceInterface
Storage ServiceInterface
![Page 18: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/18.jpg)
18
DIP Concepts
• Concrete classes only have dependencies to interfaces
• High level components build interfaces for the services they need
• Low level components depend on those high level service interfaces
![Page 19: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/19.jpg)
19
Evolving towards the DIP
class FooControllerConventional{
function indexView() {$model = new FooModel();$viewData = $model->fetchAll();$view = new FooView();$view->render($viewData);}
}
![Page 20: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/20.jpg)
20
Evolving towards the DIPclass FooControllerDI{
private $_model;private $_view;
function __construct(FooModel $model, FooView $view) {$this->_model = $model;$this->_view = $view;}
function indexView() {$viewData = $this->_model->fetchAll();$this->_view->render($viewData);}
}
![Page 21: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/21.jpg)
21
Evolving towards the DIP
interface ModelServiceInterface {function fetchAll();//… Other required methods
} interface ViewServiceInterface {
function render($viewData);//… Other required methods
}
![Page 22: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/22.jpg)
22
Evolving towards the DIPclass FooControllerDIP{
private $_model;private $_view;
function __construct(ModelServiceInterface $model, ViewServiceInterface $view) {$this->_model = $model;$this->_view = $view;}
function indexView() {$viewData = $this->_model->fetchAll();$this->_view->render($viewData);}
}
![Page 23: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/23.jpg)
23
Smells like a DIP Violation
• Any dependency by one class on another concrete class: “Hard Dependency Smell”
![Page 24: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/24.jpg)
24
Interface Segregation Principle
• Useful for “fat” classes. These classes:
– May violate SRP
– May have an “extra” method for a specific client
– May have one responsibility which can be further segregated
![Page 25: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/25.jpg)
25
ISP Example: User Modelclass UserModel {
/** * @param string $userId * @param string $password * @return string Authentication Token; empty string on failure */function doLogin($userId, $password) {}/** * @param string $token * @return bool */function authenticate($token) {}
}
Most clients just want to authenticate.
Only the login controller uses doLogin().
![Page 26: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/26.jpg)
26
ISP Example: User Model
interface UserLoginClient {function doLogin($userId, $password);
} interface UserAuthenticationClient {
function authenticate($token);}
![Page 27: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/27.jpg)
27
Smells Like an ISP Violation
• Fat Classes, “God Objects”
• Methods only used by a few clients but pollute the interface used by all clients
![Page 28: SOLID PHP & Code Smell Wrap-Up](https://reader035.fdocuments.us/reader035/viewer/2022062410/568162ec550346895dd36d2c/html5/thumbnails/28.jpg)
28
Thanks Folks!
• Thanks for joining me for the SOLID wrap up!
• If we have time, I have some code we can refactor to play with LSP, DIP and ISP
• Slides and code will be posted shortly
• Next week: CakePHP and Facebook Apps!