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.

Stefan Koopmanschap

October 04, 2014
Tweet

More Decks by Stefan Koopmanschap

Other Decks in Programming

Transcript

  1. Practical Refactoring

    View Slide

  2. Refactoring
    • What is it?

    • Why would we do it?

    • When do we do it?

    • How do we do it?

    View Slide

  3. What?

    View Slide

  4. View Slide

  5. Code refactoring is the process of changing a computer
    program's internal structure without modifying its
    external behavior or existing functionality.

    View Slide

  6. Why?

    View Slide

  7. Code is never perfect

    View Slide

  8. View Slide

  9. View Slide

  10. Code quality
    • Lessen complexity

    • Increase readability

    • Increase maintainability

    • Upgrade performance

    • Increase stability

    View Slide

  11. Functionality
    • New functionality

    • Updated functionality

    View Slide

  12. View Slide

  13. DON’T...
    • Just beautify your code

    • Refactor because of refactoring

    View Slide

  14. Selling refactoring to
    your manager/customer

    View Slide

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

    • Faster development

    • It is part of the process

    View Slide

  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
    );
    }

    View Slide

  17. View Slide

  18. A good read
    http://robots.thoughtbot.com/post/2685998010/ongoing-refactoring-and-client-work

    View Slide

  19. View Slide

  20. When?

    View Slide

  21. Continuously

    View Slide

  22. Really

    View Slide

  23. Continuously
    • NOT: Always

    • NOT: Immediately

    View Slide

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

    • You don’t spend ages on refactoring, it’s
    part of the project

    View Slide

  25. How?

    View Slide

  26. Isolation
    • Small, independant classes and methods

    • Class or method too big? refactor again!

    View Slide

  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'].'
    ';
    echo nl2br($row['message']) . '

    ';
    }

    View Slide

  28. View Slide

  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'].'
    ';
    echo nl2br($row['message']) . '

    ';
    }

    View Slide

  30. View Slide

  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);
    }
    }

    View Slide

  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'].'
    ';
    echo nl2br($row['message']) . '

    ';
    }

    View Slide

  33. View Slide

  34. View Slide

  35. View Slide

  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

    View Slide

  37. 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));
    }
    }

    View Slide

  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);
    }

    View Slide

  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));
    }

    View Slide

  40. When you change your
    test...

    View Slide

  41. You change the
    behaviour of your code

    View Slide

  42. Tests
    • Untested code?

    • Write tests before refactoring if possible

    • Write tests during refactoring

    • Tested code?

    • Expand those tests

    View Slide

  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

    View Slide

  44. What about my legacy?

    View Slide

  45. So, refactoring
    • What is it?

    • Why would we do it?

    • When do we do it?

    • How do we do it?

    View Slide

  46. Thank you!
    • https://joind.in/11795

    • http://php.ingewikkeld.net

    View Slide