Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Tombstones, Vampires & Discovering Dead Code

Chris Gmyr
October 19, 2017

Tombstones, Vampires & Discovering Dead Code

Chris Gmyr

October 19, 2017
Tweet

More Decks by Chris Gmyr

Other Decks in Technology

Transcript

  1. What are we going to learn? → What is technical

    debt? → Efficiently find dead code → Remove code with confidence
  2. What is technical debt? The implied cost of additional rework

    caused by choosing an easy solution now instead of using a better approach. If technical debt is not repaid, it accumulates 'interest', making it harder to implement changes later on...
  3. What is technical debt? ...Technical debt is not necessarily a

    bad thing, and sometimes is required to move projects forward. → https://en.wikipedia.org/wiki/Technical_debt
  4. Crowdpac Codebase → Laravel 4.2 → ~300 Classes → ~50,000

    Logical lines of code → 667.13 Average system complexity score → (excludes: migrations, tests, views)
  5. Pay back technical debt by → remove commented out blocks

    of code → improve your test suite (or start one) → refactor code you're currently working on → removing dead code
  6. What is "dead code"? → not referenced → referenced, not

    executed → no longer provides business value
  7. Variable Functions function foo() { echo "In foo()<br />\n"; }

    $func = 'foo'; $func(); We can't search for references of foo()
  8. Variable Functions function displayName($name) { echo $name; } $func =

    'display' . ucwords($_GET['property']); $func($_GET['property_value']); How are we easily going to search for displayName() usages?
  9. Magic Methods __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(),

    __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() and __debugInfo() http://php.net/manual/en/language.oop5.magic.php
  10. Magic Methods class User { public function __toString() { return

    $this->fullName(); } } echo new User('Chris Gmyr'); echo new User(['full_name' => 'Chris Gmyr']); $person = new User([...]); // User::make([...]); echo $person;
  11. Framework "Magic" class User { public function setPasswordAttribute($value) { $this->attributes['password']

    = Hash::make($value); } public function getPasswordAttribute($value) { return 'HIDDEN'; } }
  12. Framework "Magic" User::create([ 'password' => $_POST['password'] // setPasswordAttribute() ]); $user->password

    = $_POST['password']; // setPasswordAttribute() echo $user->password; // getPasswordAttribute()
  13. Framework "Magic" class Post { public function scopePopular($query) { return

    $query->where('votes', '>', 100); } } $posts = Post::popular()->get(); // scopePopular()
  14. What is a tombstone? A marker (function) placed inside code

    that is assumed dead. When a tombstone is executed, tracking information is written to a log. public function reallyOldMethod() { tombstone('2017-10-31', 'cmgmyr'); //... }
  15. What is a vampire? Suspected dead code, marked with a

    tombstone, that is alive echo $user->fullName(); class User { public function fullName() // vampire! { tombstone('2017-10-31', 'cmgmyr'); // remove this return $this->first_name . ' ' . $this->last_name; } }
  16. PHP Implementation https://github.com/scheb/tombstone function tombstone($date, $author, $label = null) {

    try { $trace = TraceProvider::getTraceHere(); $streamHandler = new StreamHandler(dirname(__DIR__)."/logs/tombstones.log"); GraveyardProvider::getGraveyard()->addHandler($streamHandler); GraveyardProvider::getGraveyard()->tombstone($date, $author, $label, $trace); } catch (\Exception $e) { // } }
  17. class User { public function canPublishPost() { if ($this->isAwesome()) {

    if($this->type == 'zombie') { tombstone('2017-10-31', 'cmgmyr'); //... } //... } //... } }
  18. Check the logs 2017-11-01 09:00:00 Vampire detected from tombstone('2017-10-31', 'cmgmyr')

    in User.php on line XXX in canPublishPost() ... 2017-11-02 09:00:00 Vampire detected from tombstone('2017-10-31', 'cmgmyr') in User.php on line XXX in canPublishPost() ... 2017-11-03 09:00:00 Vampire detected from tombstone('2017-10-31', 'cmgmyr') in User.php on line XXX in canPublishPost() ...
  19. class User { public function canPublishPost() { if ($this->isAwesome()) {

    if($this->type == 'zombie') { tombstone('2017-10-31', 'cmgmyr'); //... } //... } //... } }
  20. Check the logs 2017-11-01 09:00:00 Vampire detected from tombstone('2017-10-31', 'cmgmyr')

    in User.php on line XXX in canPublishPost() ... 2017-11-02 09:00:00 Vampire detected from tombstone('2017-10-31', 'cmgmyr') in User.php on line XXX in canPublishPost() ... 2017-11-03 09:00:00 Vampire detected from tombstone('2017-10-31', 'cmgmyr') in User.php on line XXX in canPublishPost() ... 2017-11-04 ... 2017-11-05 ... 2017-11-06 ... No more canPublishPost() vampires!!!
  21. class TombstoneWorkflow { public function __construct() { $this->makePlan(); $this->cleanCode(); }

    public function cleanCode() { $this->setTombstones(); while($this->codebaseHasVampires()) { $this->checkLogs(); $this->removeVampires(); } $this->reviewRemainingTombstones(); $this->removeDeadCode(); } }
  22. Who should utilize tombstones? → legacy code → complex domain

    → inherited codebase → upgrading a codebase
  23. So, why tombstones? → Low impact solution → Use with

    dynamic languages → High confidence in removing code