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

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.

Tomasz Kowalczyk

March 08, 2018
Tweet

More Decks by Tomasz Kowalczyk

Other Decks in Programming

Transcript

  1. functional approach in
    software design
    Tomasz Kowalczyk @tmmx

    View Slide

  2. View Slide

  3. View Slide

  4. introduction

    View Slide

  5. purpose

    View Slide

  6. levels

    View Slide

  7. level 0: approach

    View Slide

  8. paradigm shift

    View Slide

  9. SOLID

    View Slide

  10. immutability

    View Slide

  11. higher order functions

    View Slide

  12. composition

    View Slide

  13. level 1: operations

    View Slide

  14. casual conditionals

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  19. endless loops

    View Slide

  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;

    View Slide

  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;

    View Slide

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

    View Slide

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

    View Slide

  24. accidental accumulators

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  29. combined

    View Slide

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

    View Slide

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

    View Slide

  32. level 2: components

    View Slide

  33. request lifecycle

    View Slide

  34. entry | input → request
    routing | request → route
    controller | controller → response
    events | request → request
    | response → response
    forms | data → mapping
    validation | data → violations

    View Slide

  35. $response = controller(route($request));

    View Slide

  36. object graph serialization

    View Slide

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

    View Slide

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

    View Slide

  39. $normalizers = new NormalizerContainer();
    $normalizers->add(User::class, function(User $u) {
    return [
    'id' => $u->getId(),
    'email' => $u->getEmail(),
    ];
    });

    View Slide

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

    View Slide

  41. $formats = new FormatContainer();
    $formats->add('json', new JsonFormat());

    View Slide

  42. $s = new Serializard($normalizers, $hydrators, $formats);
    $user = new User(1337, '[email protected]');
    $json = $s->serialize($user, 'json');
    $user = $s->unserialize($json, 'json', User::class);

    View Slide

  43. shortcode processing

    View Slide

  44. This is a [b]bold text[/b].
    This is a bold text.

    View Slide

  45. string → parse → process → replace → string

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  49. $processor = new Processor($parser, $handlers);
    $text = 'This is a [b]bold text[/b].';
    $result = $processor->process($text);

    View Slide

  50. level 3: systems

    View Slide

  51. modelling data flow

    View Slide

  52. applications
    microservices
    APIs

    View Slide

  53. challenges

    View Slide

  54. purpose

    View Slide

  55. comfort zone

    View Slide

  56. "real world"

    View Slide

  57. performance

    View Slide

  58. summary

    View Slide

  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)

    View Slide

  60. questions?

    View Slide

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

    View Slide

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

    View Slide

  63. thanks!
    github /thunderer
    twitter @tmmx

    View Slide