• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Dependency Injection for Wordpress
 

Dependency Injection for Wordpress

on

  • 4,969 views

 

Statistics

Views

Total Views
4,969
Views on SlideShare
2,270
Embed Views
2,699

Actions

Likes
2
Downloads
10
Comments
0

10 Embeds 2,699

http://www.toppa.com 2375
http://wpdaily.co 238
http://feeds.feedburner.com 51
http://bheimseinblog.de 13
http://translate.googleusercontent.com 8
http://localhost 4
http://torquemag.io 4
http://bheimchaoten.de 3
http://webcache.googleusercontent.com 2
http://207.46.192.232 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • This means different things to different people Smashing Magazine article compared them in terms of: Structure – short line lengths, indentions Purpose – limericks for humor, not using HTML tables for layout Meaning and Efficiency – how intent is conveyed, how bloat is avoided Perception – perceived as the master's craft “apex of the written word” - custom wooden staircases parallel But while we can appreciate poetry with hidden meaning and indirection, that's not what we want in our code
  • Easy to understand Intention revealing: not just what, but also why Easy to change Adaptable to emerging needs: not fragile, not rigid Reusable (DRY) If we copy and paste, we are creating duplicate code we have to maintain Bug free Broken code costs time, money, and reputation
  • Tight deadlines Too much work Changing requirements Too many useless meetings Other people's messy code Our messy code Just make it work and get on to the next thing!
  • And launching buggy code can cost money and reputation
  • The exact shape of these lines is hotly debated May projects have ultimately failed because of the steep cost curve of messy code
  • Design patterns you may know or heard of, are ways of expressing these design principles
  • To explain dependency injection, I need to explain the DIP, and to explain it, I first need to explain the SRP
  • I'm going to show SRP and DIP examples of code from Shashin
  • Clean code books and articles all use other languages as examples – I wanted to try applying them to PHP and WordPress
  • Shashin supports multiple viewers
  • There's a lot going on here. A lot of different data sources and display possibilities to support. How do you keep the code from becoming a tangled mess?
  • Do one thing, do it well, do it only For methods, this typically means changing the value of only one variable If you are passing more than 2 or 3 arguments into a method, you are probably doing more than one thing For classes, it means having a single conceptual responsibility You want high cohesiveness in a class This is the opposite of how most WordPress plugins are written
  • The whole class is about 150 lines The run method calls the other methods (this is a simple use of the command pattern) It reads like a table of contents Breaking the functionality down into methods that do one thing makes the code easier to read and to unit test Installation is especially useful to break down into small methods that can have automated tests, as plugin activation is especially difficult to debug
  • spl_autoloader_register allows you to register a function that will be called when PHP encounters a “new” call, for finding and including the file containing the class. You can register more than one function.
  • The problem is, this conflicts with WordPress naming conventions
  • It's common to see code that hard-wires together all the parts, when those connections could be made more flexible and extensible
  • This solution violates the DIP Button depends directly on Lamp Button is not reusable It can't control, for example, a Motor
  • What it means Neither Button nor Lamp “own” the interface Buttons can now control any device that implements SwitchableDevice Lamps and other SwitchableDevices can now be controlled by any object that accepts a SwitchableDevice
  • Not shown here is the interface
  • Author: Steve Freeman and Nat Pryce
  • There was one thing that was ok in the naïve example – we were at least passing in the lamp object Instantiating it directly in the class makes your code impossible to unit test
  • Factory pattern, adapter patter, service locator pattern are others that implement the DIP
  • Constructor injection gives you a valid object, with all its dependencies, upon construction But constructor injection becomes hard to read and use when there are more than a few objects to inject More about this in an upcoming slide...
  • We want loose coupling, not a rigid chain of dependencies that is hard to change
  • I am making the objects properties of the container, because they happen to be immutable objects, so they are reusable You can see I'm using constructor injection I'll explain in a minute why I called it a “clonable” photo
  • Start with constructor injection As your design evolves, switch to setter injection once there are more than 2 objects to inject If you rely on an injection container, you don't have to worry about forgetting to call a required setter
  • This was an interesting problem for me with Shashin. It supports multiple media sources (Picasa, etc), multiple viewers (Fancybox, etc), and we could be displaying a photo or an album cover, each of which has different behaviors
  • Regardless of the type, the layout rules for the thumbnails is always the same So here I've injected the container itself getDataObjectDisplayer() uses the passed in arguments to determine which subtype of DataObjectDisplayer to return
  • The complexity of having 44 classes in Shashin is justified by its need for flexibility You can support a new viewer or a new photo service simply by creating a new subclass. This is much more maintainable and extensible than a single huge file with deeply nested conditionals and unclear dependencies But if I knew I would never need that kind of flexibility, there would be no justification for creating these layers of abstraction – they would just be needless complexity

Dependency Injection for Wordpress Dependency Injection for Wordpress Presentation Transcript

  • Dependency Injection for WordPress Plugin Development Mike Toppa WordCamp Nashville April 21, 2012 #wcn12www.toppa.com @mtoppa
  • Mike Toppa● Director of Development, WebDevStudios● 17 years of experience in web development, project management, and team management● Universities: Georgetown, Stanford, Penn● Dot coms: E*Trade, Ask Jeeves● Start-ups: Finexa, Kais Candy Co● WordPress development for non-profitswww.toppa.com @mtoppa
  • Code is Poetrywww.toppa.com @mtoppa
  • We want code to be...● Easy to understand● Easy to change● Reusable (DRY)● Bug freewww.toppa.com @mtoppa
  • So why is it usually like this?“O.P.C” http://abstrusegoose.com/432
  • It happens because we are always in a hurry, and requirements are always changing.www.toppa.com @mtoppa
  • But coding fast and dirty only makes us slower in the long run.www.toppa.com @mtoppa
  • “We like to think we spend our time power typing, but we actually spend most of our time staring into the abyss.” - Douglas Crockford principal discoverer of JSON, Creator of JSLintwww.toppa.com @mtoppa
  • The ratio of time spent reading code versus writing is well over 10 to 1. Therefore, making code easy to read makes it easier to write. - Bob Martin Paraphrased from his book Clean Codewww.toppa.com @mtoppa
  • Clean code saves time, saves $$www.toppa.com @mtoppa
  • Clean code techniques● Using meaningful names● Dont repeat yourself (DRY)● Object oriented principles and patterns● Unit testing, test driven development (TDD)● The “boy scout rule”● Vertical slicing● ...and many morewww.toppa.com @mtoppa
  • Clean code techniques● Using meaningful names● Dont repeat yourself (DRY)● Object oriented principles and patterns● Unit testing, test driven development (TDD)● The “boy scout rule”● Vertical slicing● ...and many morewww.toppa.com @mtoppa
  • The SOLID Principles● Single Responsibility (SRP)● Open-Closed (OCP)● Liskov Substitution (LSP)● Interface Segregation (ISP)● Dependency Inversion (DIP)www.toppa.com @mtoppa
  • The SOLID Principles● Single Responsibility (SRP)● Open-Closed (OCP)● Liskov Substitution (LSP)● Interface Segregation (ISP)● Dependency Inversion (DIP)www.toppa.com @mtoppa
  • Shashin My plugin for displaying albums, photos, and videos from Picasa, Twitpic, and YouTube (and others coming soon)www.toppa.com @mtoppa
  • I used the new version as a test case for applying clean code principles to WordPress pluginswww.toppa.com @mtoppa
  • From LosTechies.com
  • My Shashin plugin consists of 44 classes, each of which has a meaningful name, follows the SRP, and “does one thing” PicasaPhotoDisplayer SettingsMenu YouTubeSynchronizer Uninstall etc.www.toppa.com @mtoppa
  • Shashin exampleclass Admin_ShashinInstall { // ... public function run() { $this->createAlbumTable(); $this->verifyAlbumTable(); $this->createPhotoTable(); $this->verifyPhotoTable(); $this->updateSettings(); return true; } // ...}www.toppa.com @mtoppa
  • Class Autoloading● The problem: ● PHP lacks an equivalent statement to “import” or “use” for classes ● Having to hardcode a bunch of file paths is extra work, and makes code harder to change● The solution: ● PHP 5.1.2 and spl_autoload_register() ● PHP Standards Working Group: PSR-0www.toppa.com @mtoppa
  • PSR-0: Official Description● Each "_" character in the CLASS NAME is converted to a DIRECTORY_SEPARATOR● The fully-qualified namespace and class is suffixed with ".php" when loading from the file system● Alphabetic characters... may be of any combination of lower case and upper case● ...And other rules about namespaces● Source: https://github.com/php-fig/fig- standards/blob/master/accepted/PSR-0.mdwww.toppa.com @mtoppa
  • PSR-0 Example Admin_ShashinInstall is translated to Admin/ShashinInstall.phpwww.toppa.com @mtoppa
  • Toppa Plugin Libraries Autoloader// this is at the top of the main file for my Shashin pluginrequire_once dirname(__FILE__) . /../toppa-plugin-libraries-for-wordpress/ToppaAutoLoaderWp.php;$shashinAutoLoader = new ToppaAutoLoaderWp(/shashin);// thats it! I can now call “new” on any class under the shashin folder// and its class file will be automatically loadedwww.toppa.com @mtoppa
  • Shashins capabilities are shaped by how its objects are wired together, through implementation of the Dependency Inversion Principlewww.toppa.com @mtoppa
  • From LosTechies.com
  • Naïve model of a button and lamp Lamp Button + turnOn() + poll() + turnOff()class Button { private $lamp; public function __construct(Lamp $lamp) { $this->lamp = $lamp; } public function poll() { if (/* some condition */) { $this->lamp->turnOn(); } }} Example from “Agile Software Development”
  • Dependency inversion applied <<interface>> Button SwitchableDevice + poll() + turnOn() + turnOff() Lamp This is the Abstract Server pattern
  • class Lamp implements SwitchableDevice { public function turnOn() { // code } public function turnOff() { // code }}class Button { private $switchableDevice; public function __construct(SwitchableDevice $switchableDevice) { $this->switchableDevice = $switchableDevice; } public function poll() { if (/* some condition */) { $this->switchableDevice->turnOn(); } }}
  • A web of collaborating objects● The SRP and DIP together drive a “composition” approach to OO design● From Growing Object Oriented Software, Guided by Tests: "An object oriented system is a web of collaborating objects... The behavior of the system is an emergent property of the composition of the objects - the choice of objects and how they are connected... Thinking of a system in terms of its dynamic communication structure is a significant mental shift from the static classification that most of us learn when being introduced to objects."
  • Composition (“Has a...”) vs. Inheritance (“Is a...”)www.toppa.com @mtoppa
  • The SRP is about objects that do one thing The DIP is about how to wire them together to create working, flexible softwarewww.toppa.com @mtoppa
  • Never, ever do thisclass Button { private $lamp; public function __construct() { $this->lamp = new Lamp(); } //...}www.toppa.com @mtoppa
  • Instead, you want to inject the object dependency Dependency injection!www.toppa.com @mtoppa
  • Dependency injection is one of many design patterns for implementing the Dependency inversion principlewww.toppa.com @mtoppa
  • It comes in two flavorswww.toppa.com @mtoppa
  • Constructor injectionpublic function __construct(SwitchableDevice $switchableDevice) { $this->switchableDevice = $switchableDevice;}www.toppa.com @mtoppa
  • Setter injectionpublic function setSwitchableDevice(SwitchableDevice $switchableDevice) { $this->switchableDevice = $switchableDevice;}www.toppa.com @mtoppa
  • Which to use? It dependswww.toppa.com @mtoppa
  • Dependency chains If class A depends on class B, and class B depends on class C, class A should be blissfully unaware of class Cwww.toppa.com @mtoppa
  • To do this without going insane, you need an injection containerwww.toppa.com @mtoppa
  • Example from Shashinclass Lib_ShashinContainer { // … public function getPhotoRefData() { if (!isset($this->photoRefData)) { $this->photoRefData = new Lib_ShashinPhotoRefData(); } return $this->photoRefData; } public function getClonablePhoto() { if (!isset($this->clonablePhoto)) { $this->getPhotoRefData(); $this->clonablePhoto = new Lib_ShashinPhoto($this->photoRefData); } return $this->clonablePhoto; }www.toppa.com @mtoppa
  • Example continued public function getClonablePhotoCollection() { if (!isset($this->photoCollection)) { $this->getClonablePhoto(); $this->getSettings(); $this->clonablePhotoCollection = new Lib_ShashinPhotoCollection(); $this->clonablePhotoCollection->setClonableDataObject($this->clonablePhoto); $this->clonablePhotoCollection->setSettings($this->settings); } return $this->clonablePhotoCollection; }www.toppa.com @mtoppa
  • Beyond the textbook exampleswww.toppa.com @mtoppa
  • What to do when you need a new object inside a loop One solution is cloningwww.toppa.com @mtoppa
  • Shashin Exampleclass Admin_ShashinSynchronizerPicasa extends Admin_ShashinSynchronizer { // … public function syncAlbumPhotos(array $decodedAlbumData) { // … foreach ($decodedAlbumData[feed][entry] as $entry) { $photoData = $this->extractFieldsFromDecodedData($entry, $photoRefData,picasa); // ... $photo = clone $this->clonablePhoto; $photo->set($photoData); $photo->flush(); }www.toppa.com @mtoppa
  • What if you need a new object inside a loop, but cant know the subtype youll need ahead of time? Let the injection container figure it outwww.toppa.com @mtoppa
  • Shashin Exampleclass Public_ShashinLayoutManager { // ... public function setTableBody() { // … for ($i = 0; $i < count($this->collection); $i++) { // ... $dataObjectDisplayer = $this->container->getDataObjectDisplayer( $this->shortcode, $this->collection[$i] ); $this->tableBody .= $dataObjectDisplayer->run(); // ... }www.toppa.com @mtoppa
  • Dependency injection: key benefits● Makes your object dependencies adaptable to emerging needs● With an injection container, simplifies managing dependency chains● Supports “preferring polymorphism to conditionals”, making it easy to add new class subtypeswww.toppa.com @mtoppa
  • Will this proliferation of objects eat up all my memory? Nowww.toppa.com @mtoppa
  • Use dependency injection to instantiate only the objects you need, when you need themwww.toppa.com @mtoppa
  • Make immutable objects into properties of the container, so you only need to instantiate them oncewww.toppa.com @mtoppa
  • PHP 5 has improved memory management“In PHP 5, the infrastructure of the object model wasrewritten to work with object handles. Unless youexplicitly clone an object by using the clone keyword youwill never create behind the scene duplicates of yourobjects. In PHP 5, there is neither a need to pass objectsby reference nor assigning them by reference.”From http://devzone.zend.com/article/1714www.toppa.com @mtoppa
  • But dont overdo it:avoid needless complexity