Functional approach in software design

Functional approach in software design

Functional programming is a paradigm known for decades. It is gaining popularity again, due to the rise of purely functional languages like Haskell. You may wonder, how it could be useful in PHP? Using a few techniques and a slight change of perspective you will be able to write code that is cleaner and easier to understand. You will be able to design and implement huge solutions by composing them from small and well-tested parts.

Bb29f6afb2ea244a12c25e04d46af19c?s=128

Tomasz Kowalczyk

March 08, 2018
Tweet

Transcript

  1. functional approach in software design Tomasz Kowalczyk @tmmx

  2. None
  3. None
  4. introduction

  5. purpose

  6. levels

  7. level 0: approach

  8. paradigm shift

  9. SOLID

  10. immutability

  11. higher order functions

  12. composition

  13. level 1: operations

  14. casual conditionals

  15. $result = []; foreach($this->users as $user) { if($user->isDisabled()) { continue;

    } if($user->isHidden()) { continue; } $result[] = $user; } return $result;
  16. $result = []; foreach($this->users as $user) { if($user->isDisabled()) { continue;

    } if($user->isHidden()) { continue; } $result[] = $user; } return $result;
  17. $isEnabled = function(User $u): bool { return false === $u->isDisabled();

    }; $isVisible = function(User $u): bool { return false === $u->isHidden(); }; return array_filter( array_filter($this->users, $isVisible), $isEnabled);
  18. $isEnabled = function(User $u): bool { return false === $u->isDisabled();

    }; $isVisible = function(User $u): bool { return false === $u->isHidden(); }; return $this->users ->filter($isVisible) ->filter($isEnabled);
  19. endless loops

  20. $ids = []; foreach($this->users as $user) { foreach($user->getTags() as $tag)

    { $tagId = $tag->getId(); if(false === in_array($tagId, $ids, true)) { $ids[] = $tagId; } } } return $ids;
  21. $ids = []; foreach($this->users as $user) { foreach($user->getTags() as $tag)

    { $tagId = $tag->getId(); if(false === in_array($tagId, $ids, true)) { $ids[] = $tagId; } } } return $ids;
  22. $userToTags = function(User $user): array { return $user->getTags(); }; $tagToId

    = function(Tag $tag): int { return $tag->getId(); }; return array_unique(array_map($tagToId, array_merge( ...array_map($userToTags, $this->users) )));
  23. $userToTags = function(User $user): array { return $user->getTags(); }; $tagToId

    = function(Tag $tag): int { return $tag->getId(); }; return $this->users ->flatMap($userToTags) ->map($tagToId) ->unique();
  24. accidental accumulators

  25. $points = 0; foreach($this->users as $user) { $points += $user->getPoints();

    } return $points;
  26. $points = 0; foreach($this->users as $user) { $points += $user->getPoints();

    } return $points;
  27. $addPoints = function(int $state, User $user): int { return $state

    + $user->getPoints(); }; return array_reduce($this->users, $addPoints, 0);
  28. $addPoints = function(int $state, User $user): int { return $state

    + $user->getPoints(); }; return $this->users ->reduce($addPoints, 0);
  29. combined

  30. $isEnabled = function(User $u): bool { return !$u->isDisabled(); }; $isVisible

    = function(User $user): bool { return !$u->isHidden(); }; $userToPoints = function(User $user): int { return $user->getPoints(); }; $addPoints = function(int $st, User $u): int { return $st + $u->getPoints(); }; return $this->users ->filter($isEnabled) ->filter($isVisible) ->map($userToPoints) ->reduce($addPoints, 0);
  31. $isEnabled = function(User $u): bool { return !$u->isDisabled(); }; $isVisible

    = function(User $user): bool { return !$u->isHidden(); }; $userToPoints = function(User $user): int { return $user->getPoints(); }; $addPoints = function(int $st, User $u): int { return $st + $u->getPoints(); }; return $this->users ->filter($isEnabled) ->filter($isVisible) ->map($userToPoints) ->reduce($addPoints, 0);
  32. level 2: components

  33. request lifecycle

  34. entry | input → request routing | request → route

    controller | controller → response events | request → request | response → response forms | data → mapping validation | data → violations
  35. $response = controller(route($request));

  36. object graph serialization

  37. objects → normalization → formatting → data data → parsing

    → hydration → objects
  38. $json = format(normalize($user)) $user = hydrate(parse($json))

  39. $normalizers = new NormalizerContainer(); $normalizers->add(User::class, function(User $u) { return [

    'id' => $u->getId(), 'email' => $u->getEmail(), ]; });
  40. $hydrators = new HydratorContainer(); $hydrators->add(User::class, function(array $data) { return new

    User($data['id'], $data['email']); });
  41. $formats = new FormatContainer(); $formats->add('json', new JsonFormat());

  42. $s = new Serializard($normalizers, $hydrators, $formats); $user = new User(1337,

    'email@example.com'); $json = $s->serialize($user, 'json'); $user = $s->unserialize($json, 'json', User::class);
  43. shortcode processing

  44. This is a [b]bold text[/b]. This is a <strong>bold text</strong>.

  45. string → parse → process → replace → string

  46. $string = replace(process(parse($input)))

  47. $handlers = new HandlerContainer(); $handlers->add('b', function(ShortcodeInterface $s) { return '<strong>'.$s->getContent().'</strong>';

    });
  48. $parser = new RegexParser(); $parser = new WordpressParser(); $parser =

    new RegularParser();
  49. $processor = new Processor($parser, $handlers); $text = 'This is a

    [b]bold text[/b].'; $result = $processor->process($text);
  50. level 3: systems

  51. modelling data flow

  52. applications microservices APIs

  53. challenges

  54. purpose

  55. comfort zone

  56. "real world"

  57. performance

  58. summary

  59. Slides: https://speakerdeck.com/thunderer/functional-approach-in-software-design Resources: https://github.com/thunderer/Shortcode https://github.com/thunderer/Serializard https://en.wikipedia.org/wiki/Functional_programming http://www.phptherightway.com/pages/Functional-Programming.html https://www.smashingmagazine.com/2014/07/dont-be-scared-of-functional-programming https://pragprog.com/magazines/2012-08/functional-thinking-for-the-imperative-mind http://lambdaconf.us/downloads/documents/lambdaconf_slfp.pdf

    Images: https://www.flickr.com/photos/kinematic/4078206226 (rocks) https://www.flickr.com/photos/kyetis/12506278675 (stones) https://www.flickr.com/photos/skyseeker/14404947216 (lightning)
  60. questions?

  61. how can I help? github /thunderer twitter @tmmx

  62. please rate the talk and leave feedback joind.in/talk/c0b77

  63. thanks! github /thunderer twitter @tmmx