Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Maintaining legacy applications

460 views

Published on

Tips and tricks learned over the years on maintaining legacy applications.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Maintaining legacy applications

  1. 1. MAINTAINING LEGACY APPLICATIONS by Bernhard Breytenbach
  2. 2. ABOUT ME Started with PHP in 2005 Developer at MDS Technologies @BBreyten on Twitter lanyrd.com/cfmmrb | joind.in/14838
  3. 3. WHAT IS LEGACY SOFTWARE? “The secondary value of software is its behavior... It’s achieved when the current software meets the current needs of the current user... But the needs of the users change, and they do so frequently... Thus the primary value of software is its ability to change.” — Robert C. Martin (Uncle Bob)
  4. 4. WHAT IS LEGACY SOFTWARE? Legacy software is software that is unable to change easily Software that is difficult to read and reuse
  5. 5. “DON’T MAINTAIN, REWRITE!”
  6. 6. NETSCAPE NAVIGATOR
  7. 7. THE DANGERS OF REWRITE
  8. 8. REFACTORING Refactoring is the process of restructuring existing code without changing its external behavior, in order to improve readability and reduce code complexity, as to improve source code maintainability and create a more expressive internal architecture or object model to improve extensibility. https://en.wikipedia.org/wiki/Code_refactoring
  9. 9. RULES OF REFACTORING Small iterative changes Make sure everything still works Send to QA, Push to Production Do the next small change
  10. 10. TYPES OF LEGACY SYSTEMS Standalone App Framework (MVC) Plugins/Modules
  11. 11. VERSION CONTROL
  12. 12. DEPLOYMENT
  13. 13. PICK A CODING STANDARD PSR1 & PSR2 Only one standard
  14. 14. SETUP AUTOLOADING spl_autoload_register(function ($class) {     $prefix = 'FooBar';     $base_dir = __DIR__ . '/src/';     $len = strlen($prefix);     if (strncmp($prefix, $class, $len) !== 0) {         return;     }     $relative_class = substr($class, $len);     $file = $base_dir . str_replace('', '/', $relative_class) . '.php';     // if the file exists, require it     if (file_exists($file)) {         require $file;     } });
  15. 15. COMPOSER AUTOLOADING {     "autoload": {         "psr­0": {             "FooBar":"src/",         },         "psr­4": {             "FooBar":"src/",         }     } } bootstrap.php require "vendor/autoload.php"
  16. 16. DIRECTORY STRUCTURE public/ src/ vendor/ bootstrap.php
  17. 17. MOVE FUNCTIONALITY INTO CLASSES Get rid of includes One class per file Files should declare new symbols, or cause side effects, but not do both.
  18. 18. REPLACE MAGIC NUMBERS WITH CONSTANTS if ($status­>id === 15) if ($user­>type === 3) if ($code === 418) if ($status­>id === Status::CANCELLED) if ($user­>type === User::TYPE_ADMIN) if ($code === Response::HTTP_I_AM_A_TEAPOT)
  19. 19. DEPENDENCY INJECTION <?php class UserRepository {     public function getUsers()     {         global $db;         $sql = 'select * from users;';         return $db­>select($sql);     } }
  20. 20. DEPENDENCY INJECTION <?php class UserRepository {     public function getUsers()     {         $db = Db::getInstance();         $sql = 'select * from users;';         return $db­>select($sql);     } }
  21. 21. DEPENDENCY INJECTION <?php class UserRepository {     protected $db;     public function __construct()     {         global $db;         $this­>db = $db;     }     public function getUsers()     {         $sql = 'select * from users;';         return $this­>db­>select($sql);     } }
  22. 22. DEPENDENCY INJECTION <?php class UserRepository {     protected $db;     public function __construct($db)     {         $this­>db = $db;     }     public function getUsers()     {         $sql = 'select * from users;';         return $this­>db­>select($sql);     } }
  23. 23. BREAK UP LARGE CLASSES/FUNCTIONS Large functions is where classes go to hide.
  24. 24. PROTECTION LAYER <?php class User {     protected $attributes = [];     public function __construct($attributes)     {         $this­>attributes = $attributes;     }     public function getId()     {         return $this­>attributes['UserName'];     }     public function getUserName()     {         return $this­>attributes['UserName'];     } }
  25. 25. PLAN OF ACTION Take Charge! Baby steps Fail fast, fail cheap
  26. 26. PLUGINS/MODULES Globals only allowed in the master file If global is a class, initialize in construct All globals should be passed on as is
  27. 27. PLUGINS/MODULES <?php include('autoload.php'); class some_required_class_name extends some_base_class {     private $db;     public function __construct()     {         global $db;         $this­>db = $db;     }     public function get_info($data)     {         global $token;         $infoGetter = new InfoGetter($this­>db);         return $infoGetter­>get($data­>id, $token);     } }
  28. 28. PRESTASHOP <?php // Avoid direct access to the file if (!defined('_PS_VERSION_')) {     exit; } require_once('bootstrap.php'); class MdsCollivery extends CarrierModule {     protected $collivery;     protected $db;     protected $hooks = array(         'displayFooter',         'displayShoppingCart',         'displayAdminOrder',     );     public function __construct()     {         $this­>name = 'mds';         $this­>tab = 'shipping_logistics';         $this­>version = '1.0';
  29. 29. PRESTASHOP <?php define('_MDS_DIR_', __DIR__); class MdsColliveryAutoloader {   protected static $classMap = array(     'Mds_View'         => 'MdsPrestashopHelpersView',     'Mds_ColliveryApi' => 'MdsPrestashopColliveryColliveryApi'     'Mds_Install'      => 'MdsPrestashopInstallerInstall',   );   public static function autoload($class)   {     if (array_key_exists($class, self::$classMap)) {       class_alias(self::$classMap[$class], $class);     } else {       $classParts = explode('', $class);       $vendor = array_shift($classParts);       if ($vendor === 'Mds') {         require _MDS_DIR_ . '/' . implode('/', $classParts       }     }   } }
  30. 30. IS IT NEVER GOOD TO REWRITE?
  31. 31. WHEN CAN I REWRITE? The new system is vastly out of scope, or the current system simply can’t meet the new requirements. You have to change Programming Language/Framework You have lots of time, money and resources
  32. 32. RULES OF A REWRITE Both systems need to run in parallel Spend as little time as possible between deploys Fail fast, fail cheap Don’t try and change everything Use @deprecated Work closely with the current devs Always be ready to implement new features
  33. 33. The key to success is not perfection, but making peace with the term good enough, and then moving on.

×