kontakta oss

Detta är den andra delen av min artikel om programmeringsspråket Elm. På den första artikeln Jag fokuserade på huvudfunktionerna som gör Elm till ett intressant alternativ till JavaScript.
Här kommer jag att fokusera på det historiska perspektivet som gör Elm värt en titt, och kommer att gå djupare på språkets två huvudfunktioner: funktionell renhet och statisk typning. Efter det kommer jag att påpeka några bra exempel på vem som använder Elm i produktionen.
Det bästa sättet att förutsäga framtiden är att uppfinna den.
— Alan Kay, designer av programmeringsspråket Smalltalk
Före 2013 följde de flesta front-end-programmeringar mycket tvingande tillvägagångssätt. Ramverk som Backbone eller Angular v1 inspirerade sig själva på model-view-controller-mönstret (MVC) och gjorde mutationen och observationen av vymodellerna till kärnan i deras displaylogik. Att hantera så mycket tillstånd och händelser var svårt och obekvämt för många webbutvecklare, för vilka det enkla dataflödet i deras backend share-nothing web-ramverk fick dem att sucka för gamla dagar då JavaScript och AJAX ännu inte hade tagit över deras värld.
Reagera var det första projektet som skakade detta tvingande korthus. Det mest utmärkande inslaget i detta projekt är den virtuella DOM, som gör det möjligt för programmerare att tänka på sin webbsida som något som effektivt kan beräknas och återges utan stora kostnader.
Sådan effektivitet är det som möjliggör Reacts sätt att modellera front-end: En webbsida består av ett träd av komponenter och varje gång användaren interagerar med dem beräknas hela sidans utseende baserat på det nya tillståndet som lagras i dessa komponenter. Du behöver inte aktivt ändra DOM längre; React tar hand om det åt dig.
Trots att React gjorde det lättare att modellera webbapplikationer föreskrev det inte ett sätt att skilja affärslogiken från renderingslogiken. Facebook föreslog en arkitektur som heter Flux för att lösa detta problem, även om många av de tidigare implementeringarna var mer komplexa än vad som behövdes och tog tid att få dragkraft.
Det var 2015 som Redux dök upp och framkom som en enklare implementering av Flux-arkitekturen. Huvudtanken är att programmets tillstånd ska lagras i ett enda tillståndsträd och att ändringar i detta träd ska modelleras som en reduceringsfunktion. Detta bör i sig vara resultatet av sammansättningen av flera reduceringsfunktioner, var och en ansvarar för en del av applikationens tillstånd, modellerar logiken för att bearbeta varje åtgärd och få en ny version av staten.
Redux är ett enkelt bibliotek med en mycket liten kärna (cirka ett dussin små funktioner). Det är lätt att förstå, trevligt att använda och tillåter användning av coola utvecklingsfunktioner som tidsresande felsökare och omladdning av heta moduler.
Trots enkelheten är dess tillvägagångssätt inte intuitivt och känns främmande för JavaScript. Att skriva reduceringsfunktioner som inte ändrar den tidigare versionen av tillståndet är inte trivialt och det rekommenderas till och med att använda ett bibliotek för att hantera tillståndet på ett oföränderligt sätt. Det är alltså utan någon stor överraskning att Redux författare gjorde det mycket tydligt att sådan arkitektur är starkt inspirerad av Elm.
Mod är att veta vad man inte ska frukta.
— Platon
Om Elms arkitektur lyckades efter att ha blandats med en främmande imperativ teknik som JavaScript, även på bekostnad av att ta bort utvecklare från deras komfortzon, hur trevligt kan det vara om det höll sig borta från ”hermeneutiken” för dynamisk typning och osäkerheten av godtyckliga tillståndsmutationer? Finns det mer att ta från denna lode? Finns det andra hemligheter under Elm?
När ett mjukvaruprojekt startar är all kod vacker, rosa och glänsande. Sedan börjar du möta deadlines, buggar, snabbkorrigeringar, omfattningsändringar, företagssammanslagningar, förvärv och en hord överallokerade utvecklare som ändrar koden medan den ursprungliga författaren är på semester, sjuk eller död. Efter åldrandet bär varje kodrad höjden av sin historia och ofta är ingen där för att berätta.
På dåligt åldrade projekt ljuger variabelnamn, funktionsnamn ljuger, klassnamn ljuger och typnamn ljuger. Men när man använder dynamiskt skrivna språk - som JavaScript - ger bara namn och tester oss information om semantiken i ett program och om hur det kan ändras och förbättras.
Statiskt skrivna språk - å andra sidan - kontrollera projektets semantik och försäkra sig om dess korrekthet. Namnen kan vara fel, men vi vet vilka operationer som matchar vilka typer och kompilatorn kontrollerar automatiskt om våra ändringar är vettiga.
Informationen som tillhandahålls utvecklarna av sådana system är värd tusen namn och dessa system är lättare att ändra och kräver mycket mindre testning eftersom typsystemet undviker flera fel som annars skulle behöva kontrolleras av ett automatiserat test utvecklat av en människa.
Problemet med typer är att de - på de flesta språk - kommer i vägen när man utvecklar ny kod och felsöker eller experimenterar hur koden beter sig. Vanligtvis lägger typer till mycket onödigt brus till det tydliga tal som utvecklare har med maskinen andra utvecklare under kodning.
Med typer tvingas utvecklare också skriva mer - och även om det kanske inte är så dåligt när man använder redigerarens automatiska komplettering - är det en katastrof när man experimenterar i interaktiva miljöer som kommandoraden eller felsökaren. Storheten i att ha koden full av typinformation skapar massor av tröghet och innebär en enorm förlust av smidighet. Att välja mellan statisk och dynamisk typning hamnar alltså som en avvägning mellan Användbarhet och underhåll.
Det är alltså utan överraskning att vi hittar flera initiativ som ger statisk typning in i JavaScript-världen. De mest ökända är Flöde (Facebook), Typeskript (Microsoft) och Pil (Google). Även om dessa inte är ändringar i själva JavaScript-språket, är de antingen översättningar av språket som lägger till skrivning eller liknande språk som direkt konkurrerar med det. Detta bygger mycket press på utvecklare att gå över till ett statiskt typat tillvägagångssätt eftersom verktygen och biblioteken också rör sig på det sättet.
Det finns dock en gemensam trend bland alla dessa tillvägagångssätt: För att undvika den statiska typade bulkigheten har de valt att göra typer valfria. Således - beroende på sammanhanget - är utvecklarna fria att antingen lägga till typinformation i sin kod eller välja att arbeta utan typkontroll - och typsäkerheten som följer med den.
Resultaten är bättre än utan typer, men fortfarande relativt begränsade. Eftersom typerna är gradvisa är det ofta omöjligt att kontrollera om typsignaturerna är vettiga, och mängden verifiering beror starkt på utvecklarens disciplin och på om biblioteken som används har typinformation för samma typsystem.
Elms idéer kommer från den typade funktionella världen, där decennier av utveckling resulterade i användningen av typinferens. Till skillnad från dynamisk eller gradvis skrivning kontrollerar kompilatorn typerna på koden. Men, till skillnad från de flesta statiska typsystem, typinformationen behöver inte uttryckligen anges av programmeraren och härleds av kompilatorn.
Programmeraren kan välja att senare lägga till typsignaturer till sina funktioner, även om dessa typsignaturer skiljer sig från funktionsdefinitionerna. På så sätt blir de inte förvirrande för den som senare läser eller redigerar koden.
Det bör dock noteras att Elm, även om den är inspirerad av funktionella språktypsystem, inte följer sina mest komplexa funktioner. Den antar vad som verkar användbart för front-end-programmerare och håller ett pragmatiskt tillvägagångssätt. Det är som om JavaScript designades om för sin nuvarande användning.
Sann visdom kommer till var och en av oss när vi inser hur lite vi förstår om [...] världen omkring oss.
— Sokrates
Elm är ett rent funktionellt programmeringsspråk. Detta innebär att alla dess uttryck åtnjuter en enkel egenskap som kallas Referensgenomskinlighet som härrör från flera intressanta konsekvenser. Vi fortsätter med att beskriva vad som är Referensgenomskinlighet och sedan undersöka dess konsekvenser.
Ett uttryck eller en funktion sägs vara referentiellt transparent när dess resultat beter sig på ett logiskt sätt. Med andra ord, när det förses med en viss inmatning, kommer ett referentiellt transparent uttryck alltid att utvärderas till samma resultat.
Om vi tänker på det matematiska begreppet -funktionen Vi kanske märker att det verkligen åtnjuter denna egendom. Det är faktiskt ganska svårt att föreställa sig hur det kan vara annorlunda. Funktionen som beräknar ytan på en kvadrat utvärderas alltid till 4 kvadratmeter när den är försedd med en 2-meters ingång och kommer alltid att bete sig som sådan. Det finns inget sätt att skriva en funktion som tar sidan av torget som en enda ingång och får den att returnera olika värden vid olika tidpunkter.
Åtminstone i den matematik som de flesta av oss har tänkt verkar matematiker ha valt sådan abstraktion som ett mycket viktigt - om inte det viktigaste - verktyget för att modellera och resonera om världen. Jag skulle säga att detta inte var någon slump.
Om en funktion alltid returnerar samma resultat kan vi utvärdera och testa den utan att ha något i beräkningen förutom dess ingångar och utgångar. Vi vet exakt vad vi ska tillhandahålla och vad vi kan förvänta oss när vi funderar på att modellera och testa det.
Men Referentiell transparens är inte en verklighet i de flesta programmeringsspråk. Med utvecklingen av digitala datorer valde de flesta programmeringsspråk att modellera världen på ett sätt som liknar hur maskinerna fungerar internt snarare än det som matematiker använde för att modellera världen.
Det gjordes försök att följa den första vägen sedan utvecklingen av de första kompilatorerna. Datorerna vid den tiden var dock inte tillräckligt kraftfulla för att hantera en sådan beräkningsmodell och det maskinliknande sättet att modellera världen blev en inrotad del av vår datavetenskapskultur.
Det maskinliknande sättet att modellera världen (imperativ programmering) är mestadels baserat på ett muterande tillstånd. I den kan beräkningar modelleras genom att läsa och ändra tillståndet för en minnesenhet tills ett slutligt tillstånd beräknas. När funktioner läggs till i den här modellen valde de flesta språk att dela detta tillstånd mellan funktioner och därmed bryta referensgenomskinligheten.
Funktioner beror inte på deras inmatning; deras resultat beror på minnet som de läser och skriver, och de returnerar ofta inget värde, endast tjänar syftet att ändra värdena i det delade tillståndet.
Däremot, i rent funktionell programmering, delas inget tillstånd mellan våra funktioner. Och om inget tillstånd delas upphör det att finnas en anledning att ändra tillståndet för de värden som används. Syftet med våra funktioner slutar handla om att ändra värden och börjar använda dem som ingångar för att beräkna andra värden. I rent funktionell programmering är varje definition oföränderlig.
Elm passar på denna språkfamilj och därmed är alla dess definitioner oföränderliga och alla dess funktioner är referentiellt transparenta.
Enbart rena funktioner är värdelösa. Vi utför beräkningar eftersom vi vill läsa ingångsvärden från den yttre världen och för att vi vill ändra det enligt värdena i våra beräkningar. Den yttre världen är alltså som ett tillstånd som förändras av vårt program i samma mening som minnet av våra imperativa program.
Vissa funktionella programmeringsspråk hittade matematiska sätt att hantera denna fråga elegant i renfunktionell stil och på ett allmänt sätt, men genom att använda några begrepp som har visat sig vara ganska svåra att förstå.
Elm har ett annat tillvägagångssätt. Dess körtid och arkitektur döljer detta problem från oss. Vårt program slutar med att vara en uppsättning funktioner som används för att beräkna vad som ska visas för användaren med en viss sekvens av användaråtgärder eller andra miljöinsatser.
I grund och botten tar Elm-körningen och arkitekturen hand om att interagera med världen inom denna speciella domän, vilket gör det på ett trevligt och enkelt sätt.
Framtiden är inte planerad på ett spår. Det är något som vi kan bestämma, och i den utsträckning vi inte bryter mot några kända lagar i universum kan vi förmodligen få det att fungera som vi vill.
— Alan Kay
Elms ekosystem är ganska omoget och utvecklas långsamt. Men bibliotekets kvalitet är ofta mycket bra och kompilatorn ger oss gott om garantier för deras stabilitet. För närvarande är Elm lämplig för små dynamiska webbsidekomponenter eller för enkla webbsidor som inte kräver rendering på serversidan.
Det finns några viktiga funktioner som bara förväntas komma med följande version (0.19):
Huvudsyftet med denna version är att tillhandahålla ett acceptabelt system för att utveckla komplexa webbapplikationer på en sida.
Att klä upp sig är oundvikligen en ersättning för bra idéer. Det är ingen slump att tekniskt odugliga affärstyper kallas ”kostymer”.
- Paul Graham
Trots sin omogenhet finns det redan några framgångshistorier i branschen:
Sammanhanget är värt 80 IQ-poäng.
- Alan Kay
Elm är starkt inspirerad i Haskell och inspirerar starkt Purescript. Här följer en översikt över vad dessa handlar om:
Haskell är överlägset det språk som påverkade Elm mest. Det är den nuvarande standarden för lata typade programmeringsspråk och utvecklas av en kommitté av akademiker från fältet. De viktigaste skillnaderna från Elm är:
PureScript faller någonstans mellan Haskell och Elm. Båda utvecklas tillsammans och påverkar varandra när de växer. Dess huvudsakliga egenskaper är:
På grund av dess komplexa typsystem tror jag inte att det är möjligt för de flesta JavaScript-programmerare att hoppa in i Purescript. Men dess enkla (och osäkra) interaktion med JavaScript gör det till ett intressant alternativ för människor som kan ha gått igenom Elms eller Haskells trappstenar.
Det finns tre projekt i detta språks ekosystem som försöker ta itu med samma problem som Elm-arkitekturen:
Elm är en intressant front-end-specifik programmeringsmiljö som stöder ett omoget mjukvaruekosystem. På grund av språkdesignen ger detta unga ekosystem atypiskt starka säkerhetsgarantier. Många av dessa härrör från den vänliga kompilatorn som garanterar att det inte finns några körtidsfel.
Det är väldigt trevligt att arbeta med och möjliggör enkel utveckling och refactoring med oöverträffad säkerhet och glädje. Den var utformad för att uppfylla behoven hos en modern JavaScript-programmerare och att vara lätt att komma igång med.
För tillfället är det inte redo att utveckla komplexa webbapplikationer på en sida på grund av bristande rendering på serversidan och några viktiga optimeringar. Nästa utgåva (0.19) förväntas ta itu med dessa problem och även om den inte är klar kanske det inte är en bra idé att använda den för mer än små applikationer eller komponenter.
Det är värt att hålla lite uppmärksamhet på detta projekt som verkar ha potential att bli ett mycket konkurrenskraftigt verktyg.
Vid Imaginärt moln Vi har ett team av experter på mjukvaruutveckling. Om du tror att du kan behöva lite hjälp med ditt digitala projekt, skicka oss en rad här!

Hittade den här artikeln användbar? Du kanske gillar dessa också!

Rails utvecklare med 10+ års erfarenhet av olika tekniker. Jag är intresserad av funktionell programmering.
Människor som läste det här inlägget tyckte också att dessa var intressanta: