Tombstones, Vampires & Discovering Dead Code

6834447bdbca70cd2390adc690c3b4f1?s=47 Chris Gmyr
October 19, 2017

Tombstones, Vampires & Discovering Dead Code

6834447bdbca70cd2390adc690c3b4f1?s=128

Chris Gmyr

October 19, 2017
Tweet

Transcript

  1. 3.
  2. 4.
  3. 5.

    What are we going to learn? → What is technical

    debt? → Efficiently find dead code → Remove code with confidence
  4. 6.

    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...
  5. 7.
  6. 8.

    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
  7. 10.

    Crowdpac Codebase → Laravel 4.2 → ~300 Classes → ~50,000

    Logical lines of code → 667.13 Average system complexity score → (excludes: migrations, tests, views)
  8. 11.
  9. 13.

    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
  10. 14.

    What is "dead code"? → not referenced → referenced, not

    executed → no longer provides business value
  11. 17.

    Variable Functions function foo() { echo "In foo()<br />\n"; }

    $func = 'foo'; $func(); We can't search for references of foo()
  12. 18.

    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?
  13. 19.

    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
  14. 20.

    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;
  15. 21.

    Framework "Magic" class User { public function setPasswordAttribute($value) { $this->attributes['password']

    = Hash::make($value); } public function getPasswordAttribute($value) { return 'HIDDEN'; } }
  16. 22.

    Framework "Magic" User::create([ 'password' => $_POST['password'] // setPasswordAttribute() ]); $user->password

    = $_POST['password']; // setPasswordAttribute() echo $user->password; // getPasswordAttribute()
  17. 23.

    Framework "Magic" class Post { public function scopePopular($query) { return

    $query->where('votes', '>', 100); } } $posts = Post::popular()->get(); // scopePopular()
  18. 27.

    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'); //... }
  19. 28.

    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; } }
  20. 29.

    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) { // } }
  21. 31.
  22. 35.
  23. 36.

    class User { public function canPublishPost() { if ($this->isAwesome()) {

    if($this->type == 'zombie') { tombstone('2017-10-31', 'cmgmyr'); //... } //... } //... } }
  24. 38.
  25. 40.
  26. 42.

    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() ...
  27. 43.

    class User { public function canPublishPost() { if ($this->isAwesome()) {

    if($this->type == 'zombie') { tombstone('2017-10-31', 'cmgmyr'); //... } //... } //... } }
  28. 44.

    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!!!
  29. 46.

    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(); } }
  30. 48.
  31. 49.

    Who should utilize tombstones? → legacy code → complex domain

    → inherited codebase → upgrading a codebase
  32. 50.

    So, why tombstones? → Low impact solution → Use with

    dynamic languages → High confidence in removing code