Clean code for WordPress plugin development Mike Toppa Philly WordCamp November 5, 2011
Mike Toppa Director, Web Applications, University of Pennsylvania, School of Medicine Information Services
15 years of experience in web development, project management, and functional management Universities: Georgetown, Stanford, Penn
Dot coms: E*Trade, Ask Jeeves
Start-ups: Finexa, Kai's Candy Co
WordPress development for non-profits
Shashin My plugin for displaying albums, photos, and videos from Picasa, Twitpic, and YouTube (and others coming soon)
I used the new version as a test case for applying clean code principles to WordPress plugins
 
 
 
 
What is clean code?
Clean code... “does one thing well” - Bjarne Stroustrup
“reads like well written prose” - Grady Booch
“can be read and enhanced by a developer other than its original author” - Dave Thomas
“always looks like it was written by someone who cares” - Michael Feathers
“contains no duplication” - Ron Jeffries
“turns out to be pretty much what you expected” - Ward Cunningham Quotes from “Clean Code” by Robert Martin
That sounds nice, but I have a deadline I don't have time for clean code!
Do you want your emergency room doctor to rush your surgery? Do you want your account to rush his work on your tax return? Analogy from “The Clean Coder”
The software craftsmanship movement
You  are responsible for the quality of your code And to truly go fast, you have to go clean
Why?
The time spent reading code compared to writing code is 10:1
Clean, modular code is flexible code, and can adapt to changing requirements
Clean code can be understood and enhanced by others
Clean code for WordPress Meaningful names
“A web of collaborating objects” The single responsibility principle (SRP)
The dependency inversion principle (DIP) Independent architecture The facade pattern Unit testing
Meaningful names
The name of a variable, function, or class should tell you why it exists, and what it does
If a name requires a comment, then the name does not reveal its intent
Not good $d; // elapsed time in days
Good $elapsedTimeInDays; $daysSinceCreation; $daysSinceModification;
Shashin example public function setNumericThumbnailSize($requestedSize = 'xsmall') { if (array_key_exists($requestedSize, $this->thumbnailSizesMap)) { $this->numericThumbnailSize = $this->thumbnailSizesMap[$requestedSize]; } elseif (is_numeric($requestedSize)) { $this->numericThumbnailSize = $requestedSize; } else { throw New Exception(__('invalid thumbnail size requested', 'shashin')); } return $this->numericThumbnailSize; }
The SOLID Principles S ingle Responsibility (SRP)
O pen-Closed (OCP)
L iskov Substitution (LSP)
I nterface Segregation (ISP)
D ependency Inversion (DIP)
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."
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.
class ShashinInstall { // ... public function run() { $this->createAlbumTable(); $this->verifyAlbumTable(); $this->createPhotoTable(); $this->verifyPhotoTable(); $this->updateSettings(); return true; } // ... } Shashin example
Shashin's capabilities are shaped by how these objects are wired together, through implementation of the DIP
From LosTechies.com
Naïve model of a button and lamp 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” Button + poll() Lamp + turnOn() + turnOff()

Clean code for WordPress

  • 1.
    Clean code forWordPress plugin development Mike Toppa Philly WordCamp November 5, 2011
  • 2.
    Mike Toppa Director,Web Applications, University of Pennsylvania, School of Medicine Information Services
  • 3.
    15 years ofexperience in web development, project management, and functional management Universities: Georgetown, Stanford, Penn
  • 4.
  • 5.
  • 6.
  • 7.
    Shashin My pluginfor displaying albums, photos, and videos from Picasa, Twitpic, and YouTube (and others coming soon)
  • 8.
    I used thenew version as a test case for applying clean code principles to WordPress plugins
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
    Clean code... “doesone thing well” - Bjarne Stroustrup
  • 15.
    “reads like wellwritten prose” - Grady Booch
  • 16.
    “can be readand enhanced by a developer other than its original author” - Dave Thomas
  • 17.
    “always looks likeit was written by someone who cares” - Michael Feathers
  • 18.
  • 19.
    “turns out tobe pretty much what you expected” - Ward Cunningham Quotes from “Clean Code” by Robert Martin
  • 20.
    That sounds nice,but I have a deadline I don't have time for clean code!
  • 21.
    Do you wantyour emergency room doctor to rush your surgery? Do you want your account to rush his work on your tax return? Analogy from “The Clean Coder”
  • 22.
  • 23.
    You areresponsible for the quality of your code And to truly go fast, you have to go clean
  • 24.
  • 25.
    The time spentreading code compared to writing code is 10:1
  • 26.
    Clean, modular codeis flexible code, and can adapt to changing requirements
  • 27.
    Clean code canbe understood and enhanced by others
  • 28.
    Clean code forWordPress Meaningful names
  • 29.
    “A web ofcollaborating objects” The single responsibility principle (SRP)
  • 30.
    The dependency inversionprinciple (DIP) Independent architecture The facade pattern Unit testing
  • 31.
  • 32.
    The name ofa variable, function, or class should tell you why it exists, and what it does
  • 33.
    If a namerequires a comment, then the name does not reveal its intent
  • 34.
    Not good $d;// elapsed time in days
  • 35.
  • 36.
    Shashin example publicfunction setNumericThumbnailSize($requestedSize = 'xsmall') { if (array_key_exists($requestedSize, $this->thumbnailSizesMap)) { $this->numericThumbnailSize = $this->thumbnailSizesMap[$requestedSize]; } elseif (is_numeric($requestedSize)) { $this->numericThumbnailSize = $requestedSize; } else { throw New Exception(__('invalid thumbnail size requested', 'shashin')); } return $this->numericThumbnailSize; }
  • 37.
    The SOLID PrinciplesS ingle Responsibility (SRP)
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
    A web ofcollaborating objects The SRP and DIP together drive a “composition” approach to OO design
  • 43.
    From GrowingObject 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."
  • 44.
  • 45.
    My Shashin pluginconsists of 44 classes, each of which has a meaningful name, follows the SRP, and “does one thing” PicasaPhotoDisplayer SettingsMenu YouTubeSynchronizer Uninstall etc.
  • 46.
    class ShashinInstall {// ... public function run() { $this->createAlbumTable(); $this->verifyAlbumTable(); $this->createPhotoTable(); $this->verifyPhotoTable(); $this->updateSettings(); return true; } // ... } Shashin example
  • 47.
    Shashin's capabilities areshaped by how these objects are wired together, through implementation of the DIP
  • 48.
  • 49.
    Naïve model ofa button and lamp 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” Button + poll() Lamp + turnOn() + turnOff()

Editor's Notes

  • #11 Stroustrup: inventor of C++ Booch: IBM chief scientist Thomas: founder of Object Technology International Feathers: author of Working Effectively with Legacy Code Jeffries: co-creator of XP development Cunnigham: inventor of Wikis
  • #13 Doctors take the Hippocratic oath and a set of practices to ensure they practice medicine safely Accounts are expected to do double entry booking, to avoid mistakes Other professions have standards for what it means to practice that profession safely and responsibly
  • #14 The software craftsmanship movement is a part of the Agile community, and is intended to start a conversation about what it means to write code responsibly and cleanly. You don't have to agree with the ideas, but you do need to engage them
  • #17 Code that is hard to read will slow you down Code that is easy to read frees you to go faster
  • #18 “Big ball of mud” code can't - it will eventually make you so slow, you'll want to throw it out and start over Talk about wasted time!
  • #19 Dirty code will drive away potential contributors
  • #20 I will probably need to save unit testing for a session in tomorrow's unconference time
  • #23 The revelation for me in learning clean code techniques is that code can be expressive. That it really can “read like well written prose.” Rather than relying on comments to explain your code, the code can explain itself Comments become something you have to maintain, and if they become outdated and no longer describe the current behavior of the code, they become dangerous lies
  • #26 Take a minute to read this Even without knowing the class or the properties, it's clear what this method does. You should use a 21 st century IDE, that auto-completes names for you and makes it easy to rename. I use PHP Storm
  • #27 Well written object oriented code follows these principles
  • #29 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
  • #31 The whole class is about 100 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
  • #33 It's common to see code that hard-wires together all the parts, when those connections could be made more flexible and extensible
  • #34 This solution violates the DIP Button depends directly on Lamp Changes to Lamp may require changes to Button Button is not reusable It can't control, for example, a Motor
  • #36 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 I'll provide a Shashin example after introducing one more concept
  • #38 Looking at the Shashin files and code, it screams “photo management and display!” It does not scream “WordPress plugin” The fact that it is a WordPress plugin is incidental to its design This makes it possible to do unit testing of your plugins, and makes them potentially usable outside of WordPress
  • #40 A different implementation of the facade would allow Shashin to work outside of WordPress, without touching Shashin code
  • #42 At the highest level, other CMS' or frameworks are not going to wire Shashin together to same way as WordPress. Also, since WordPress' hooks and filters return nothing, they are hard to mock for tests I need a better understanding of what other environments are like before I can design an interface with the appropriate flexibility
  • #43 This isolates the impact of changes that might be needed in the future, since I don't yet have a specific use case for Shashin outside of WordPress, but I want to be ready when the need comes
  • #44 Each function that is called instantiates the necessary objects for that hook. This approach is efficient. Shashin is a big plugin with a lot of files, but the only code loaded at runtime is the code needed
  • #45 Having an automated test suite can alert you to bugs before your customers find them TDD drives good design, but of all the clean code practices, is the hardest to learn how to do well
  • #46 Although PHPUnit is the standard, I chose to create a plugin for using SimpleTest with WordPress because: It's designed for web use and is very easy to subclass and package with a plugin It's approach to mock objects is easier to understand and use than PHPUnit's
  • #47 For my plugin, you create your tests, then in a shortcode give the path to the tests, and SimpleTest will run them. Since it's running within WordPress, you can also use it for integration testing (that is, calling actual WordPress functions will work)
  • #49 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