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

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.

Michael John Burgess

January 24, 2014
Tweet

Other Decks in Programming

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