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

The Language Of Collections

E18c5cba78277eb42c8473e0861262ef?s=47 turanct
September 26, 2017

The Language Of Collections

E18c5cba78277eb42c8473e0861262ef?s=128

turanct

September 26, 2017
Tweet

Transcript

  1. Exploring The Language Of Collections

  2. twitter.com/tinydroptest2 github.com/turanct

  3. engagor.github.io

  4. Exploring The Language Of Collections

  5. situation

  6. you nd this in your codebase public function displayCoffeeRunsOpenForOrders() {

    $coffeeRuns = $this->coffeeRunsRepository->getAll(); $openForOrders = array(); foreach ($coffeeRuns as $coffeeRun) { if ($coffeeRun->ordersCanBeMade()) { $openForOrders[] = $coffeeRun; } } return $openForOrders; }
  7. wait a minute

  8. what if CoffeeRunsRepository contains 10 years worth of coffee runs

  9. None
  10. experiment 1: iterator

  11. we had this public function displayCoffeeRunsOpenForOrders() { $coffeeRuns = $this->coffeeRunsRepository->getAll();

    $openForOrders = array(); foreach ($coffeeRuns as $coffeeRun) { if ($coffeeRun->ordersCanBeMade()) { $openForOrders[] = $coffeeRun; } } return $openForOrders; }
  12. Repository implements Iterator public function displayCoffeeRunsOpenForOrders() { $coffeeRuns = $this->coffeeRunsRepository;

    $openForOrders = array(); foreach ($coffeeRuns as $coffeeRun) { if ($coffeeRun->ordersCanBeMade()) { $openForOrders[] = $coffeeRun; } } return $openForOrders; }
  13. memory problem solved* *depending on implementation

  14. new problem created have a guess?

  15. dependency injection public function __construct( CoffeeRunsRepository $coffeeRuns ) { $this->coffeeRuns

    = $coffeeRuns; } foreach ($this->coffeeRuns as $coffeeRun) { // ... }
  16. we're using an undocumented interface

  17. interface CoffeeRunsRepository { /** * @return CoffeeRun[] A list of

    CoffeeRuns */ public function getAll(); } make Repostory interface extend Iterator interface? typehint on Iterator instead of the repository?
  18. None
  19. experiment 2: classic refactor

  20. we had this public function displayCoffeeRunsOpenForOrders() { $coffeeRuns = $this->coffeeRuns->getAll();

    $openForOrders = array(); foreach ($coffeeRuns as $coffeeRun) { if ($coffeeRun->ordersCanBeMade()) { $openForOrders[] = $coffeeRun; } } return $openForOrders; }
  21. we end up with this public function displayCoffeeRunsOpenForOrders() { return

    $this->coffeeRuns->openForOrders(); }
  22. return coffee runs that are open for orders

  23. interface changed interface CoffeeRunsRepository { // ... /** * @return

    CoffeeRun[] A list of CoffeeRuns open for orders */ public function openForOrders(); // ... }
  24. wait a minute

  25. what if we want to have runs open for orders

    happening before noon? our interface will grow and grow and grow
  26. None
  27. experiment 3: laravel collections

  28. public function displayCoffeeRunsOpenForOrders() { $coffeeRuns = collect($this->coffeeRuns->getAll()); $openForOrders = $coffeeRuns->filter(

    function (CoffeeRun $run) { return $run->ordersCanBeMade(); } )->filter( function (CoffeeRun $run) { return $run->happensBeforeNoon(); } )->all(); return $openForOrders; } Eloquent always returns Collection s like this
  29. methods for ltering declarative style memory preserving* *when using eloquent

  30. unreadable mess jargon like filter

  31. recap

  32. not so nice: foreach over array Repository as an Iterator

    speci c ltering methods on Repository jargon
  33. nice: abstraction encapsulation contracts declarative style language

  34. experiment 4: language

  35. coffee runs that are open for orders .

  36. coffee runs that are open for orders and are happening

    before noon .
  37. coffee runs -> that are ( open for orders )->

    and are ( happening before noon );
  38. interface CoffeeRuns { /** * @param callable function that takes

    a CoffeeRun * and returns a boolean * * @return CoffeeRuns that match the predicate */ public function thatAre(callable $matchingPredicate); /** * @return CoffeeRun[] An array of CoffeeRuns */ public function asArray(); }
  39. public function displayCoffeeRunsOpenForOrders() { $coffeeRuns = $this->coffeeRuns->getAll(); $runsOpenForOrders = $coffeeRuns

    ->thatAre($openForOrders); return $runsOpenForOrders->asArray(); } public function displayCoffeeRunsBeforeNoonOpenForOrders() { $coffeeRuns = $this->coffeeRuns->getAll(); $runsOpenForOrders = $coffeeRuns ->thatAre($happeningBeforeNoon) ->thatAre($openForOrders); return $runsOpenForOrders->asArray(); }
  40. domain language declarative style small interfaces combinations possible

  41. wait a minute

  42. what if we want to have MySQL WHERE statements? our

    closures will not suf ce
  43. interface CoffeeRuns { /** * @param Predicate * * @return

    CoffeeRuns that match the predicate */ public function thatAre(Predicate $matching); /** * @return CoffeeRun[] An array of CoffeeRuns */ public function asArray(); } we could have Predicate objects that can be translated to a MySQL statement, or anything else
  44. shut up and take my money

  45. things to remember

  46. language helped us understand

  47. declarative style helped us understand

  48. contracts* helped us understand *interfaces, a.o.

  49. encapsulation helped us understand

  50. questions?

  51. twitter.com/tinydroptest2 github.com/turanct