APPLYING FUNCTIONAL REACTIVE PROGRAMMING TO WRITE … · APPLYING FUNCTIONAL REACTIVE PROGRAMMING...

Post on 01-Oct-2020

16 views 0 download

Transcript of APPLYING FUNCTIONAL REACTIVE PROGRAMMING TO WRITE … · APPLYING FUNCTIONAL REACTIVE PROGRAMMING...

APPLYINGFUNCTIONALREACTIVEPROGRAMMINGTOWRITEDYNAMICSERVER

BASEDWEB-APPLICATIONS-

ConnectingSinglePageApplicationstotheBackendwithoutMessandMayhem

-

HackITZ,November2016

Dr.ThomasSchankVersion1.0.0

Motivation1-Cider-CIperiodicallypullpage(!)andreplace

Knownaspjaxpjax=pushState+ajax

"pushState"⇒pulling

pjaxworksbygrabbinghtmlfromyourserverviaajaxandreplacingthecontentofacontaineron

yourpagewiththeajax'dhtml

pjaxpro/conssimple,verylittleJavaScript

extendsserversiderendering

notsuitableforcomplexfrontend

frequentpullingcausesloadandtraffic

timelags

Goals1

maintainstateontheserver,

andpushitfromtheretothebrowserondemand

Motivation2-OO/MVCStyleinPivotal

⇒Reactwonthelpyouifyoumessupmanagingstate

DataBindingsandConnectingComponents

DataBindingsandConnectingComponents

DataBindingsandConnectingComponents

DataBindingsandConnectingComponents

Goal2

ensureconsistencyofstateeverywherebackend,frontend,components,…

Motivation3-Segregation

Thereisanunnaturalandunnecessarydividebetweenback-andfrontend.ThegapinMadekv3isnowbiggerasithaseverbeenbefore.

Thereisanunnaturalandunnecessarydividebetweenback-andfrontend.ThegapinMadekv3isnowbiggerasithaseverbeenbefore.

RailsandotherMVCFrameworks:conventionoverconfiguration

breaksdownwhenthingsgetcomplex

Thereisanunnaturalandunnecessarydividebetweenback-andfrontend.ThegapinMadekv3isnowbiggerasithaseverbeenbefore.

RailsandotherMVCFrameworks:conventionoverconfiguration

breaksdownwhenthingsgetcomplex

"Backend":LotsofRails+ARhackstowritecomplexSQLqueries.

Middle-Layer:lotsofcode(presentersetc.)ifyouwantrealseparation(asinMVC)

Frontend:(C)JSXsomeReactgoodness

XML/HTMLhardtoread

Templates

React = require('react')ReactDOM = require('react-dom')RailsForm = require('../lib/forms/rails-form.cjsx')

module.exports = React.createClass displayName: 'HeaderButton'

_onClick: (event) -> event.preventDefault() if @props.onAction @props.onAction(@props.asyncAction) return false

render: ({authToken, href, method, icon, title, name} = @props) -> method = 'post' if not method icon = 'icon-' + icon onClick = if @props.onAction and @props.asyncAction then @_onClick else null <RailsForm className='button_to' name='' method={method} action={href} authToken={authToken}> <button className="button" type="submit" title={title} onClick={onClick}> <i className={icon}></i> </button> {@props.children} </RailsForm>

Frontend:(C)JSX

TheDOM"isatree"!Encodeitessuchandyougetfullcode-andcomposability.

someReactgoodness

XML/HTMLhardtoread

Templates

React = require('react')ReactDOM = require('react-dom')RailsForm = require('../lib/forms/rails-form.cjsx')

module.exports = React.createClass displayName: 'HeaderButton'

_onClick: (event) -> event.preventDefault() if @props.onAction @props.onAction(@props.asyncAction) return false

render: ({authToken, href, method, icon, title, name} = @props) -> method = 'post' if not method icon = 'icon-' + icon onClick = if @props.onAction and @props.asyncAction then @_onClick else null <RailsForm className='button_to' name='' method={method} action={href} authToken={authToken}> <button className="button" type="submit" title={title} onClick={onClick}> <i className={icon}></i> </button> {@props.children} </RailsForm>

Goal3

uniformityclosethegapbetweenbackendandfrontend

CoreProblem-Remedy-Roadmap

TheCoreProblemmanagingstateovertimeandindifferentplaces

ComingUpcompletelydifferentapproach

effective

veryefficient

impossibletocreatebugslikeseen

awesomedeveloperexperience

Roadmap1. basics

2. singlepageapplications

3. SPA+backend

4. consequencestodevelopers&architecture

OnefurtherGoalInterestYOUforthestuff.

Catchattachedtoaparticulartechnology:

Clojure+ClojureScript

FunctionalReactiveProgramming

Elliott,Conal;Hudak,Paul(1997),"FunctionalReactiveAnimation"

Thecombinationoffunctionalprogramming,andreactiveprogramming.

Elliott,Conal;Hudak,Paul(1997),"FunctionalReactiveAnimation"

What?

Thecombinationoffunctionalprogramming,andreactiveprogramming.

Thebasicideabehindreactiveprogrammingisthattherearecertaindatatypesthatrepresentavalue"overtime".Computationsthatinvolvethesechanging-over-timevalueswillthemselveshave

valuesthatchangeovertime.

SpreadsheetProgramming

StoringStatewithAtoms

increaseanddecreaseexample: (def ^:dynamic db {:a 0 :b 0})

(doseq [_ (range 0 1000)] (def db {:a (inc (:a db)) :b (dec (:b db))}))

; (= db {:a 1000 :b -1000})

1234567

increaseanddecreaseexample:

withthreads

ooooops

(def ^:dynamic db {:a 0 :b 0})

(doseq [_ (range 0 1000)] (def db {:a (inc (:a db)) :b (dec (:b db))}))

; (= db {:a 1000 :b -1000})

1234567

(def ^:dynamic db {:a 0 :b 0})

(doseq [_ (range 0 1000)] (future (def db {:a (inc (:a db)) :b (dec (:b db))})))

; .e.g. (= db {:a 598, :b -666})

12345678

increaseanddecreaseexample:

withthreads

ooooopsTheabsenceofthreadsdoesnotsolvethestateproblem,itmakesitevenharder.

(def ^:dynamic db {:a 0 :b 0})

(doseq [_ (range 0 1000)] (def db {:a (inc (:a db)) :b (dec (:b db))}))

; (= db {:a 1000 :b -1000})

1234567

(def ^:dynamic db {:a 0 :b 0})

(doseq [_ (range 0 1000)] (future (def db {:a (inc (:a db)) :b (dec (:b db))})))

; .e.g. (= db {:a 598, :b -666})

12345678

TheAtom (def db (atom {:a 0 :b 0})) (doseq [_ (range 0 1000)] (future (swap! db (fn [current] {:a (inc (:a current)) :b (dec (:b current))}))))

; (= @db {:a 1000, :b -1000})

123456789

10

Atomsprovideawaytomanageshared,synchronous,independentstate.TheintendeduseofatomistoholdoneofClojure’simmutabledata

structures.

TheAtomcont.

Interestingnolockingtransactions,MVCC

Extremelyuseful

supportvalidators⇒schema

watchable

ReactiveProgramming-Atoms-Reagent

AtomsandReactiveProgrammingimagine:atom≅cellofaspreadsheet

(def a1 (atom 5)) (def a2 (atom 7)) (def a3 (reaction (+ @a1 @a2)))

123

AtomsandReactiveProgrammingimagine:atom≅cellofaspreadsheet

a3isanatomvalueofa1ora2change⇒a3willgetupdated[^lazy][^reaction]evaluationcanbeeagerorlazy,dependingontheenvironmentandlibrary

(def a1 (atom 5)) (def a2 (atom 7)) (def a3 (reaction (+ @a1 @a2)))

123

-

"MinimalisticReactforClojureScript"see

"ManagingstateinReagent"

Reagent

SinglePageApplications

Weconsiderawebappwithoutdataexchangetoorfromtheserverfornow.

Single-PageApplications(SPAs)areWebappsthatloadasingleHTMLpageanddynamicallyupdatethatpageastheuserinteractswiththeapp...withoutconstantpagereloads.(ASP.NET)

re-frameisapatternforwritingSPAsinClojureScript,usingReagent.

re-frame

"It'sMVC,Jim,butnotasweknowit".(re-frame)

re-frameisapatternforwritingSPAsinClojureScript,usingReagent.

Honestly,itisnotMVC!

Youwillfindthepatternsusedinre-frameinothertalks,libraries,frameworks.Itisallovertheplace.

Youshouldreadthere-framedocumentation.Itiswittyinallofitsmeanings.

re-frame

"It'sMVC,Jim,butnotasweknowit".(re-frame)

re-framekeyfeaturesOneandonlyonedatabase!

DataflowsfromthedatabasetotheDOM.

Eventscausethedatabasetochange.

EventsnevermanipulatetheDOMdirectly.

noshortcuts!

OneDatabase?Technically,youcanhavemultipledatabases.

Theirsignalgraphmustformanacyclicdirectedgraph.

Makesureyoudon'tshortcut.TheDomisalways"thesink".

Donotcomplicatethingsunnecessarily⇒justuseonedatabase!

OneDatabase?Technically,youcanhavemultipledatabases.

Theirsignalgraphmustformanacyclicdirectedgraph.

Makesureyoudon'tshortcut.TheDomisalways"thesink".

Donotcomplicatethingsunnecessarily⇒justuseonedatabase!Theserulesarelessoutofatechnicalnecessity.Theyhelpustoavoidunnecessarycomplexityandfocusonthefeatures.

DefineaSchemaandValidate! (ns cider-ci.repository.fetch-and-update.db-schema (:require [schema.core :as schema])) (def schema {:last_fetched_at (schema/maybe org.joda.time.DateTime) :last_error (schema/maybe String) :last_error_at (schema/maybe org.joda.time.DateTime) :updated_at org.joda.time.DateTime :state (schema/enum "error" "fetching" "initializing" "ok" "waiting")

:pending? Boolean })

123456789

10

DefineaSchemaandValidate!

e.g.useitlikethis

worksuniformlyinClojureandClojureScript.

(ns cider-ci.repository.fetch-and-update.db-schema (:require [schema.core :as schema])) (def schema {:last_fetched_at (schema/maybe org.joda.time.DateTime) :last_error (schema/maybe String) :last_error_at (schema/maybe org.joda.time.DateTime) :updated_at org.joda.time.DateTime :state (schema/enum "error" "fetching" "initializing" "ok" "waiting")

:pending? Boolean })

123456789

10

(def fetch-and-update-db (atom {:last_fetched_at nil :last_error nil :last_error_at nil :updated_at (time/now) :pending? true :state "initializing" } :validator #(schema/validate schema %)))

12345678

plumatic/schema

SPAsinteractingwiththeServerAtleastapartoftheroutesareSPAs.

Updatedstateontheserverneedstobereflectedontheclient.

⇒extendingthere-frameconcept

Butthisisnot"webscale"

No,butonhowmanycoresdoesyourapplicationrunrightnow?

PushforthechannelServer→ClientprobablyWebSocketspushdiffs!

Wepushthestateinthespiritofreactiveprogramming.

nothingelse,noRPCstyle,nothing!

⇒WebSocketsvia seemtoworkratherwellptaoussanis/sente

RESTfortheChannelClient→ServerWecanusethesameroutesfortheAPIandthefrontend!

willsaveyouatonofwork

enablesacertainkindofarchitecture

WedoNotSyncTwo(n-)waysyncingdataisveryhard/expensivetoimplement.Sowe

justdonotdoit.

Benefits-DeveloperExperience-Architecture

♻UniformProgrammingClojure+ClojureScript

Ourprimarygoalistoimplementfeatures;nottowriteHTML,React,SQL,ActiveRecord,…

Traditionalframeworksfosterseparationbytechnologyandoverheadincommunication.

samecodeontheserverandclient(almost)

itworks,actuallyitisawesome!

e.g.durationparserandvalidatorinCider-CI

UniformStructuresItisalljustdata-treesmostly.

DOM ,

SQL

Lisp'shomoiconicityreallyflieshere!

weavejester/hiccup reagent

kk/honeysql

ClojureScriptProgrammingExperience

sourcemaps

interactiveprogrammingwith

Demo?

ItisreallybetterthanwritingpureJavaScript!

bhauman/lein-figwheel

ArchitectureMostapplicationhaveascrumdriven(i.e.nonatall)architecture.

Onthenextlevelthearchitecturesaremostlytechnologydriven.

Weshouldincludethefeaturesanddemandsinourarchitectures.

FeatureDrivenArchitecture

Cider-CIArchitectureRefactoring

⇒cheaperandeasierchangesandrefactorings

FinalWords

Whyshouldyoucare?JavaScripthastomanygotchasasageneralplatformontheserver.

Ruby(onRails),PHP,Python,…,willneverruninthebrowserforreal.Theyhavealsotoomanyweaknessesontheserver.

Whyshouldyoucare?JavaScripthastomanygotchasasageneralplatformontheserver.

Ruby(onRails),PHP,Python,…,willneverruninthebrowserforreal.Theyhavealsotoomanyweaknessesontheserver.

Imho,wehavetomoveandthefuturewillbeeither:

TheenterprisestackAngular2/3+servertechnologyX,orthedistinguishablealternativeClojure+ClojureScript.

Whatdoyouchoose?

THEENDThankyou!