Hva er funksjonell programmering?

..

Funksjonell programmering er en disiplin for programmering som gjør det enklere å skrive, forstå og endre kode. I denne teksten introduserer jeg funksjonell programmering, og belyser hvordan tradisjonen for funksjonell programmering har påvirket dagens JavaScript-økosystem for webprogrammering.

Vi følger Eric Normands definisjon av funksjonell programmering1 og skiller mellom:

  1. Data
  2. Beregninger
  3. Handlinger.

Data kan for eksempel være et JSON-objekt. Beregninger er funksjoner fra data til data. Handlinger har en effekt, for eksempel at data blir lagret i databasen, eller en koeffekt, for eksempel at vi henter ut dagens dato (forskjellig hver dag). Effekter er funksjoner fra data “til verden”, og koeffekter er funksjoner “fra verden” til data.

Hvordan har funksjonell programmering påvirket dagens kultur for utvikling av webapplikasjoner? La oss ta et tilbakeblikk.

Da Brendon Eich skulle lage et programmeringsspråk som skulle kjøre rett i nettleseren, ville han først lage en Scheme-dialekt2. Scheme er et funksjonelt programmeringsspråk, og Eich mente at Scheme var godt egnet til å lage interaktive nettsider. Sjefene hans sa at det fikk han ikke lov til! Sjefene hadde hørt om Java, og ville at programmeringsspråket Eich designet skulle likne på Java. Det måtte være lett for Java-utviklere å brukte språket til Eich, sa sjefene. Ellers ville ingen bruke språket til Eich. Eich fikk ti dager, og lagde JavaScript.

Vi fikk så en objektorientert modell for hypertekst-dokumenter med det fine navnet Document Object Model3. Hypertekst-objektmodellen var vanskelig å jobbe med i praksis, så John Resig skrev jQuery4 for å kunne jobbe med hypertekst-dokumenter uten å lage så mange objekter.

Hypertekst-programmering med jQuery var fremdeles tungvindt. Programmereren måtte selv sørge for å holde tilstand i synk med hva som ble vist på skjermen. I tillegg ble sider skrevet med jQuery ofte trege: jQuery oppdaterer hele HTML-dokumentet hver gang brukeren endrer på noe.

Dette hadde Conal Elliot og Paul Hudak et svar på i 1997: Funksjonell-reaktiv programmering (FRP)5. Elliot og Hudak designet et språk (eller en protokoll hvis du vil) for å la effekter reagere på andre effekter. Én effekt kan være at en person trykker på en knapp. En annen effekt kan være at en farge endrer seg fra grønn til grå.

I 2012 lagde Evan Czaplicki programmeringsspråket Elm for å bruke FRP til å lage spill6, og i 2013 lagde Jordan Walke javascript-biblioteket React for å bruke FRP til å lage interaktive webapper7. React-teamet oppfordret først til å lage React-apper i objektorientert stil (React Class Components), før de ombestemte seg, og anbefalte folk å bruke reaktive funksjoner (React Hooks).

Jordan Walke lager i 2016 ReasonML8, et språk for programmering av nettsider som er funksjonelt først, i kontrast til Javascript, som har klasser, objekter og syntaks inspirert av Java. ReasonML er basert på ML9, og andre språk i ML-familien (som Standard ML, OCaml, Haskell og F#).

Hvis vi skal behandle programmering som en seriøs disiplin, må vi forstå hvordan vi kom hit vi er i dag.

Jeg foretrekker å bruke programmeringsspråket Clojure10. Clojure har knallgod støtte for funksjonell programmering og knallgode utviklerverktøy — som Calva for Visual Studio Code, og Clerk for Literate Programming11. Og Clojure er lett12. Det er få ting man må lære, og de få tingene fungerer godt sammen. Syntaksen til språket er minimal. Du får akkurat nok for å snakke godt om data, beregninger og handlinger. Du får ikke med deg bagasje laget for å tilfredsstille en mellomleder som ville overbevise Java-utviklere om å prøve språket fordi Java var i vinden da språket ble skrevet. Hvis du kun har skrevet kode i blokk-orienterte språk med krøllparanteser (som Algol, C, Java, Javascript og Go), krever Clojure-syntaksen tilvenning.

Men du trenger ikke skrive Clojure for å skrive funksjonell kode. Skill mellom beregninger og handlinger i koden din. Funksjoner returnerer enten et svar, eller kjører en sideeffekt. Lag nyhetsbrevet du ønsker å sende ut før du sender det ut. Bruk spørsmålet hvor er mutasjonen? til å dele opp systemet ditt så du kan lager begripelige moduler. Da er det rett fram å teste, og du slipper mocking. Hvis du bruker et funksjonelt tankesett når du skal lage distribuerte systemer, ramler Event Sourcing13 og Command Query Response Segregation14 ut. Plutselig cacher du på content id-er15 i stedet for referanser til muterbare objekter, og caching i distribuerte systemer blir trivielt i stedet for kjempevanskelig.

Min erfaring er at systemer som ikke skiller mellom muterende kode (handlinger) og ikke-muterende kode (beregninger) ender opp i en suppe av mutasjon der utvikling går saktere og saktere og saktere. Funksjonell programmering gir en vei ut16.

Men da må vi sette oss ned og legge ned en innsats for å lære. Rich Hickey skiller i Simple Made Easy mellom ting som er lett og ting som er enkelt.

Git krever innsats for å lære, men gjør det enklere å jobbe sammen med andre utviklere senere.

Hvis vi utelukkende skal gjøre lette ting, kommer vi ingen vei. Vi lærer heller ingenting. Vi lager derimot aktive hindre mot å lære noe som helst. Å lære er tungt arbeid. Det gjør vondt å koble om hjernen vår til å kunne tenke på en annen måte. Hvis det er “lett”, har vi ikke lært noe fundamentalt nytt.

Store språkmodeller (large language models, LLM-er) som GPT-4 tydeliggjør dette skillet. GPT-4 har lest enorme mengder tekst, og klarer å koble sammen kjente ting. GPT-4 klare ikke å finne opp nye ting. Hvis vi som utviklere fortsetter å vektlegge lette ting over enkle ting, kommer vil til å bli automatisert bort.

Så hva bør jeg gjøre, da, Teodor, du får hodet mitt til å gjøre vondt!

Hvis du har én time, hør Eric Normand definere funksjonell programmering:

Hvis du har 10 timer, les Grokking Simplicity. Underveis, se etter data, beregninger og handlinger i kode du har skrevet tidligere.

Hvis du har 100 timer, plukk deg et språk med førsteklasses støtte for funksjonell programmering (for eksempel Racket, Elm, Elixir eller Clojure) og velg deg noe du vil lage. Sett av fire timer til å komme i gang så du finner ut hvor du står fast. Så løfter du de problemene opp til noen som kan språket du prøver å lære deg.

Funksjonell programmering er en disiplin som kommer til å gjøre deg til en permanent bedre utvikler. Det er en ferdighet som gir varig avkastning, uansett om du jobber i et språk med førsteklasses støtte for funksjonell programmering eller ikke.


  1. https://grokkingsimplicity.com/↩︎

  2. https://en.wikipedia.org/wiki/Brendan_Eich#Netscape↩︎

  3. https://en.wikipedia.org/wiki/Document_Object_Model↩︎

  4. https://en.wikipedia.org/wiki/JQuery↩︎

  5. http://conal.net/papers/icfp97/↩︎

  6. https://en.wikipedia.org/wiki/Elm_(programming_language)↩︎

  7. https://en.wikipedia.org/wiki/React_(software)↩︎

  8. https://en.wikipedia.org/wiki/Reason_(programming_language)↩︎

  9. https://en.wikipedia.org/wiki/ML_(programming_language)↩︎

  10. https://clojure.org/↩︎

  11. https://clerk.vision/↩︎

  12. https://clojureverse.org/t/clojure-has-a-dirty-little-secret/9160↩︎

  13. https://martinfowler.com/eaaDev/EventSourcing.html↩︎

  14. https://martinfowler.com/bliki/CQRS.html↩︎

  15. https://en.wikipedia.org/wiki/Content-addressable_storage↩︎

  16. https://curtclifton.net/papers/MoseleyMarks06a.pdf↩︎