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

Curing the Common Loop

Curing the Common Loop

Trying to understand a complex function full of nested loops and conditionals is like trying to read a "choose your own adventure" book from front to back.

In this whirlwind tour of programming with collection pipelines, you'll learn how to use functional programming ideas to break down complex code and abstract hidden duplication behind expressive higher order functions.

Together we'll refactor ugly, complicated spaghetti into a series of simple, elegant transformations; free of loops, complex conditionals, and temporary variables.

34147b9eecf59779b777eb68a1805113?s=128

Adam Wathan

July 29, 2016
Tweet

Transcript

  1. Curing the Common Loop @adamwathan

  2. $totalRevenue = 0; $minSales = 75000; foreach ($employees as $employee)

    { $employeeType = $employee->getType(); if ($employeeType == 'Sales') { $customers = $employee->getCustomers(); foreach ($customers as $customer) { $customerTotalSales = 0; foreach ($customer->getOrders() as $order) { $customerTotalSales += $order->total; } if ($customerTotalSales >= $minSales) { $totalRevenue += $customerTotalSales; } } } } return $totalRevenue;
  3. Higher Order FUNCTIONS

  4. Route::get('/', function () { return view('welcome'); });

  5. Mail::send('order-shipped', $data, function ($m) { $m->to($this->customer->email); $m->subject("Your order has shipped!");

    });
  6. DB::transaction(function () use ($user) { $user->subscription()->delete(); $user->update([ 'cancelled_at' => Carbon::now()

    ]); });
  7. Afford more powerful ABSTRACTIONS

  8. For example…

  9. $customerEmails = []; foreach ($customers as $customer) { $customerEmails[] =

    $customer->email; } return $customerEmails;
  10. $stockTotals = []; foreach ($inventoryItems as $item) { $stockTotals[] =

    [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; } return $stockTotals;
  11. $customerEmails = []; foreach ($customers as $customer) { $customerEmails[] =

    $customer->email; } return $customerEmails;
  12. $customerEmails = []; foreach ($customers as $customer) { $email =

    $customer->email; $customerEmails[] = $email; } return $customerEmails;
  13. $stockTotals = []; foreach ($inventoryItems as $item) { $stockTotals[] =

    [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; } return $stockTotals;
  14. $stockTotals = []; foreach ($inventoryItems as $item) { $stockTotal =

    [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; $stockTotals[] = $stockTotal; } return $stockTotals;
  15. $stockTotals = []; foreach ($inventoryItems as $item) { $stockTotal =

    [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; $stockTotals[] = $stockTotal; } return $stockTotals;
  16. $results = []; foreach ($items as $item) { $result =

    [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; $results[] = $result; } return $results;
  17. $results = []; foreach ($items as $item) { $result =

    $item->email; $results[] = $result; } return $results;
  18. $results = []; foreach ($items as $item) { $result =

    $item->email; $results[] = $result; } return $results;
  19. $callback = function ($item) { return $item->email; }; $results =

    []; foreach ($items as $item) { $result = $callback($item); $results[] = $result; } return $results;
  20. $results = []; foreach ($items as $item) { $result =

    [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; $results[] = $result; } return $results;
  21. $callback = function ($item) { return [ 'product' => $item->productName,

    'total_value' => $item->quantity * $item->price, ]; }; $results = []; foreach ($items as $item) { $result = $callback($item); $results[] = $result; } return $results;
  22. $callback = function ($item) { return [ 'product' => $item->productName,

    'total_value' => $item->quantity * $item->price, ]; }; $results = []; foreach ($items as $item) { $result = $callback($item); $results[] = $result; } return $results;
  23. $callback = function ($item) { return $item->email; }; $results =

    []; foreach ($items as $item) { $result = $callback($item); $results[] = $result; } return $results;
  24. function array_map($callback, $items) { } $results = []; foreach ($items

    as $item) { $result = $callback($item); $results[] = $result; } return $results;
  25. $customerEmails = []; foreach ($customers as $customer) { $customerEmails[] =

    $customer->email; } return $customerEmails;
  26. $customerEmails = array_map(function ($customer) { return $customer->email; }, $customers);

  27. $stockTotals = []; foreach ($inventoryItems as $item) { $stockTotals[] =

    [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; } return $stockTotals;
  28. $stockTotals = []; foreach ($inventoryItems as $item) { $stockTotals[] =

    [ 'product' => $item->productName, 'total_value' => $item->quantity * $item->price, ]; } return $stockTotals;
  29. $stockTotals = array_map(function ($inventoryItem) { return [ 'product' => $item->productName,

    'total_value' => $item->quantity * $item->price, ]; }, $inventoryItems);
  30. Another…

  31. $outOfStockProducts = []; foreach ($products as $product) { if ($product->isOutOfStock())

    { $outOfStockProducts[] = $product; } } return $outOfStockProducts;
  32. $expensiveProducts = []; foreach ($products as $product) { if ($product->price

    > 100) { $expensiveProducts[] = $product; } } return $expensiveProducts;
  33. $results = []; foreach ($items as $item) { if ($item->price

    > 100) { $results[] = $item; } } return $results;
  34. $outOfStockProducts = []; foreach ($products as $product) { if ($product->isOutOfStock())

    { $outOfStockProducts[] = $product; } } return $outOfStockProducts;
  35. $results = []; foreach ($items as $item) { if ($item->isOutOfStock())

    { $results[] = $item; } } return $results;
  36. $results = []; foreach ($items as $item) { if ($item->isOutOfStock())

    { $results[] = $item; } } return $results;
  37. $results = []; foreach ($items as $item) { if ($item->price

    > 100) { $results[] = $item; } } return $results;
  38. $callback = function ($item) { return $item->price > 100; };

    $results = []; foreach ($items as $item) { if ($callback($item)) { $results[] = $item; } } return $results;
  39. $results = []; foreach ($items as $item) { if ($item->isOutOfStock())

    { $results[] = $item; } } return $results;
  40. $callback = function ($item) { return $item->isOutOfStock(); }; $results =

    []; foreach ($items as $item) { if ($callback($item)) { $results[] = $item; } } return $results;
  41. $callback = function ($item) { return $item->isOutOfStock(); }; $results =

    []; foreach ($items as $item) { if ($callback($item)) { $results[] = $item; } } return $results;
  42. $callback = function ($item) { return $item->price > 100; };

    $results = []; foreach ($items as $item) { if ($callback($item)) { $results[] = $item; } } return $results;
  43. function array_filter($items, $callback) { $results = []; foreach ($items as

    $item) { if ($callback($item)) { $results[] = $item; } } return $results; } $results = []; foreach ($items as $item) { if ($callback($item)) { $results[] = $item; } } return $results;
  44. $outOfStockProducts = []; foreach ($products as $product) { if ($product->isOutOfStock())

    { $outOfStockProducts[] = $product; } } return $outOfStockProducts;
  45. $outOfStockProducts = array_filter($products, function ($product) { return $product->isOutOfStock(); });

  46. $expensiveProducts = []; foreach ($products as $product) { if ($product->price

    > 100) { $expensiveProducts[] = $product; } } return $expensiveProducts;
  47. $expensiveProducts = array_filter($products, function ($product) { return $product->price > 100;

    });
  48. function getSalesEmails($employees) { $emails = []; foreach ($employees as $employee)

    { if ($employee->department === 'Sales') { $emails[] = $employee->email; } } return $emails; }
  49. function getSalesEmails($employees) { $emails = []; foreach ($employees as $employee)

    { if ($employee->department === 'Sales') { $emails[] = $employee->email; } } return $emails; } …map?
  50. function getSalesEmails($employees) { $emails = []; foreach ($employees as $employee)

    { if ($employee->department === 'Sales') { $emails[] = $employee->email; } } return $emails; }
  51. Thinking in STEPS

  52. function getSalesEmails($employees) { $emails = []; foreach ($employees as $employee)

    { if ($employee->department === 'Sales') { $emails[] = $employee->email; } } return $emails; }
  53. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = []; foreach ($employees as $employee) { if ($employee->department === 'Sales') { $emails[] = $employee->email; } } return $emails; }
  54. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = []; foreach ($employees as $employee) { if ($employee->department === 'Sales') { $emails[] = $employee->email; } } return $emails; }
  55. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = []; foreach ($employees as $employee) { if ($employee->department === 'Sales') { $emails[] = $employee->email; } } return $emails; }
  56. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = []; foreach ($salesEmployees as $employee) { if ($employee->department === 'Sales') { $emails[] = $employee->email; } } return $emails; }
  57. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = []; foreach ($salesEmployees as $employee) { if ($employee->department === 'Sales') { $emails[] = $employee->email; } } return $emails; }
  58. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = []; foreach ($salesEmployees as $employee) { $emails[] = $employee->email; } return $emails; }
  59. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = []; foreach ($salesEmployees as $employee) { $emails[] = $employee->email; } return $emails; }
  60. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = []; foreach ($salesEmployees as $employee) { $emails[] = $employee->email; } return $emails; } Map!
  61. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = []; foreach ($salesEmployees as $employee) { $emails[] = $employee->email; } return $emails; }
  62. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = array_map(function ($employee) { return $employee->email; }, $salesEmployees); return $emails; }
  63. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = array_map(function ($employee) { return $employee->email; }, $salesEmployees); return $emails; }
  64. Things I HATE

  65. #1. FOR LOOPS #2. CONDITIONALS #3. TEMP VARIABLES

  66. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = array_map(function ($employee) { return $employee->email; }, $salesEmployees); return $emails; }
  67. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = array_map(function ($employee) { return $employee->email; }, $salesEmployees); return $emails; }
  68. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = array_map(function ($employee) { return $employee->email; }, $salesEmployees); return $emails; }
  69. Inline TEMP

  70. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = array_map(function ($employee) { return $employee->email; }, $salesEmployees); return $emails; }
  71. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); return array_map(function ($employee) { return $employee->email; }, $salesEmployees); }
  72. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); return array_map(function ($employee) { return $employee->email; }, $salesEmployees); }
  73. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); return array_map(function ($employee) { return $employee->email; }, $salesEmployees); }
  74. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); return array_map(function ($employee) { return $employee->email; }, $salesEmployees); }
  75. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); return array_map(function ($employee) { return $employee->email; }, array_filter($employees, function ($employee) { return $employee->department == 'Sales'; })); }
  76. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); return array_map(function ($employee) { return $employee->email; }, array_filter($employees, function ($employee) { return $employee->department == 'Sales'; })); }
  77. function getSalesEmails($employees) { return array_map(function ($employee) { return $employee->email; },

    array_filter($employees, function ($employee) { return $employee->department == 'Sales'; })); }
  78. The Problem With PRIMITIVES

  79. # => hello_there_laracon function toCamelCase($snakeString) { return lcfirst( str_replace(' ',

    '', ucwords(str_replace('_', ' ', $snakeString)) ) ); } # => helloThereLaracon
  80. # => hello_there_laracon function toCamelCase($snakeString) { return $snakeString->replace('_', ' ')

    ->ucwords() ->replace(' ', '') ->lcfirst(); } # => helloThereLaracon
  81. Introducing COLLECTIONS

  82. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = array_map(function ($employee) { return $employee->email; }, $salesEmployees); return $emails; }
  83. function getSalesEmails($employees) { $salesEmployees = array_filter($employees, function ($employee) { return

    $employee->department == 'Sales'; }); $emails = array_map(function ($employee) { return $employee->email; }, $salesEmployees); return $emails; }
  84. function getSalesEmails($employees) { $salesEmployees = $employees->filter(function ($employee) { return $employee->department

    == 'Sales'; }); $emails = array_map(function ($employee) { return $employee->email; }, $salesEmployees); return $emails; }
  85. function getSalesEmails($employees) { $salesEmployees = $employees->filter(function ($employee) { return $employee->department

    == 'Sales'; }); $emails = array_map(function ($employee) { return $employee->email; }, $salesEmployees); return $emails; }
  86. function getSalesEmails($employees) { $salesEmployees = $employees->filter(function ($employee) { return $employee->department

    == 'Sales'; }); $emails = $salesEmployees->map(function ($employee) { return $employee->email; }); return $emails; }
  87. function getSalesEmails($employees) { return $employees->filter(function ($employee) { return $employee->department ==

    'Sales'; })->map(function ($employee) { return $employee->email; }); }
  88. Let’s write SOME CODE!

  89. http://www.fullstackradio.com FULL RADIO STACK

  90. @adamwathan adamwathan.me