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

Practical Refactoring (PHPNW14)

Practical Refactoring (PHPNW14)

Every codebase builds up some legacy over time, there is hardly a way around that. But how you handle the legacy is what seperates a good developer from a great developer. Refactoring code should be a part of your every day work, but how to effectively refactor your code? How to ensure the quality of the new code as well as the fact that refactoring code won't break something elsewhere in your code? During this talk we'll go into the why, when and how of refactoring.

A8f72e32766355f12a56ede9aaa0ee78?s=128

Stefan Koopmanschap

October 04, 2014
Tweet

Transcript

  1. Practical Refactoring

  2. Refactoring • What is it? • Why would we do

    it? • When do we do it? • How do we do it?
  3. What?

  4. None
  5. Code refactoring is the process of changing a computer program's

    internal structure without modifying its external behavior or existing functionality.
  6. Why?

  7. Code is never perfect

  8. None
  9. None
  10. Code quality • Lessen complexity • Increase readability • Increase

    maintainability • Upgrade performance • Increase stability
  11. Functionality • New functionality • Updated functionality

  12. None
  13. DON’T... • Just beautify your code • Refactor because of

    refactoring
  14. Selling refactoring to your manager/customer

  15. What’s in it for them? • Less bugs • Faster

    development • It is part of the process
  16. Example if ($order) { if ( ! $order->retryPossible()) { throw

    new BadRequestHttpException('Order already exists for ShoppingCart'); } } public function isOpen() { return $this->getOrder() === null; } public function isOpen() { return ( $this->getOrder() === null || $this->getOrder()->retryPossible() === true ); }
  17. None
  18. A good read http://robots.thoughtbot.com/post/2685998010/ongoing-refactoring-and-client-work

  19. None
  20. When?

  21. Continuously

  22. Really

  23. Continuously • NOT: Always • NOT: Immediately

  24. Continuously • Your code gets better, one step at a

    time • You don’t spend ages on refactoring, it’s part of the project
  25. How?

  26. Isolation • Small, independant classes and methods • Class or

    method too big? refactor again!
  27. mysql_connect('127.0.0.1', 'root'); mysql_select_db('refactoring'); ! $newsSQL = "SELECT * FROM NEWS

    ORDER BY published_at DESC"; $result = mysql_query($newsSQL); ! while($row = mysql_fetch_assoc($result)) { echo $row['published_at'] . ': ' . $row['title'].'<br />'; echo nl2br($row['message']) . '<br /><br />'; }
  28. None
  29. $db_server = '127.0.0.1'; $db_user = 'root'; $db_pass = ''; $db_name

    = 'refactoring'; require_once('config.php'); ! $db = new PDO('mysql:dbname='.$db_name.';host='.$db_server, $db_user, $db_pass); $newsSQL = "SELECT * FROM NEWS ORDER BY published_at DESC"; $stmt = $db->prepare($newsSQL); $stmt->execute(); ! while($row = $stmt->fetch(PDO::FETCH_ASSOC)) { echo $row['published_at'] . ': ' . $row['title'].'<br />'; echo nl2br($row['message']) . '<br /><br />'; }
  30. None
  31. class NewsRepository { private $db; public function __construct($db) { $this->db

    = $db; } public function getAllNews() { $newsSQL = "SELECT * FROM NEWS ORDER BY published_at DESC"; $stmt = $this->db->prepare($newsSQL); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_ASSOC); } }
  32. require_once('config.php'); require_once('NewsRepository.php'); ! $db = new PDO('mysql:dbname='.$db_name.';host='.$db_server, $db_user, $db_pass); !

    $newsRepo = new NewsRepository($db); $news = $newsRepo->getAllNews(); ! foreach($news as $row) { echo $row['published_at'] . ': ' . $row['title'].'<br />'; echo nl2br($row['message']) . '<br /><br />'; }
  33. None
  34. None
  35. None
  36. Tests • Tests are contracts and verifications • Contract: Code

    should do what is tested • Verification: Does it do what is tested? • Don’t change the tests • Just expand the test
  37. <?php class NewsRepositoryTest extends PHPUnit_Framework_TestCase { $private $MockDb; public function

    setUp() { // here we set up the mock class $this->MockDb = new MockDb(); } ! public function testGetAllNews() { $newsRepo = new NewsRepository($this->MockDb); // mock repo returns 2 newsitems $news = $newsRepo->getAllNews(); $this->assertEquals(2, count($news)); } }
  38. public function getAllNews($limit = null) { $newsSQL = "SELECT *

    FROM NEWS ORDER BY published_at DESC"; if ( ! is_null($limit)) { $newsSQL .= " LIMIT 0, " . $limit; } $stmt = $this->db->prepare($newsSQL); $stmt->execute(); return $stmt->fetchAll(PDO::FETCH_ASSOC); }
  39. public function testGetAllNews() { $newsRepo = new NewsRepository($this->MockDb); // mock

    repo returns 2 newsitems $news = $newsRepo->getAllNews(); $this->assertEquals(2, count($news)); // new functionality: limit the newsitems $news = $newsRepo->getAllNews(1); $this->assertEquals(1, count($news)); }
  40. When you change your test...

  41. You change the behaviour of your code

  42. Tests • Untested code? • Write tests before refactoring if

    possible • Write tests during refactoring • Tested code? • Expand those tests
  43. Your IDE can help • Most IDE’s have refactoring support

    • Scan for usage of methods and classes • http://qafoo.com/blog/ 041_refactoring_browser.html
  44. What about my legacy?

  45. So, refactoring • What is it? • Why would we

    do it? • When do we do it? • How do we do it?
  46. Thank you! • https://joind.in/11795 • http://php.ingewikkeld.net