La programmation fonctionnelle

pour les développeuses·eurs web

@ThibaudDauce | https://thibaud.dauce.fr
Quantic Telecom

Co-fondateur de Quantic Telecom

https://www.quantic-telecom.net
Apprendre Laravel

Thibaud Dauce sur YouTube

https://www.apprendre-laravel.fr

La programmation fonctionnelle

pour les développeuses·eurs web

@ThibaudDauce | https://thibaud.dauce.fr

Il y a 3 ans…

Haskell Book

Haskell c'est quoi ?

  • pas de conditions
  • pas de boucles
  • pas de variables

                        function getStudents() {
                            $customers = Customer::all();
                            $students = [];

                            foreach($customers as $customer) {
                                if ($customer->isStudent()) {
                                    $students[] = $customer;
                                }
                            }

                            return $students;
                        }
                    

                        function getStudents() {
                            $customers = Customer::all();
                            
                            return array_filter($customers, function ($customer) {
                                return $customer->isStudent();
                            });
                        }
                    

                        function getStudents() {
                            return Customer::all()
                                ->filter(function ($customer) {
                                    return $customer->isStudent();
                                });
                        }
                    

                        function getStudents() {
                            $customers = Customer::all();
                            
                            return array_filter(array_filter($customers, function ($customer) {
                                return $customer->isStudent();
                            }), function ($student) {
                                return $student->isValid();
                            });
                        }
                    

                        function getStudents() {
                            return Customer::all()
                                ->filter(function ($customer) {
                                    return $customer->isStudent();
                                });
                                ->filter(function ($student) {
                                    return $customer->isValid();
                                });
                        }
                    

                        function getMonthlyMeanRevenueForStudents() {
                            $customers = Customer::all();
                            $totalRevenue = [];
                            $counts = [];

                            foreach($customers as $customer) {
                                if ($customer->isStudent()) {
                                    foreach($customer->invoices() as $invoice) {
                                        $totalRevenue[$invoice->month()] +=
                                            $invoice->total();
                                        $counts[$invoice->month()]++;
                                    }
                                }
                            }
    
                            $meanRevenue = [];
                            foreach ($totalRevenue as $month => $total) {
                                $meanRevenue[$month] = $total / $counts[$month];
                            }
    
                            return $meanRevenue;
                        }
                    

                    function getMonthlyMeanRevenueForStudents() {
                        return Customer::all()
                            // [
                            //     'Étudiant John',
                            //     'Étudiante Jane',
                            //     'Entreprise Google',
                            // ]
                            ->filter(function ($customer) {
                                return $customer->isStudent();
                            })
                            // [
                            //     'Étudiant John',
                            //     'Étudiante Jane',
                            // ]
                            ->map(function ($student) {
                                return $student->invoices();
                            })
                            // [
                            //     ['2019-03-001', '2019-04-001'],
                            //     ['2019-03-002'],
                            // ]
                            ->flatten()
                            // [ '2019-03-001', '2019-04-001', '2019-03-002']
                            ->groupBy(function ($invoice) {
                                return $invoice->month();
                            })
                            // [
                            //     '2019-03' => ['2019-03-001', '2019-03-002'],
                            //     '2019-04' => ['2019-04-001'],
                            // ]
                            ->map(function ($invoices) {
                                // = ['2019-03-001', '2019-03-002']// = [80, 100]// = 180// = 90
                                return $invoices->map(function ($invoice) {
                                    return $invoice->total();
                                })->sum() / $invoices->count();
                            });
                            // [
                            //     '2019-03' => 90,
                            //     '2019-04' => 150,
                            // ]
                    }
                    

                        function getMonthlyMeanRevenueForStudents() {
                            $customers = Customer::all();
                            $totalRevenue = [];
                            $counts = [];
    
                            foreach($customers as $customer) {
                                if ($customer->isStudent()) {
                                    foreach($customer->invoices() as $invoice) {
                                        $totalRevenue[$invoice->month()] +=
                                            $invoice->total();
                                        $counts[$invoice->month()]++;
                                    }
                                }
                            }
    
                            $meanRevenue = [];
                            foreach ($totalRevenue as $month => $total) {
                                $meanRevenue[$month] = $total / $counts[$month];
                            }
    
                            return $meanRevenue;
                        }
                    

PHP RFC: Arrow Functions 2.0


                    function getMonthlyMeanRevenueForStudents() {
                        return Customer::all()
                            ->filter(fn($customer) => $customer->isStudent())
                            ->flatMap(fn($student) => $student->invoice())
                            ->groupBy(fn($invoice) => $invoice->month())
                            ->map(function ($invoices) {
                                $total = $invoices
                                    ->map(fn($invoice) => $invoice->total())
                                    ->sum();
                                return $total / $invoices->count();
                            });
                    }
                    

Middlewares

Gestion d'une Chaîne de traitement

Requête HTTP → Réponse HTTP

3 problèmes

  • Vérifiez que la personne est connectée
  • Ajouter un header HTTP à toutes les réponses
    (Content-Language: fr)
  • Enregistrer le temps de traitement d'une requête

                        function myMiddleware(Request $request, $next): Response
                        {
                            // $next = function (Request $request): Response {
                            //      return new Response(200, 'All good!');
                            // };

                            $response = $next($request);
                            return $response;
                        }
                    

Vérifiez que la personne est connectée


                        function authMiddleware(Request $request, $next): Response
                        {
                            if (! $request->session()->has('user')) {
                                return new Response(302, '/login');
                            }

                            $response = $next($request);
                            return $response;
                        }
                    

Ajouter un header HTTP à chaque réponse


                        function contentLanguageMiddleware(Request $request, $next): Response
                        {
                            $response = $next($request);

                            $response->headers()->add('Content-Language', 'fr');

                            return $response;
                        }
                    

Enregistrer le temps de traitement d'une requête


                        function timeMiddleware(Request $request, $next): Response
                        {
                            $start = microtime(true);
                            
                            $response = $next($request);

                            $time = microtime(true) - $start;
                            $text = "Request {$request->url()} took {$time}s \n";
                            file_put_content('timings.txt', $text, FILE_APPEND);

                            return $response;
                        }
                    

Exemples de middlewares avec Laravel


                        $middlewares = [
                            CheckForMaintenanceMode::class,
                            EncryptCookies::class,
                            StartSession::class,
                            ThrottleRequests::class,
                            ConvertEmptyStringsToNull::class,
                        ];
                    

L'ordre des middlewares


                        $middlewares = [
                            'authMiddleware',
                            'contentLanguageMiddleware',
                            'timeMiddleware',
                        ];
                    

                        $middlewares = [
                            'timeMiddleware',
                            'authMiddleware',
                            'contentLanguageMiddleware',
                        ];
                    

                        function otherMiddleware(ClasseA $classeA, $next): ClasseB
                        {
                            // $next = function (ClasseA $classeA): ClasseB {
                            //      return new ClasseB;
                            // };
        
                            $classeB = $next($classeA);
                            return $classeB;
                        }
                    

Un peu de Front-End

Elm

MVU

Model View Update

Model


                        type alias Model = String
                    

                        init : Model
                        init = "Thibaud"
                    

Update


                        type Event = NewName String | Reverse
                    

                        update : Event -> Model -> Model
                        update event oldName = case event of
                            NewName newName -> newName
                            Reverse -> String.reverse oldName
                    

View


                        view : Model -> Html Event
                        view name =
                            div []
                                [ input [ placeholder "New Name", onInput NewName, value name ] []
                                , button [ onClick Reverse ] [ text "Reverse Name" ]
                                , div [] [ text name ]
                                ]
                    

elm-lang.org

D'autres ressources

Merci à tous

@ThibaudDauce | https://thibaud.dauce.fr