Save 37% off PRO during our Black Friday Sale! »

Clean Code: Refactoring

0f930e13633535c1c4041e95b8881308?s=47 Jeff Carouth
February 08, 2014

Clean Code: Refactoring

There are very few "write once" applications in reality. As developers we must keep up with constant changes and evolution of problems and our code should reflect this. In this talk we will look at practical examples of code that is not "bad" code but needs a little attention. We will look at techniques for refactoring it to a more readable, understandable, and maintainable state.

0f930e13633535c1c4041e95b8881308?s=128

Jeff Carouth

February 08, 2014
Tweet

Transcript

  1. clean code: refactoring PRESENTED BY JEFF CAROUTH @jcarouth Saturday, February

    8, 14
  2. is hard Programming Saturday, February 8, 14

  3. Why is programming difficult? Saturday, February 8, 14

  4. Are you a compiler? Saturday, February 8, 14

  5. Any fool can write code a computer can understand.” “

    Saturday, February 8, 14
  6. Good programmers write code humans can understand.” “ – Martin

    Fowler Saturday, February 8, 14
  7. Read These Books Saturday, February 8, 14

  8. clean code Saturday, February 8, 14

  9. Clean code is readable; it tells a story. Saturday, February

    8, 14
  10. Clean code is cared for; it is maintained. Saturday, February

    8, 14
  11. Clean code is efficient; it is done right. Saturday, February

    8, 14
  12. Clean code is extensible; it is able to solve tomorrow’s

    problems. Saturday, February 8, 14
  13. Clean code is simple; it is easy to understand how

    it works and what it does. Saturday, February 8, 14
  14. the two rules of clean code Saturday, February 8, 14

  15. Rule #1 Write dirty code, then clean it. Saturday, February

    8, 14
  16. Rule #1 Write dirty code, then clean it. You cannot

    write clean code at first. > Saturday, February 8, 14
  17. Rule #1 Write dirty code, then clean it. You cannot

    write clean code at first. Your first pass at solving a problem will not be your best. > > Saturday, February 8, 14
  18. Rule #1 Write dirty code, then clean it. You cannot

    write clean code at first. Your first pass at solving a problem will not be your best. > > Successive refinement through refactoring is the key to clean code. > Saturday, February 8, 14
  19. Rule #2 Leave the code cleaner than you found it.

    Saturday, February 8, 14
  20. Rule #2 Leave the code cleaner than you found it.

    Shamelessly borrowed from the Boy Scouts of America. > Saturday, February 8, 14
  21. Rule #2 Leave the code cleaner than you found it.

    Shamelessly borrowed from the Boy Scouts of America. Incremental changes are the way to go. > > Saturday, February 8, 14
  22. Rule #2 Leave the code cleaner than you found it.

    Shamelessly borrowed from the Boy Scouts of America. Incremental changes are the way to go. > > Even if the only change you make is cosmetic, you are maintaining clean code. > Saturday, February 8, 14
  23. an example Saturday, February 8, 14

  24. class AccountService { public function find($id) { if (is_string($id) &&

    strlen($id) == 36) { $statement = $this->db->prepare( "SELECT * FROM accounts WHERE id = :account_id" ); $statement->execute(['account_id' => $id]); if ($statement->rowCount() == 1) { $data = $statement->fetch(); $account = new Account(); $account->setId($data['id']); $account->setName($data['name']); return $account; } else { return null; } } else { throw new \InvalidArgumentException('ID is not valid'); } } } Saturday, February 8, 14
  25. class AccountService { public function find($id) { if (is_string($id) &&

    strlen($id) == 36) { $statement = $this->db->prepare( "SELECT * FROM accounts WHERE id = :account_id" ); $statement->execute(['account_id' => $id]); if ($statement->rowCount() == 1) { $data = $statement->fetch(); $account = new Account(); $account->setId($data['id']); $account->setName($data['name']); return $account; } else { return null; } } else { throw new \InvalidArgumentException('ID is not valid'); } } } Saturday, February 8, 14
  26. When you have a significant number of nested conditionals, you

    can refactor them to be more understandable using guard clauses. Refactoring Saturday, February 8, 14
  27. class AccountService { public function find($id) { if (is_string($id) &&

    strlen($id) == 36) { $statement = $this->db->prepare( "SELECT * FROM accounts WHERE id = :account_id" ); $statement->execute(['account_id' => $id]); if ($statement->rowCount() == 1) { $data = $statement->fetch(); $account = new Account(); $account->setId($data['id']); $account->setName($data['name']); return $account; } else { return null; } } else { throw new \InvalidArgumentException('ID is not valid'); } } } Saturday, February 8, 14
  28. class AccountService { public function find($id) { if (!is_string($id) ||

    strlen($id) != 36) { throw new \InvalidArgumentException('Account ID is not valid'); } $statement = $this->db->prepare( "SELECT * FROM accounts WHERE id = :account_id" ); $statement->execute(['account_id' => $id]); if ($statement->rowCount() == 1) { $data = $statement->fetch(); $account = new Account(); $account->setId($data['id']); $account->setName($data['name']); return $account; } else { return null; } } } Saturday, February 8, 14
  29. Complicated or boolean expressions using magic numbers or otherwise non-obvious

    logic should be refactored to a descriptively named helper method. Refactoring Saturday, February 8, 14
  30. class AccountService { public function find($id) { if (!$this->isValidId($id)) {

    throw new \InvalidArgumentException('Account ID is not valid'); } //snip – my favorite slide-only refactoring } private function isValidId($id) { return is_string($id) && strlen($id) == 36; } } Saturday, February 8, 14
  31. public function find($id) { if (!$this->isValidId($id)) { throw new \InvalidArgumentException('Account

    ID is not valid'); } $statement = $this->db->prepare( "SELECT * FROM accounts WHERE id = :account_id" ); $statement->execute(['account_id' => $id]); if ($statement->rowCount() == 1) { $data = $statement->fetch(); $account = new Account(); $account->setId($data['id']); $account->setName($data['name']); return $account; } else { return null; } } Saturday, February 8, 14
  32. Extract what could be common functionality, or even functionality that

    belongs on a different object into methods. Refactoring Saturday, February 8, 14
  33. private function fetchAccountDataById($id) { $statement = $this->db->prepare( "SELECT * FROM

    accounts WHERE id = :account_id" ); $statement->execute(['account_id' => $id]); if ($statement->rowCount() == 1) { $data = $statement->fetch(); } else { $data = array(); } return $data; } Saturday, February 8, 14
  34. class AccountService { public function find($id) { if (!$this->isValidId($id)) {

    throw new \InvalidArgumentException('Account ID is not valid'); } $data = $this->fetchAccountDataById($id); if (empty($data)) { return null; } $account = new Account(); $account->setId($data['id']); $account->setName($data['name']); return $account; } private function fetchAccountDataById($id) { //snip – slides are not very tall } } Saturday, February 8, 14
  35. class AccountService { public function find($id) { if (!$this->isValidId($id)) {

    throw new \InvalidArgumentException('Account ID is not valid'); } $data = $this->fetchAccountDataById($id); if (empty($data)) { return null; } $account = new Account(); $account->setId($data['id']); $account->setName($data['name']); return $account; } } Saturday, February 8, 14
  36. class AccountService { public function find($id) { if (!$this->isValidId($id)) {

    throw new \InvalidArgumentException('Account ID is not valid'); } $data = $this->fetchAccountDataById($id); return $this->buildAccountFromData($data); } private function buildAccountFromData($data) { if (empty($data)) { return null; } $account = new Account(); $account->setId($data['id']); $account->setName($data['name']); return $account; } // snip } Saturday, February 8, 14
  37. Replace instances of returning null in place of an object

    with returning instances of a NullObject where possible and appropriate. Refactoring Saturday, February 8, 14
  38. $accountService = new AccountService(new MyPdoWrapper(...)); $account = $accountService->fetch('...'); if (null

    === $account) { //bail. we don't have a valid account } if (!$account->isActive()) { //error the account is not active } Saturday, February 8, 14
  39. class NullAccount extends Account { public function isActive() { return

    false; } } Saturday, February 8, 14
  40. class AccountService { public function find($id) { if (!$this->isValidId($id)) {

    throw new \InvalidArgumentException('Account ID is not valid'); } $data = $this->fetchAccountDataById($id); return $this->buildAccountFromData($data); } private function buildAccountFromData($data) { if (empty($data)) { return new NullAccount(); } $account = new Account(); $account->setId($data['id']); $account->setName($data['name']); return $account; } // snip } Saturday, February 8, 14
  41. Extract methods or logic into classes when the code isn’t

    necessarily relevant to the object you are working in. Refactoring Saturday, February 8, 14
  42. class AccountService { // snip private function fetchAccountDataById($id) { $statement

    = $this->db->prepare( "SELECT * FROM accounts WHERE id = :account_id" ); $statement->execute(['account_id' => $id]); if ($statement->rowCount() == 1) { $data = $statement->fetch(); } else { $data = array(); } return $data; } // snip } Saturday, February 8, 14
  43. class AccountDataProvider { public function __construct(PDO $pdo) { $this->dbh =

    $pdo; } public function fetchById($id) { $statement = $this->db->prepare( "SELECT * FROM accounts WHERE id = :account_id" ); $statement->execute(['account_id' => $id]); if ($statement->rowCount() == 1) { $data = $statement->fetch(); } else { $data = array(); } return $data; } } Saturday, February 8, 14
  44. class AccountService { // snip public function find($id) { if

    (!$this->isValidId($id)) { throw new \InvalidArgumentException('Account ID is not valid'); } $data = $this->provider->fetchById($id); return $this->buildAccountFromData($data); } // snip } Saturday, February 8, 14
  45. $accountService = new AccountService(new AccountDataProvider($pdo)); $account = $accountService->fetch('...'); if (!$account->isActive())

    { //error the account is not active } Saturday, February 8, 14
  46. Which is more readable? Saturday, February 8, 14

  47. class AccountService { public function find($id) { if (isset($id) &&

    strlen($id) == 36) { $statement = $this->db->prepare( "SELECT * FROM accounts WHERE id = :account_id" ); $statement->execute(['account_id' => $id]); if ($statement->rowCount() == 1) { $data = $statement->fetch(); $account = new Account(); $account->setId($data['id']); $account->setName($data['name']); return $account; } else { return null; } } else { throw new \InvalidArgumentException('ID is not valid'); } } } Saturday, February 8, 14
  48. class AccountService { public function find($id) { if (!$this->isValidId($id)) {

    throw new \InvalidArgumentException('Account ID is not valid'); } $data = $this->provider->fetchById($id); return $this->buildAccountFromData($data); } // snip } Saturday, February 8, 14
  49. Two examples are better than one Saturday, February 8, 14

  50. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true) { $url = ""; if (!$store->isDefault()) { $trySSL = false; $forceToCore = false; if ($this->featureToggle) { if ($includeDomain) { $url .= $this->config->secureProtocol.$this->config->storeDomainName; } $url .= "/checkout?product_id=".$this->productId; if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } } else { if ($includeDomain) { $url .= $store->GetFullUrl($trySSL, $isMobile); } $url .= "/resort_detail.php?ProductId=".$this->productId; if ($this->isDated()) { $url .= "&StartDate=".date("Y-m-d", strtotime($this->date)); } } } else { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } if ($this->featureToggle) { if ($includeDomain) { $url .= $this->config->secureProtocol.$domainName; } $url .= "/checkout?product_id=".$this->productId; if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } } else { if ($includeDomain) { $url .= "http://".$domainName; } $url .= "/resort_detail.php?ProductId=".$this->productId; if ($this->isDated()) { $url .= "&StartDate=".date("Y-m-d", strtotime($this->date)); } } } } } Saturday, February 8, 14
  51. { $url = ""; if (!$store->isDefault()) { $trySSL = false;

    $forceToCore = false; if ($this->featureToggle) { if ($includeDomain) { $url .= $this->config->secureProtocol.$this->config->sto } $url .= "/checkout?product_id=".$this->productId; if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } } else { if ($includeDomain) { $url .= $store->GetFullUrl($trySSL, $isMobile); } $url .= "/product_detail.php?ProductId=".$this->productId; if ($this->isDated()) { $url .= "&StartDate=".date("Y-m-d", strtotime($this->dat } } } else { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } if ($this->featureToggle) { Saturday, February 8, 14
  52. $url .= "&StartDate=".date("Y-m-d", strtotime($this->date) } } } else { $domainName

    = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } if ($this->featureToggle) { if ($includeDomain) { $url .= $this->config->secureProtocol.$domainName; } $url .= "/checkout?product_id=".$this->productId; if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } } else { if ($includeDomain) { $url .= "http://".$domainName; } $url .= "/product_detail.php?ProductId=".$this->productId; if ($this->isDated()) { $url .= "&StartDate=".date("Y-m-d", strtotime($this->date) } } } } } Saturday, February 8, 14
  53. { $url = ""; if (!$store->isDefault()) { $trySSL = false;

    $forceToCore = false; if ($this->featureToggle) { if ($includeDomain) { $url .= $this->config->secureProtocol.$this->config->sto } $url .= "/checkout?product_id=".$this->productId; if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } } else { if ($includeDomain) { $url .= $store->GetFullUrl($trySSL, $isMobile); } $url .= "/product_detail.php?ProductId=".$this->productId; if ($this->isDated()) { $url .= "&StartDate=".date("Y-m-d", strtotime($this->dat } } } else { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } if ($this->featureToggle) { Saturday, February 8, 14
  54. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true { $url = ""; if ($includeDomain) { if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } if ($this->featureToggle) { $url .= $this->config->secureProtocol.$domainName; } else { $url .= "http://".$domainName; } } else { if ($this->featureToggle) { $url .= $this->config->secureProtocol.$this->config->store } else { $url .= $store->GetFullUrl($trySSL, $isMobile); } } } if (!$store->isDefault()) { $trySSL = false; $forceToCore = false; Saturday, February 8, 14
  55. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true { $url = ""; if ($includeDomain) { if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } if ($this->featureToggle) { $url .= $this->config->secureProtocol.$domainName; } else { $url .= "http://".$domainName; } } else { if ($this->featureToggle) { $url .= $this->config->secureProtocol.$this->config->store } else { $url .= $store->GetFullUrl($trySSL, $isMobile); } } } if (!$store->isDefault()) { $trySSL = false; $forceToCore = false; Saturday, February 8, 14
  56. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true { $url = ""; $protocol = $this->config->secureProtocol; if ($includeDomain) { if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } if ($this->featureToggle) { $url .= $protocol.$domainName; } else { $url .= "http://".$domainName; } } else { if ($this->featureToggle) { $url .= $protocol.$this->config->storeDomainName; } else { $url .= $store->GetFullUrl($trySSL, $isMobile); } } } if (!$store->isDefault()) { Saturday, February 8, 14
  57. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true { $url = ""; $protocol = $this->config->secureProtocol; if ($includeDomain) { if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } if (!$this->featureToggle) { $protocol = "http://"; } $url .= $protocol.$domainName; } else { if ($this->featureToggle) { $url .= $protocol.$this->config->storeDomainName; } else { $url .= $store->GetFullUrl($trySSL, $isMobile); } } } Saturday, February 8, 14
  58. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true { $url = ""; $protocol = $this->config->secureProtocol; if ($includeDomain) { if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } if (!$this->featureToggle) { $protocol = "http://"; } $url .= $protocol.$domainName; } else { if ($this->featureToggle) { $url .= $protocol.$this->config->storeDomainName; } else { $url .= $store->GetFullUrl($trySSL, $isMobile); } } } Saturday, February 8, 14
  59. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true { $url = ""; $protocol = $this->config->secureProtocol; if ($includeDomain) { $domainName = $this->config->storeDomainName; if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } } if ($store->isDefault()) { if (!$this->featureToggle) { $protocol = "http://"; } $url .= $protocol.$domainName; } else { if ($this->featureToggle) { $url .= $protocol.$domainName; } else { $url .= $store->GetFullUrl($trySSL, $isMobile); } } Saturday, February 8, 14
  60. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true { $url = ""; $protocol = $this->config->secureProtocol; if ($includeDomain) { $domainName = $this->config->storeDomainName; if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } } if ($store->isDefault() && !$this->featureToggle) { $protocol = "http://"; } $url .= $protocol.$domainName; if (!$store->isDefault()) { if ($this->featureToggle) { $url .= $protocol.$domainName; } else { $url .= $store->GetFullUrl($trySSL, $isMobile); } } Saturday, February 8, 14
  61. $url = ""; $protocol = $this->config->secureProtocol; if ($includeDomain) { $domainName

    = $this->config->storeDomainName; if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } } if ($store->isDefault() && !$this->featureToggle) { $protocol = "http://"; } $url .= $protocol.$domainName; if (!$store->isDefault()) { if ($this->featureToggle) { $url .= $protocol.$domainName; } else { $url .= $store->GetFullUrl($trySSL, $isMobile); } } } if (!$store->isDefault()) { $trySSL = false; $forceToCore = false; Saturday, February 8, 14
  62. $url = ""; $protocol = $this->config->secureProtocol; if ($includeDomain) { $domainName

    = $this->config->storeDomainName; if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } } if ($store->isDefault() && !$this->featureToggle) { $protocol = "http://"; } $url .= $protocol.$domainName; if (!$store->isDefault()) { if (!$this->featureToggle) { $url .= $store->GetFullUrl($trySSL, $isMobile); } } } if (!$store->isDefault()) { $trySSL = false; $forceToCore = false; if ($this->featureToggle) { Saturday, February 8, 14
  63. $url = ""; $protocol = $this->config->secureProtocol; if ($includeDomain) { $domainName

    = $this->config->storeDomainName; if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } } if ($store->isDefault() && !$this->featureToggle) { $protocol = "http://"; } $url .= $protocol.$domainName; if (!$store->isDefault() && !$this->featureToggle) { $trySSL = false; $url .= $store->GetFullUrl($trySSL, $isMobile); } } if (!$store->isDefault()) { if ($this->featureToggle) { $url .= "/checkout?product_id=".$this->productId; if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } Saturday, February 8, 14
  64. } if (!$store->isDefault()) { if ($this->featureToggle) { $url .= "/checkout?product_id=".$this->productId;

    if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } } else { $url .= "/product_detail.php?ProductId=".$this->productId; if ($this->isDated()) { $url .= "&StartDate=".date("Y-m-d", strtotime($this->date) } } } else { if ($this->featureToggle) { $url .= "/checkout?product_id=".$this->productId; if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } } else { $url .= "/product_detail.php?ProductId=".$this->productId; if ($this->isDated()) { $url .= "&StartDate=".date("Y-m-d", strtotime($this->date) } } } } } Saturday, February 8, 14
  65. } if ($this->featureToggle) { if (!$store->isDefault()) { $url .= "/checkout?product_id=".$this->productId;

    if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } } else { $url .= "/checkout?product_id=".$this->productId; if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } } } else { if (!$store->isDefault()) { $url .= "/resort_detail.php?ProductId=".$this->productId; if ($this->isDated()) { $url .= "&StartDate=".date("Y-m-d", strtotime($this->date) } } else { $url .= "/resort_detail.php?ProductId=".$this->productId; if ($this->isDated()) { $url .= "&StartDate=".date("Y-m-d", strtotime($this->date) } } } } } Saturday, February 8, 14
  66. } if ($this->featureToggle) { $url .= "/checkout?product_id=".$this->productId; } else {

    $url .= "/resort_detail.php?ProductId=".$this->productId; } if ($this->isDated) { $dateParam = $this->featureToggle ? "start_date" : "StartDate"; $url = "&{$dateParam}=" . date("Y-m-d", strtotime($this->date)); } } } Saturday, February 8, 14
  67. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true { $url = ""; $protocol = $this->config->secureProtocol; if ($includeDomain) { $domainName = $this->config->storeDomainName; if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } } if ($store->isDefault() && !$this->featureToggle) { $protocol = "http://"; } $url .= $protocol.$domainName; if (!$store->isDefault() && !$this->featureToggle) { $trySSL = false; $url .= $store->GetFullUrl($trySSL, $isMobile); } } if ($this->featureToggle) { Saturday, February 8, 14
  68. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true { $url = ""; $protocol = $this->config->secureProtocol; if ($includeDomain) { $domainName = $this->getDomainNameForStore($store); // snip } // snip } private function getDomainNameForStore($store) { $domainName = $this->config->storeDomainName; if ($store->isDefault()) { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } } } } Saturday, February 8, 14
  69. whew Saturday, February 8, 14

  70. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true) { $url = ""; if (!$store->isDefault()) { $trySSL = false; $forceToCore = false; if ($this->featureToggle) { if ($includeDomain) { $url .= $this->config->secureProtocol.$this->config->storeDomainName; } $url .= "/checkout?product_id=".$this->productId; if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } } else { if ($includeDomain) { $url .= $store->GetFullUrl($trySSL, $isMobile); } $url .= "/resort_detail.php?ProductId=".$this->productId; if ($this->isDated()) { $url .= "&StartDate=".date("Y-m-d", strtotime($this->date)); } } } else { $domainName = $this->config->domainName; if (!$domainName) { $domainName = $this->config->desktopDomainName; } if ($this->featureToggle) { if ($includeDomain) { $url .= $this->config->secureProtocol.$domainName; } $url .= "/checkout?product_id=".$this->productId; if ($this->isDated()) { $url .= "&date=".date("Y-m-d", strtotime($this->date)); } } else { if ($includeDomain) { $url .= "http://".$domainName; } $url .= "/resort_detail.php?ProductId=".$this->productId; if ($this->isDated()) { $url .= "&StartDate=".date("Y-m-d", strtotime($this->date)); } } } } } Saturday, February 8, 14
  71. class Product { public function createUrl($store, $isMobile = false, $includeDomain

    = true) { $url = ""; $protocol = $this->config->secureProtocol; if ($includeDomain) { $domainName = $this->getDomainNameForStore($store); if ($store->isDefault() && !$this->featureToggle) { $protocol = "http://"; } $url .= $protocol.$domainName; if (!$store->isDefault() && !$this->featureToggle) { $trySSL = false; $url .= $store->GetFullUrl($trySSL, $isMobile); } } if ($this->featureToggle) { $url .= "/checkout?product_id=".$this->productId; } else { $url .= "/product_detail.php?ProductId=".$this->productId; } if ($this->isDated) { $dateParam = $this->featureToggle ? "start_date" : "StartDate"; $url = "&{$dateParam}=" . date("Y-m-d", strtotime($this->date)); } } private function getDomainNameForStore($store) Saturday, February 8, 14
  72. recap Saturday, February 8, 14

  73. recap Code should be understandable by humans. Saturday, February 8,

    14
  74. recap Code should be understandable by humans. Clean code is

    readable, cared for, efficient, extensible, and simple. Saturday, February 8, 14
  75. recap Code should be understandable by humans. Clean code is

    readable, cared for, efficient, extensible, and simple. Write dirty code and successively refine. Saturday, February 8, 14