0
Clean code for WordPress plugin development Mike Toppa Philly WordCamp November 5, 2011
Mike Toppa <ul><li>Director, Web Applications, University of Pennsylvania, School of Medicine Information Services
15 years of experience in web development, project management, and functional management </li><ul><li>Universities: George...
Dot coms: E*Trade, Ask Jeeves
Start-ups: Finexa, Kai's Candy Co
WordPress development for non-profits </li></ul></ul>
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... <ul><li>“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 </li></ul>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?...
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 <ul><li>Meaningful names
“A web of collaborating objects” </li><ul><li>The single responsibility principle (SRP)
The dependency inversion principle (DIP) </li></ul><li>Independent architecture </li><ul><li>The facade pattern </li></ul>...
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, ...
The SOLID Principles <ul><li>S ingle Responsibility (SRP)
O pen-Closed (OCP)
L iskov Substitution (LSP)
I nterface Segregation (ISP)
D ependency Inversion (DIP) </li></ul>
A web of collaborating objects <ul><li>The SRP and DIP together drive a “composition” approach to OO design
From  Growing Object Oriented Software, Guided by Tests :  </li></ul>&quot;An object oriented system is a web of collabora...
From LosTechies.com
My Shashin plugin consists of 44 classes, each of which has a meaningful name, follows the SRP, and “does one thing” Picas...
class ShashinInstall { // ... public function run() { $this->createAlbumTable(); $this->verifyAlbumTable(); $this->createP...
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 = $la...
Upcoming SlideShare
Loading in...5
×

Clean code for WordPress

2,958

Published on

Wor

Published in: Technology
1 Comment
3 Likes
Statistics
Notes
No Downloads
Views
Total Views
2,958
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
30
Comments
1
Likes
3
Embeds 0
No embeds

No notes for slide
  • 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
  • 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
  • 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&apos;t have to agree with the ideas, but you do need to engage them
  • Code that is hard to read will slow you down Code that is easy to read frees you to go faster
  • “Big ball of mud” code can&apos;t - it will eventually make you so slow, you&apos;ll want to throw it out and start over Talk about wasted time!
  • Dirty code will drive away potential contributors
  • I will probably need to save unit testing for a session in tomorrow&apos;s unconference time
  • 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
  • Take a minute to read this Even without knowing the class or the properties, it&apos;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
  • Well written object oriented code follows these principles
  • 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 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
  • It&apos;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 Changes to Lamp may require changes to Button Button is not reusable It can&apos;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 I&apos;ll provide a Shashin example after introducing one more concept
  • 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
  • A different implementation of the facade would allow Shashin to work outside of WordPress, without touching Shashin code
  • At the highest level, other CMS&apos; or frameworks are not going to wire Shashin together to same way as WordPress. Also, since WordPress&apos; 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
  • This isolates the impact of changes that might be needed in the future, since I don&apos;t yet have a specific use case for Shashin outside of WordPress, but I want to be ready when the need comes
  • 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
  • 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
  • Although PHPUnit is the standard, I chose to create a plugin for using SimpleTest with WordPress because: It&apos;s designed for web use and is very easy to subclass and package with a plugin It&apos;s approach to mock objects is easier to understand and use than PHPUnit&apos;s
  • For my plugin, you create your tests, then in a shortcode give the path to the tests, and SimpleTest will run them. Since it&apos;s running within WordPress, you can also use it for integration testing (that is, calling actual WordPress functions will work)
  • 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
  • Transcript of "Clean code for WordPress"

    1. 1. Clean code for WordPress plugin development Mike Toppa Philly WordCamp November 5, 2011
    2. 2. Mike Toppa <ul><li>Director, Web Applications, University of Pennsylvania, School of Medicine Information Services
    3. 3. 15 years of experience in web development, project management, and functional management </li><ul><li>Universities: Georgetown, Stanford, Penn
    4. 4. Dot coms: E*Trade, Ask Jeeves
    5. 5. Start-ups: Finexa, Kai's Candy Co
    6. 6. WordPress development for non-profits </li></ul></ul>
    7. 7. Shashin My plugin for displaying albums, photos, and videos from Picasa, Twitpic, and YouTube (and others coming soon)
    8. 8. I used the new version as a test case for applying clean code principles to WordPress plugins
    9. 13. What is clean code?
    10. 14. Clean code... <ul><li>“does one thing well” - Bjarne Stroustrup
    11. 15. “reads like well written prose” - Grady Booch
    12. 16. “can be read and enhanced by a developer other than its original author” - Dave Thomas
    13. 17. “always looks like it was written by someone who cares” - Michael Feathers
    14. 18. “contains no duplication” - Ron Jeffries
    15. 19. “turns out to be pretty much what you expected” - Ward Cunningham </li></ul>Quotes from “Clean Code” by Robert Martin
    16. 20. That sounds nice, but I have a deadline I don't have time for clean code!
    17. 21. 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”
    18. 22. The software craftsmanship movement
    19. 23. You are responsible for the quality of your code And to truly go fast, you have to go clean
    20. 24. Why?
    21. 25. The time spent reading code compared to writing code is 10:1
    22. 26. Clean, modular code is flexible code, and can adapt to changing requirements
    23. 27. Clean code can be understood and enhanced by others
    24. 28. Clean code for WordPress <ul><li>Meaningful names
    25. 29. “A web of collaborating objects” </li><ul><li>The single responsibility principle (SRP)
    26. 30. The dependency inversion principle (DIP) </li></ul><li>Independent architecture </li><ul><li>The facade pattern </li></ul><li>Unit testing </li></ul>
    27. 31. Meaningful names
    28. 32. The name of a variable, function, or class should tell you why it exists, and what it does
    29. 33. If a name requires a comment, then the name does not reveal its intent
    30. 34. Not good $d; // elapsed time in days
    31. 35. Good $elapsedTimeInDays; $daysSinceCreation; $daysSinceModification;
    32. 36. 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; }
    33. 37. The SOLID Principles <ul><li>S ingle Responsibility (SRP)
    34. 38. O pen-Closed (OCP)
    35. 39. L iskov Substitution (LSP)
    36. 40. I nterface Segregation (ISP)
    37. 41. D ependency Inversion (DIP) </li></ul>
    38. 42. A web of collaborating objects <ul><li>The SRP and DIP together drive a “composition” approach to OO design
    39. 43. From Growing Object Oriented Software, Guided by Tests : </li></ul>&quot;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.&quot;
    40. 44. From LosTechies.com
    41. 45. 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.
    42. 46. class ShashinInstall { // ... public function run() { $this->createAlbumTable(); $this->verifyAlbumTable(); $this->createPhotoTable(); $this->verifyPhotoTable(); $this->updateSettings(); return true; } // ... } Shashin example
    43. 47. Shashin's capabilities are shaped by how these objects are wired together, through implementation of the DIP
    44. 48. From LosTechies.com
    45. 49. 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()
    46. 50. Dependency inversion applied This is the Abstract Server pattern Button + poll() <<interface>> SwitchableDevice + turnOn() + turnOff() Lamp
    47. 51. 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(); } } }
    48. 52. Independent Architecture
    49. 53. “Software architectures are structures that support the use cases of the system... Frameworks are tools to be used, not architectures to be conformed to” - Bob Martin http://blog.8thlight.com/uncle-bob/2011/09/30/Screaming-Architecture.html
    50. 54. In my plugins, WordPress custom functions are moved behind a “facade”
    51. 55. Facade pattern for my plugins Shashin Functions facade interface Some other facade implementation WordPress facade implementation Yet another facade implementation
    52. 56. interface ToppaFunctionsFacade { // ... public function enqueueStylesheet($handle, $relativePath, $dependencies = false, $version = null, $media = null); } class ToppaFunctionsFacadeWp implements ToppaFunctionsFacade { // … public function enqueueStylesheet($handle, $relativePath, $dependencies = false, $version = null, $media = null) { return wp_enqueue_style($handle, $relativePath, $dependencies, $version, $media); } } // use in Shashin // ... public function setFunctionsFacade(ToppaFunctionsFacade $functionsFacade) { $this->functionsFacade = $functionsFacade; return $this->functionsFacade; } // ... $this->functionsFacade->enqueueStylesheet('shashinAdminStyle', $cssUrl, false, $this->version); Shashin example
    53. 57. But I decided to not use a facade for WordPress' hooks and filters
    54. 58. I isolated the WordPress hooks and filters in a single method
    55. 59. public function run() { add_action('admin_menu', array($this, 'initToolsMenu')); add_action('admin_menu', array($this, 'initSettingsMenu')); add_action('template_redirect', array($this, 'displayPublicHeadTags')); add_shortcode('shashin', array($this, 'handleShortcode')); add_action('wp_ajax_nopriv_displayAlbumPhotos', array($this, 'ajaxDisplayAlbumPhotos')); add_action('wp_ajax_displayAlbumPhotos', array($this, 'ajaxDisplayAlbumPhotos')); add_action('media_buttons', array($this, 'addMediaButton'), 30); add_action('media_upload_shashin_photos', array($this, 'initPhotoMediaMenu')); add_action('media_upload_shashin_albums', array($this, 'initAlbumMediaMenu')); add_action('wp_ajax_shashinGetPhotosForMediaMenu', array($this, 'ajaxGetPhotosForMediaMenu')); add_action('shashinSync', array($this, 'runScheduledSync')); add_action('widgets_init', array($this, 'registerWidget')); add_action('admin_head', array($this, 'displayPluginPageUpgradeNag')); } // ... public function runScheduledSync() { $adminContainer = new Admin_ShashinContainer($this->autoLoader); $scheduledSynchronizer = $adminContainer->getScheduledSynchronizer(); $scheduledSynchronizer->run(); } ShashinWp
    56. 60. Unit testing and TDD
    57. 61. The test frameworks available for PHP are PHPUnit (the standard) and SimpleTest
    58. 62. SimpleTest for WordPress
    59. 63. Shashin example This is one of the tests for the method setTableCaptionTag(), in the class ShashinLayoutManager Mock::generate('Lib_ShashinSettings'); Mock::generate('Lib_ShashinAlbumPhotosCollection'); class UnitPublic_ShashinLayoutManager extends UnitTestCase { // … public function testSetTableCaptionTagWithFewerPhotosThanMaxPerPage() { $layoutManager = new Public_ShashinLayoutManager(); $collection = new MockLib_ShashinAlbumPhotosCollection(); $collection->setReturnValue('getCount', 9); $layoutManager->setDataObjectCollection($collection); $settings = new MockLib_ShashinSettings(); $settings->setReturnValue('getPhotoLimit',10); $this->layoutManager->setSettings($settings); $this->assertNull($this->layoutManager->setTableCaptionTag()); } }
    60. 64. But don't overdo it: avoid needless complexity
    61. 65. Contact www.toppa.com [email_address] @mtoppa
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×