• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Clean code for WordPress
 

Clean code for WordPress

on

  • 2,995 views

Wor

Wor

Statistics

Views

Total Views
2,995
Views on SlideShare
2,079
Embed Views
916

Actions

Likes
3
Downloads
27
Comments
1

5 Embeds 916

http://www.toppa.com 862
http://lanyrd.com 42
http://feeds.feedburner.com 6
http://translate.googleusercontent.com 5
http://www.php-talks.com 1

Accessibility

Categories

Upload Details

Uploaded via as OpenOffice

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

11 of 1 previous next

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • 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'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't - it will eventually make you so slow, you'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'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'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'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'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'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' 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
  • 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
  • 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'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
  • 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)
  • 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

Clean code for WordPress Clean code for WordPress Presentation Transcript

  • 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()
  • Dependency inversion applied This is the Abstract Server pattern Button + poll() <<interface>> SwitchableDevice + turnOn() + turnOff() Lamp
  • 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(); } } }
  • Independent Architecture
  • “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
  • In my plugins, WordPress custom functions are moved behind a “facade”
  • Facade pattern for my plugins Shashin Functions facade interface Some other facade implementation WordPress facade implementation Yet another facade implementation
  • 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
  • But I decided to not use a facade for WordPress' hooks and filters
  • I isolated the WordPress hooks and filters in a single method
  • 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
  • Unit testing and TDD
  • The test frameworks available for PHP are PHPUnit (the standard) and SimpleTest
  • SimpleTest for WordPress
  • 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()); } }
  • But don't overdo it: avoid needless complexity
  • Contact www.toppa.com [email_address] @mtoppa