Pro Yearly is on sale from $80 to $50! »

Functional Application Design in PHP

Functional Application Design in PHP

A review of contemporary application design in PHP, and the over-reliance on object-orientation to solve all problems. A major alternative to this paradigm, functional programming, is poorly supported in PHP, however there is still a lot of architectural inspiration we can derive from functional languages.

Bd46180824315fc1d313cba55d8ed0a3?s=128

Michael John Burgess

January 24, 2014
Tweet

Transcript

  1. FUNCTIONAL APPLICATION DESIGN IN PHP Michael J. Burgess @mjburgess #fadphp

  2. ABSTRACT THIS TALK WILL… • review “contemporary application design in

    PHP” • present “a major alternative […], functional programming” • discuss “architectural inspiration we can derive from functional languages” • conclude functional design has much better ‘performance’ under ideal conditions
  3. ABSTRACT OVERVIEW • Introduction • What is Application Design? •

    A History of Application Design in PHP • Problem • How do we do better? • How do you measure the performance of a design paradigm? • How does the present paradigm (and alternatives) perform? • Idea • Functional design has better performance under ideal conditions • Details • Conclusions
  4. INTRODUCTION WHAT IS APPLICATION DESIGN? • Patterns in problems become

    themselves problems $a, $b $weight, $height $weightKg, $heightFt … one file ℎ many files many functions/file one class/file … • Design paradigms ( ) distribute this labour (eg. debugging $a) • Design paradigms ( ) map problem domain to program domain • Design (specializing ) is cognitive (‘conceptual’) labour
  5. INTRODUCTION WHAT IS APPLICATION DESIGN? Linear Procedural OO A Person

    $name = ‘M’; $age = 24; [‘name’ => ‘M’, ‘age’ => 24 ] new Person(‘M’, 24) An Event switch callback observer Protection $pwd == $password is_allowed($pwd) new ACL()->check($U) HTTP State $_POST get_post() $request->getPost()
  6. INTRODUCTION WHAT IS APPLICATION DESIGN? • the aim of design

    is to minimize spare complexity ie. complexity not due to the language or the problem domain • Your application design should be as complex as your problem domain • too simple => complexity hiding => making careless assumptions • too complex => difficult to understand => difficult to reason about • Paradigms usually sold on a ‘spare complexity economy’ • ‘Spare complexity’ is the complexity which arises when mapping the problem domain to program domain • A ‘spare complexity economy’ is therefore how paradigms change how complex this mapping becomes for different kinds of application
  7. 0 10 20 30 40 50 60 70 80 90

    100 Physics Simulations HTTP Apps Games Concurrent Apps Linear Proceedural OO Functional INTRODUCTION SPARE COMPLEXITY
  8. INTRODUCTION WHAT IS APPLICATION DESIGN? • The spare complexity economy

    for HTTP Applications underdetermines our paradigm choice • Web Application design is an ‘aparadigmatic’ case. • Most problems may be phrased on way or another without incurring additional spare complexity (nb. more code != more spare complexity!) • So, what other important measures of paradigm ‘performance’ are there? • Planning (client requirements, technical architecture, integration…), • Programming (static requirements, dynamic requirements, new requirements, …), • Maintenance (misapplied rules, broken code, …) • Describe the difficulty of these (for a programmer) as ‘conceptual labour’; this translates into training difficulty, time, cost, etc.
  9. 0% 10% 20% 30% 40% 50% 60% 70% 80% 90%

    100% OO Proceedural Linear Planning Programming Maintaining INTRODUCTION CONCEPTUAL LABOUR BREAKDOWN
  10. ie., where do the ‘Conceptual Labour’ numbers come from? •

    Phenomenology of Programming • Also, phenomenology of planning, of maintaining, etc. which require different analyses • Reasoning vs Compiling • Conceptual Models • Non-conscious reasoning • State Change and Execution Flow PROBLEM MEASURING PARADIGM PERFORMANCE
  11. PROBLEM ASSESSING CURRENT BEST PRACTICE • What is our present

    paradigm? • Object Orientation != Good Programmer • correlation != causation • Object Orientation vs Type Orientation • Dependency Injection: Hidden Type Orientation? • How do our present paradigms perform? • Object Orientation • DI/Type Orientation
  12. PROBLEM ASSESSING FUNCTIONAL PROGRAMMING • What is the functional paradigm?

    • Key terms: • function f value vs. procedure vs. method • application f($x) ‘filling in the gaps’ vs. execution • Transformation [1, 2, 3] -> 6 relations vs. destructions • Composition f(g($x)) flow vs. steps • State is function application • Execution flow is function application …therefore… • State is a series of transformations • Execution flow is a kind of composition • How does the function paradigm perform?
  13. DETAILS FUNCTIONAL PROGRAMMING $input = [['Michael', 24], ['Lucy', 17]]; function

    under18($x) { return $x < 18; } function getSecond(array $xs) { return $xs[1]; } $output = array_map('under18', array_map('getSecond', $input)); $> [false, true] function lessThan($y) { return function ($x) use($y) { return $x < $y; }; } function getNth($n) { return function (array $xs) use($n) { return $xs[$n - 1]; }; } $output = array_map(lessThan(18), array_map(getNth(2), $input)); $> [false, true]
  14. DETAILS FUNCTIONAL STATE //immutable lightweight data representation function newPerson($name, $age)

    { return [$name, $age]; } function personName($person) { return $person[0]; } function personAge($person) { return $person[1]; } function agePerson($person, $age = 1) { return newPerson(personName($person), personAge($person) + $age); } function fmtPerson($person) { return newPerson(ucwords(personName($person)), personAge($person)); } $input = [newPerson('michael burgess', 24), newPerson('lucy rain', 17)]; $output = array_map('fmtPerson', array_map('agePerson', $input)); $> [['Michael Burgess', 25], ['Lucy Rain', 18]]
  15. DETAILS FUNCTIONAL EXECUTION FLOW function age($person) { return [ $person[0],

    $person[1] + 1 ]; } function format($person) { return [ ucwords($person[0]), $person[1] ]; } function mapWith($fn) { return function ($xs) use($fn) { return array_map($fn, $xs); }; } function chain($flow, $xs) { foreach($flow as $fn) { $xs = $fn($xs); //cheating! (a little…) } return $xs; } $flow = [mapWith('age'), mapWith('format')]; $input = [['michael burgess', 24], ['lucy rain', 17]]; $output = chain($flow, $input); $> [['Michael Burgess', 25], ['Lucy Rain', 18]]
  16. DETAILS FUNCTIONAL DESIGN CONCLUSIONS • Programs use • Input state

    $input = [$_GET, $_POST]; ? • Arrays of functions $flow = [data(), model($x), view($y), …]; ? • A HOF defining flow $output = chain($flow, $input); ? • Light-weight data representation • Function combination to achieve novelty • Programs do not • mutate state ( have side effects ) • have unpredictable execution flow
  17. DETAILS FUNCTIONAL DESIGN CONCLUSIONS • Problems • Function combination in

    PHP is poor & no dynamic definitions • No immutable data collection • No function-level polymorphism ( & no types ) add(18, 1) is the same function as add(‘Hello ’, ‘World’) • No syntax sugar (function deferencing foo()(), …) • Decomposition support (eg. list) is poor • etc. • Solution • Combine Objects & Functional Programming: Object-Functional Programming
  18. DETAILS OBJECT-FUNCTIONAL DESIGN • What is a web application? •

    Input, ‘Application Context’ • HTTP Context: [$_SERVER, $_GET, $_POST, $_COOKIE] • Static Context: [$_ENV, $_SESSION, $CONFIG] • Runtime Context: [$actions, $services] • Output • String (Template, View, HTML, etc.) • Transformation • ApplicationContext -> Response • [httpContext, $staticContext, $runtimeContext] -> Response -> string • AppContext -> Request (AppContext) -> Response (string) -> string • Request (AppContext) -> Action (Request, AppCtx) -> Response
  19. DESIGN OBJECT-FUNCTIONAL WEB APPS class ApplicationContext { private $httpContext, $staticContext,

    $runtimeContext; public function setHttpContext(HttpServer $s, HttpRequest $r) {} public function setStaticContext(array $env, HttpSession $s) {} public function setRuntimeContext(Router $r, ServiceManager $s) {} } class Request { private $appContext, $target; } class Response { private $string; } class ToAppContext implements IArrayTransform { public function __invoke() {} } class ToRequest implements IContextTransform {} //ToHttpRequest, ToCliRequest,... class ToAction implements IRequestTransform {} //ToRestfulAction, ... class ToResponse implements IActionTransform {} //ToHttpResonse, ToCliResponse, ... class ToOutput implements IResponseTransform {} //ToJsonOutput, ToXmlOutput, ... $flow = ['ToAppContext', 'ToRequest', 'ToAction', 'ToResponse', 'ToOutput']; $string = chainAppFlow($flow, $actions, [$_SERVER, $_GET, $_POST /*, ...*/]); echo $string;
  20. DESIGN OBJECT-FUNCTIONAL WEB APPS $actions = ['/' => function (Request

    $r) { return $r->getAppContext()->write('Hello World!'); },]; $router = function () { return '/'; }; $services = ['write' => 'print_r']; $flow = new Flow(); $flow->then(function () use($actions, $services) { return new ToApplicationContext($actions, $services); }); $flow->then(function () use($router) { return new ToRequest($router); }); $flow->then(function () { return new ToAction(); }); $flow->then(function () { return new ToResponse(); }); $flow->then(function () { return new ToOutput(); }); $flow->run([$_SERVER, $_GET, $_POST]); $> Hello World
  21. • If actions return Views and Models are Tod by

    the service layer then this has a 1:1 conceptual correspondence with MVC. • Objection: this is just MVC! • Zend2/Symfony/etc. basically have these steps in their dispatch structure. • Reply: that’s true. But they aren’t phrased to: • Transform rather than mutate (cf. problems of state) • Constrain execution flow with higer-order functions (__invokeables, etc.) • Expose execution flow (cf. xml files & type relations) DESIGN OBJECT-FUNCTIONAL WEB APPS
  22. 0% 10% 20% 30% 40% 50% 60% 70% 80% 90%

    100% Functional O-Functional Type-O OO Proceedural Linear Planning Programming Maintaining CONCLUSIONS CONCEPTUAL LABOUR BREAKDOWN
  23. 0% 10% 20% 30% 40% 50% 60% 70% 80% 90%

    100% Functional O-Functional Type-O OO Proceedural Linear Developing Expanding Dynamic CONCLUSIONS CODING LABOUR
  24. 0% 10% 20% 30% 40% 50% 60% 70% 80% 90%

    100% Functional O-Functional Type-O OO Proceedural Linear Requirements Architecture Integration CONCLUSIONS PLANNING LABOUR
  25. 0% 10% 20% 30% 40% 50% 60% 70% 80% 90%

    100% Functional O-Functional Type-O OO Proceedural Linear Planning Programming Maintaining CONCLUSIONS CONCEPTUAL LABOUR BREAKDOWN
  26. 0% 10% 20% 30% 40% 50% 60% 70% 80% 90%

    100% Functional O-Functional Type-O OO Proceedural Linear Prq Parch Pint Cdev Cexp Cdyn Mdom Mprog CONCLUSIONS CONCEPTUAL LABOUR 8D-BREAKDOWN
  27. • Conceptual labour distributions describe the effect of the paradigm

    on a programmer • They imply team distributions, market requirements, …, i.e., ‘ideal conditions’ under which a paradigm will reach its inherent distribution • CL distributions do not imply fixed time, costs, etc. • CL distributions in conjunction with empirical distributions do imply time (for comparable problem domains) CONCLUSIONS ‘IDEAL CONDITIONS’
  28. 0 100 200 300 400 500 600 Functional O-Functional Type-O

    OO Proceedural Linear $k/Lifetime/Application CONCLUSIONS LABOUR COMPARISON IS NOT ZERO SUM
  29. 0 100 200 300 400 Functional O-Functional Type-O OO Proceedural

    Linear Programmers/100k People CONCLUSIONS LABOUR COMPARISON IS NOT ZERO SUM
  30. • ‘Pure programmers’ want to drive the adoption of paradigms

    which maximize mastery • ‘Pure managers’ want to drive paradigms which maximize productivity. • I consider type-orientation a symptom of managerial programming: trading programmers’ self-development for a team stratification which suits market/empirical conditions • However, we can resist stratifying paradigms by investing in programmers: by changing market conditions • nb. ‘Best Practices’ evolve under these two (mastery, productivity) pressures! CONCLUSIONS THE SOCIOLOGY OF APPLICATION DESIGN
  31. CONCLUSIONS TAKE-AWAYS • Paradigms distribute conceptual labour (but not zero-sum!)

    • Comparing paradigms is difficult • The functional paradigm offers PHP a different (object-functional) direction • In one conclusion, Functional design has much better performance under ideal conditions
  32. QUESTIONS? Functional Application Design in PHP by Michael J. Burgess

    @mjburgess #fadphp