Översikt
Efter många veckor av programmerande i Node-plattformen är det nu dags att börja titta på hur du kan ta dina program till webben! Veckans två artiklar går igenom hur webbläsaren skiljer sig från Node, hur du bör ladda in dina skript och vad webbkomponenter är, grunden för resten av kursen. Information om veckans upplägg annonseras löpande i kursens Zulip-kanal.
Veckostart med webbläsaren
Section titled “Veckostart med webbläsaren”Tisdagen i kursvecka 8 handlade om steget från Node.js till webbläsaren: veckans två nya artiklar,
hur skript laddas och varför kursen bygger på webbkomponenter i stället för ett ramverk. Mikael
byggde sedan ett Hello World-projekt för webbläsaren från grunden, med package.json, Vite och
webbläsarens utvecklingsverktyg. Passet avslutades med frågor om versionsnummer, den muntliga
examinationen av A3 och enhetstester inför torsdagen.
Om passet
Section titled “Om passet”Tisdagens pass i kursvecka 8 hölls av Mats och Mikael tillsammans. Mats gick igenom veckans
översikt och de två nya artiklarna, som ersätter inspelningarna som primärt material, och varför
kursen bygger på webbkomponenter i stället för ett ramverk. Därefter byggde Mikael ett Hello
World-projekt för webbläsaren från grunden: mappstruktur, HTML, package.json, Vite och
utvecklingsverktygen i webbläsaren. Passet avslutades med frågor från chatten om versionsnummer, den
muntliga examinationen av A3 och önskemål om enhetstester till torsdagen.
En ny körmiljö
Section titled “En ny körmiljö”Hittills har koden körts i Node.js, en kontrollerad miljö med en enda JavaScript-motor. Nu flyttar kursen in i webbläsaren, och där finns det många att välja på: Chrome, Firefox, Edge, Safari, Chromium och fler därtill. Under huven delar flera av dem motor. Chrome och Edge använder båda V8, samma JavaScript-motor som Node.js, medan Firefox har SpiderMonkey och Safari JavaScriptCore. Det spelar inte lika stor roll som det gjorde en gång i tiden, men det påverkar fortfarande hur du behöver förhålla dig till miljön.
Mikael minns hur det var när han började med JavaScript runt 2011–2012. Då fanns knappt några standarder, och skillnaderna mellan webbläsarna var ett stort problem. I dag är det inte lika allvarligt, men skulle han bygga en applikation för mobiler, läsplattor och datorer skulle han ändå sätta upp en testmiljö mot flera webbläsare. Han skulle inte svära på att något fungerar överallt utan att ha provat.
Artiklar i stället för nya inspelningar
Section titled “Artiklar i stället för nya inspelningar”Veckans inspelningar har några år på nacken, och mycket har hänt sedan dess. I stället för att spela in dem på nytt har Mats skrivit två artiklar: Webbläsaren som körmiljö och Webbkomponenter – en introduktion. Läs dem i den ordningen. De gamla inspelningarna finns kvar under Äldre inspelningar för den som ändå vill se dem, men de innehåller delvis inaktuellt material.
Artiklarna varvar teori med små frågor att fundera över, med lösningen dold tills du har tänkt efter, till exempel vad som fungerar i både Node.js och webbläsaren. Mikael, som har sett de gamla inspelningarna, tycker att artiklarna fungerar bra som läromedel. Även för honom är innehållet viktig bakgrundskunskap som är lätt att glömma bort.
Douglas Crockford och de bra delarna
Section titled “Douglas Crockford och de bra delarna”En av artikelns informationsrutor handlar om Douglas Crockford, som har haft stor betydelse för JavaScript och för att språket blev populärt. Mats berättar att han en gång hade en bok om JavaScript på närmare tusen sidor. Crockford tyckte att någon borde skriva om de bra delarna i språket, och resultatet blev den betydligt tunnare JavaScript: The Good Parts. Crockford gjorde också JSON känt, något du stöter på längre fram i kursen.
JavaScript skapades på väldigt kort tid, och en del designbeslut kan betraktas som rena misstag, som också går att missbruka. Ska en bok beskriva allt du kan göra blir den tjock. Ska den bara beskriva hur du bör göra blir den tunn. Mats jämför med en gammal spis: att du står vid den betyder inte att du ska lägga handen på den varma plattan. Mikael tillägger att han ibland har svårt för när folk skämtar om programmeringsspråk. Det kan ge nya användare intrycket att språket är konstigt, när det egentligen handlar om att använda det på fel sätt.
Hur skript laddas
Section titled “Hur skript laddas”Artikeln går igenom webbläsarens beståndsdelar, hur HTML blir till pixlar och hur skript laddas,
något som har förändrats mycket genom åren. I kursen används uteslutande <script type="module">,
men det är bra att förstå vad som händer med renderingen av en sida så fort du använder en
<script>-tagg. När du har läst avsnittet ska du kunna lista ut i vilken ordning bokstäverna A, B
och C skrivs ut i artikelns fråga.
Rekommendationen i dag är att ladda in applikationen som en modul i <head> och låta den modulen
importera det den behöver. Det räcker med ett <script>-element. Mats ser spår av det framför allt
i examinationsuppgift B3. Mikael tänker på alla sina gamla exempelprogram där skriptet ligger längst
ner, eller där sidan läser in åtta JavaScript-filer. Mats understryker att det är just en
rekommendation, ingen absolut lag, och att den gäller i dag. Imorgon kan standarden och synen på
saker se annorlunda ut, och det går att få det att fungera på andra sätt också. Mikael tycker om
upplägget: du ser direkt att sidan inkluderar ett huvudprogram, och i det känner du igen den
JavaScript-kod du har skrivit hittills.
Webbkomponenter, inte ett ramverk
Section titled “Webbkomponenter, inte ett ramverk”Den andra artikeln är en kort introduktion till webbkomponenter, som är det resten av kursen bygger
på. När någon tidigare frågade om kursen kommer att ta upp React eller Vue är svaret alltså
webbkomponenter. Det är ett samlingsnamn för flera tekniker: custom elements, shadow DOM, HTML
templates och ES-moduler. Artikelns första, starkt förenklade element innehåller sådant du känner
igen, som class och extends. Webbkomponenter bygger på arv. Artikeln beskriver också vad som har
hänt sedan inspelningarna gjordes, till exempel deklarativ shadow DOM, formulärkopplade element och
delade stilmallar. Hur mycket av det som tas upp i kursen återstår att se.
Varför standarden och inte ett ramverk? För att det är webbstandard, och Mats skulle göra samma val om han byggde kursen från grunden i dag. Den största vinsten är strukturen. Kursen har använt webbkomponenter länge, men i de föregångarkurser som inte gjorde det blev det spagettikod så fort applikationerna växte. Med komponenter får du en komponentbaserad arkitektur. Populära ramverk kan med tiden bli de facto-standarder, och ramverk som React, Vue och Angular har i sin tur närmat sig webbkomponenterna.
Mikael känner igen stökigheten från de äldre kurserna: JavaScript-kod som uppdaterar användargränssnittet, händelser, routing och mycket annat blir snabbt rörigt, och webbkomponenter är ett av många svar på det. Han vet att platsannonserna kanske efterfrågar React, men är bekväm med valet. Standarden rör sig långsammare än ramverken, men den rör sig framåt, och ser han tillbaka har standard-JavaScript sakta men säkert ätit upp behovet av ramverk. Därför är standardsidan bra att undervisa på: den är stabil och växer hela tiden.
Vägen fram till B3
Section titled “Vägen fram till B3”Kursen går mot kursvecka 20, då det är deadline och muntlig examination för B3, där du bygger ett eget skrivbord med hjälp av webbkomponenter. Innan dess behöver en del grunder bockas av, och den här veckan handlar om att läsa in sig. Samtidigt pågår A3, som till stor del kodas i den gamla miljön, Node.js. Mats ser det som ett bra avbrott: du kan inte knacka kod hela dagarna, och artiklarna om webbläsaren passar att varva med arbetet på A3. Inga frågor om A3 hade kommit in än, och Mikael tror att det snart är dags för dem att börja dyka upp.
Det som är centralt men inte hör till den här veckan är att börja arbeta med HTML-elementen från koden. Det kommer nästa vecka, med en ny gammal övningsuppgift, Tiny Tunes, där du kommunicerar med element och påverkar dem med JavaScript.
Övningsuppgiften och utvecklingsmiljön
Section titled “Övningsuppgiften och utvecklingsmiljön”Veckans övningsuppgift, Hello World Again, är inte teoretiskt tung. Den handlar om att bekanta dig med utvecklingsmiljön nu när webbläsaren är inblandad. Till uppgiften finns ett inspelat lösningsförslag, men sedan det spelades in har Visual Studio Code fått en enklare och bättre integration för att felsöka kod som körs i webbläsaren. Inspelningen visar det klassiska sättet, där allt görs i webbläsarens utvecklingsverktyg, vilket fortfarande fungerar. Mats var osäker på om projektet är konfigurerat för felsökning i Visual Studio Code och ska se över det.
Det behövs en webbserver
Section titled “Det behövs en webbserver”En fråga i chatten var om kursen kommer att använda Live Server, ett tillägg till Visual Studio
Code som en del har använt i kursen i webbteknik. Det nya från och med den här veckan är att det
måste finnas en server som tillhandahåller filerna när koden körs i en webbläsare. Kursen har sedan
några år använt Vite, efter Snowpack och flera andra genom åren, och alla
projekt är förberedda för det. Vill du använda något annat är det fritt fram. I praktiken startar du
servern i terminalen med npm run dev. Samma verktyg kan sedan bygga projektet när det ska
publiceras.
En student förtydligade senare att Live Server startas från Visual Studio Code men öppnar sidan i den vanliga webbläsaren, så du har samma utvecklingsverktyg där.
Hello World från grunden
Section titled “Hello World från grunden”I övningsuppgifterna får du ett färdigt projekt, men Mikael ville visa vad alla stegen dit
egentligen är. Han följde en egen, mindre övning,
exercise-hello-world-browser:
ett projekt som bara skriver ut Hello World i konsolen från en webbsida. Han forkade repot, klonade
sin fork och kontrollerade versionerna med node --version och npm --version.
Strukturen. Mikael skapade mappstrukturen i terminalen (i bash, där touch skapar en tom fil,
till skillnad från PowerShell) och kontrollerade resultatet med tree:
public/├── index.html├── css/│ └── style.css└── js/ └── main.jsVarför public? Mikael är van vid det från många projekt. Det är webbroten, där webbservern
startar, och de statiska filerna ligger där även i ett så litet projekt. Han påpekade också att
projekten längre fram kommer att organiseras på andra sätt, med mer JavaScript-kod som inte bara
ligger under public. I Hello World Again ligger koden till exempel i src/.
HTML-sidan. Sidan är en så liten korrekt HTML-sida som möjligt, med en <link> till CSS-filen
och <script type="module" src="js/main.js"> i <head>. Mats hittade en detalj: dokumentet hade
lang="sv", men rubriken Exercise Hello World in Browser är på engelska. En petitess i det här
sammanhanget, men ibland är det viktigt.
Mats tog också upp sökvägarna i href och src. Borde det stå ./css/style.css i stället för
css/style.css? I det här exemplet spelar det ingen roll, men i andra fall kan det göra det.
Mikael beskrev sedan flödet: webbläsaren hämtar index.html, tolkar den, hittar resurserna som
ska hämtas och hämtar dem. Han gissade att JavaScript-programmet får starta först när alla sidans
resurser är hämtade. Mats svarade att du får det korrekta svaret genom att läsa veckans artikel.
Startfilens namn. Mats påpekade att main.js bara är ett av många namn. Hittills i kursen har
startfilen hetat app.js, artikeln använder index.js (som hör ihop med index.html) och i
serverprogrammeringen kommer den att heta server.js. Filen kan heta precis vad som helst, så länge
index.html pekar ut den. Namnen är rutin, inget tvång. Poängen, säger Mikael, är att du som
programmerare snabbt hittar var programmet startar.
package.json. Med npm init -y skapade Mikael en package.json. Vad det blir för något var
de inte helt överens om. Mikael säger npm-projekt, en student föreslog Node-projekt, och Mats
konstaterade att package.json används av flera pakethanterare, som pnpm, Bun och Deno. Mikael
upptäckte att npm init hade lagt in "type": "commonjs", och bytte till "type": "module". Det
är en förutsättning för att använda import och export. Annars är du hänvisad till det gamla
modulsystemet, som kursen har lämnat.
Vite. Mikael lade till skriptet "dev": "vite public", så att Vite startar med public som
rotmapp, och installerade Vite som utvecklingsberoende:
npm install --save-dev viteEtt utvecklingsberoende är ett verktyg som bara behövs under utvecklingen, inte för att köra
projektet när det driftsätts. Installationen skapade mappen node_modules, med förvånansvärt många
paket för ett så litet verktyg, lade till vite under devDependencies i package.json och
skapade package-lock.json, som anger exakt vilka paket och versioner som är installerade.
node_modules ska inte checkas in, eftersom den genereras vid varje installation och den som klonar
repot annars skulle behöva radera den direkt. Därför lade Mikael till den i .gitignore. I de
färdiga projekten är allt detta redan gjort och du kör bara npm install.
I webbläsaren. npm run dev startade Vite på http://localhost:5173. Mikael öppnade adressen i
sin vanliga webbläsare och utvecklingsverktygen via Inspect. Där syns lite mer än i den råa
webbsidan, eftersom Vite injicerar en del i utvecklingsläge. I fliken Console fanns utskriften
från main.js, och via View Page Source kan du se exakt vilken kod webbläsaren har läst in, ett
av många sätt att felsöka. När Mikael ändrade utskriften i main.js, bakgrundsfärgen i CSS-filen
eller rubriken i HTML-filen och sparade laddade Vite om sidan automatiskt.
Av gammal vana tittar Mikael ibland i fliken Network för att se om resurserna är cachade, och tvingar då fram en omladdning med Ctrl+Shift+R. Mats påpekar att det behövdes för några år sedan, men att verktygen numera sköter det. Hans eget tips: kör i inkognitoläge, eftersom webbläsartillägg annars kan fylla konsolen med felmeddelanden.
Vad körs var? En fråga i chatten var om koden verkligen körs i webbläsaren, när Hello World
syns i konsolen och inte på sidan. Den gör det, svarar Mikael. Webbläsaren hämtar allt och
exekverar det. Mats reder ut de två delarna: rubriken på sidan kommer från HTML-filen, medan det som
skrivs ut i konsolen bestäms av JavaScript-filen, som körs av webbläsaren. console.log skriver
till webbläsarens konsolfönster.
I konsolen kan du också skriva kod direkt. När Mikael körde console.log där visades även
funktionens returvärde, undefined, något du inte har sett när du kört program i Node.js.
Nästa steg. Nu skulle Mikael kunna lägga sin Dice-klass i en egen fil, exportera den,
importera den i main.js, skapa ett objekt, rulla tärningen och skriva ut resultatet i konsolen.
Det är också övningens utmaning. Mats spänner bågen högre: varför inte visa tärningen som HTML,
när du har en hel webbläsare att leka med? Det får vänta en vecka eller två. Mikael ser ett sådant
litet projekt som en lekplats för egna små exempelprogram.
Frågor från chatten
Section titled “Frågor från chatten”TypeScript och "type": "module". En student påpekade att TypeScript kräver att projektet är
inställt på moduler. Med CommonJS får du ett felmeddelande som uppmanar dig att antingen importera
på ett annat sätt eller byta till moduler.
Går det att låsa ett paket till en viss version? Ja. Mats förklarar att "^8.3.4" betyder att
alla versioner inom version 8 från och med 8.3.4 godkänns, till exempel 8.3.5 och 8.99.3, men inte
9.0.0. Tar du bort taket (^) krävs exakt 8.3.4. Mikael förklarar logiken: när den första siffran
ändras är det en major release, som inte behöver vara bakåtkompatibel och kan kräva att du ändrar
din kod. De två andra siffrorna står för nya funktioner och rättningar, som ska vara
bakåtkompatibla. Det kallas semantisk versionshantering (semver), och kursen återkommer till det.
Inför torsdagen: enhetstester
Section titled “Inför torsdagen: enhetstester”En student önskade att torsdagen skulle ta upp hur du skriver egna enhetstester. I A3 finns inga tester alls, utan manuell testning krävs, och då kanske du vill komplettera med egna. För några år sedan hade Mats avrått från att skriva massor av tester så här tidigt i utbildningen, eftersom det kan vara lurigt. Det är det fortfarande, men i dag går det att göra på ett annat sätt, med lite assistans.
Att det saknas tester i A3 är ett avsiktligt hål. Problemet med att dela ut tester till examinationsuppgifter är att de avslöjar för mycket av designen och lösningen. A2 är faktiskt det enda stället i hela utbildningen där du får så rikligt med tester. Behöver du tester i kommande kurser får du skriva dem själv. Mats val av verktyg är redan gjort: Vitest, samma som han använder för all annan JavaScript- och TypeScript-kod. Han funderar på att skriva tester till kod som redan finns i A3. Det är inget krav, men det kan vara lämpligt att ta upp i samband med A3. Mikael ska fundera på om det finns delar av A3 som är värda att titta närmare på.
Den muntliga examinationen av A3
Section titled “Den muntliga examinationen av A3”En tidig fråga i chatten gällde den muntliga examinationen av A3. Under Om examination på kursens webbplats finns en inspelning där en betydligt yngre Mats förhör en lika ung Daniel på sitt kontor, och visar hur det går till. Den är från campus, men förfarandet är detsamma på distans. Skillnaden är bara geografisk. Enligt uppgiftsbeskrivningen berör frågorna kursvecka 1–7, och har du genomfört A3 står du väl rustad. Kan du navigera i din kod klarar du det strålande, säger Mikael.
Mats tycker att muntlig examination är ärligare. Det är lättare att anpassa frågorna till studenten: att ställa frågor för högsta betyg till någon som knappt når godkänt är meningslöst. Då skiftar fokus till de frågor du måste kunna svara på för att bli godkänd. Det är lättare att ge ledtrådar, och det blir mer en diskussion än ett förhör.
Deadline är tisdag 3 november kl. 17.00. Det är vanligt när en uppgift följs av ett muntligt förhör, eftersom Mats då har onsdagen på sig att planera, och förhören hålls torsdag 5 och fredag 6 november. Du bokar själv tid på kursens Moodle-sida, där Mats lägger ut tiderna. Han portionerar ut dem, med torsdag förmiddag först och fler tider när de fylls, eftersom långt ifrån alla väljer att gå upp. Det finns ingen automatik som hindrar dig från att boka innan du har lämnat in, men du ska minst ha skapat en merge request först. Har du bokat en tid utan merge request stryker Mats den, utan att meddela dig.
Torsdag med tester och A3
Section titled “Torsdag med tester och A3”Torsdagen i kursvecka 8 började med tisdagens önskemål om enhetstester. Mats presenterade artikeln
Att testa din kod och lade till Vitest och ett första test i A3-mallen. Därefter visade Mikael
hur han provkör sin egen A3-lösning, hur flödet i app.js kan se ut och vilka metoder som brukar
ge flest diskussioner vid redovisningen.
Om passet
Section titled “Om passet”Torsdagens pass i kursvecka 8 hölls av Mats och Mikael tillsammans. Första halvan svarade på
tisdagens önskemål om enhetstester: Mats presenterade artikeln Att testa din kod och visade hur du
lägger till Vitest och ett första test i A3-mallen. Andra halvan ägnade Mikael åt A3, med sin egen
lösning som utgångspunkt: felfallen vid uppstart, flödet i app.js och de metoder där lösningarna
brukar skilja sig mest åt.
Från en fråga till en artikel
Section titled “Från en fråga till en artikel”Tisdagens sista fråga gällde hur du skriver egna tester, och den har resulterat i en artikel, Att testa din kod, som ligger i kursvecka 7 eftersom den hänger ihop med A3. Någon inspelning finns inte än. Mats funderar på att komplettera den här typen av artiklar med korta inspelningar, kanske tre till fem minuter långa, som demonstrerar det som beskrivs.
Bakgrunden är densamma som i tisdags. I A2 fick du över 170 automatiska tester, i A3 får du inga
alls, och det är ett medvetet upplägg. Men i REFLECTION.md ska du svara på några frågor om hur du
har testat din lösning, och där är artikeln tänkt som en introduktion till att testa på ett mer
strukturerat sätt. Det är artikelns första steg, det manuella, som är det intressanta i den här
kursen. Automatiska tester ligger utanför kursen, och i årskurs två läser du en hel kurs om
enhetstester, integrationstester och end-to-end-tester.
Manuellt, halvautomatiskt, automatiskt
Section titled “Manuellt, halvautomatiskt, automatiskt”Alla som har gjort övningsuppgifterna har redan testat sin kod. Det är det Mikael gör med sina
console.log: han kör några satser, skriver ut resultatet och konstaterar att det stämmer med det
förväntade. Det är manuell testning, och där börjar artikeln.
A3-mallens app.js innehåller redan ett sådant manuellt test. Den skapar en kortlek, skriver ut
den, blandar den och skriver ut den igen. Mats körde det med npm start och kunde se att kortleken
hade blivit blandad, men att det verkligen är 52 kort och inga dubbletter orkade han inte
kontrollera. Det är svagheten: det är du som måste läsa och jämföra varje gång.
Steget därefter är att låta koden kontrollera sig själv. JavaScript har ingen inbyggd assert, men
console.assert() skriver ut ett meddelande när ett villkor inte är uppfyllt. I Node.js finns
modulen node:assert, som i stället stoppar programmet med ett undantag. Då slipper du läsa och
titta själv.
Det sista steget är ett testramverk. I A2 var det Vitest, från samma utvecklare som Vite, och det är
det verktyg som gäller i dag. A3 har inget spår av det, så du installerar det själv med
npm install --save-dev vitest och lägger till två skript i package.json.
Var ska testerna ligga?
Section titled “Var ska testerna ligga?”Det finns två skolor. För ett år sedan hade Mikael lagt testerna i en separat katalog, i dag hade han nog lagt dem bredvid källkodsfilen. Mats har gjort samma resa. Ett enhetstest testar bara en fil, så det är naturligt att det ligger intill den. Testar du flera klasser tillsammans är det ett integrationstest, och testar du hela applikationen ett end-to-end-test.
Tillsammans bildar de en pyramid, med flest enhetstester i botten. De är automatiska och oftast billiga att köra. Hur dyra testerna är beror helt på vad som testas. Är ett grafiskt gränssnitt inblandat, så att testerna måste ta skärmdumpar och analysera dem, springer tiden och kostnaden iväg.
Livekodning: ett första test
Section titled “Livekodning: ett första test”Mats installerade Vitest i sin A3-lösning, skapade PlayingCard.test.js i samma katalog som
PlayingCard.js och lade till skripten i package.json. Testfilen fyllde han med exemplet från
artikeln. Det enda som behöver importeras är describe, test och expect, och matchare som
toBe() följer med expect. Resten är vanlig kod.
npm test körde de tre testerna, och alla gick igenom. Skulle en ändring i PlayingCard få
testerna att sluta fungera har du troligen infört en bugg, eller så har kraven ändrats och då får du
uppdatera testerna. Med Vitest-tillägget till Visual Studio Code kan du också köra ett enskilt test,
till exempel bara det som testar toString().
Mats har ställt in Visual Studio Code så att JavaScript-filer får gula ikoner och testfiler orange, så att det är lätt att se vilken fil som hör ihop med vilken.
Tester och AI
Section titled “Tester och AI”Mikael konstaterar att testning blir en viktig del av det dagliga arbetet när ni är färdiga med utbildningen. Mats menar att dess betydelse ökar ytterligare med AI: när mer kod skrivs av en assistent blir det ännu viktigare att kunna verifiera att koden gör rätt.
Mikael låter ofta AI skriva koden i sina egna projekt, men kräver alltid en testsvit. Han är misstänksam av sig och vill ha koll på vilka sorters tester det är: enhetstester eller integrationstester, och testas användargränssnittet i en riktig webbläsare? Ibland fuskar assistenten med testerna, så han behöver vara med som halvövervakare. I kursvecka 11 tar kursen upp hur du testar webbkomponenter, som har ett grafiskt gränssnitt, och kanske dyker verktyget Playwright upp där. Mikael berättar också om en kollega som testar ett spel genom att spela in spelomgångar och låta testerna analysera videoslingorna.
Testdriven utveckling
Section titled “Testdriven utveckling”Mikael har hört kolleger säga att testdriven utveckling (TDD) är grejen. Då skriver du enhetstesterna först, ser dem gå sönder och skriver sedan koden som får dem att gå igenom. Mats har arbetat så, men det är mycket svårt i det skede ni befinner er nu. För att skriva tester måste du kunna programmera och känna problemdomänen väl. Fördelen är att det skrivs få rader produktionskod i onödan, eftersom du bara skriver det som behövs för att testerna ska gå igenom. Annars är risken att du designar och implementerar en massa saker som aldrig kommer att köras. Mikael använder TDD ibland, beroende på uppgift, och tycker att det är trevligt.
Lagom mycket tester
Section titled “Lagom mycket tester”När du lär dig enhetstester efter att ha lärt dig programmera kan det kännas som att testkoden blir större än den riktiga koden. Det stämmer, säger Mats, och det gäller att hitta en balans. Du behöver inte testa allt. Testa normalfallet och gränsfallen (edge cases), och filtrera bort det mesta däremellan, annars blir det alldeles för många tester.
Artikeln är frivillig läsning. Kämpar du för att få A3 i mål kan den vänta, men den refererar till
A3 och ger mer kött på benen till frågorna om manuella tester i REFLECTION.md.
Mikaels A3-lösning
Section titled “Mikaels A3-lösning”Mikael har för första gången på många år en egen lösning till A3, och visade hur han provkör den. Hans tips är att börja längst ner i README-filen, där exemplen visar hur det ska se ut när programmet körs. Det hjälpte honom att förstå och bygga upp uppgiften. När han kör programmet med olika argument och jämför med exemplen är det, påpekar Mats, manuella end-to-end-tester.
Enhetstester i all ära, men som student tror Mikael inte att han hade haft energi över till dem. Han hade nöjt sig med att provköra programmet på det här sättet.
Utskrifterna går att göra på många sätt, och här skiljer sig lösningarna mycket åt. Mats påminner om att klassdiagrammet ska följas till punkt och pricka, men att det inte säger exakt var varje kodavsnitt ska placeras. Det finns sätt som är mindre bra och sätt som är bättre, men oavsett var på skalan du hamnar är den bästa lösningen den du förstår. Det primära är att lösa problemet. Har du sedan tid att strukturera om koden så att flödet blir naturligare är det en bonus.
Felfallen
Section titled “Felfallen”README-filen beskriver flera felfall, och Mikael räknar med att den som rättar kommer att prova dem.
Antalet spelomgångar ska vara ett heltal mellan 1 och 5 och antalet spelare ett heltal mellan 1 och
7, eller 52. Ett felaktigt argument ska ge ett felmeddelande och en statuskod, och då ska spelet
inte ens starta. Det hanteras i app.js, vid uppstarten.
Det tredje felfallet, att korten tar slut, hanteras i spelets kod. Mats förklarar att 52 spelare är ett specialfall som finns just för att det ska vara lätt att testa. Det understa kortet i draghögen delas aldrig ut, så när den femtioandra spelaren ska få sitt första kort finns det inga fler kort att dela ut. Felet inträffar alltså tidigt.
Mikael understryker att du ska köra felfallen själv och kontrollera att utskriften blir rätt. Han och Mats har varit med om redovisningar där studenten inte kommer ihåg hur programmet körs i terminalen, så det finns all anledning att träna innan.
Flödet i app.js
Section titled “Flödet i app.js”För att tänka igenom flödet i app.js skriver Mikael pseudokod. Med npm start kan två tal skickas
in, antalet spelomgångar och antalet spelare. Saknas ett värde ska ett standardvärde användas (en
spelomgång respektive tre spelare). Varje värde ska kontrolleras mot de giltiga värdena, och är det
felaktigt ska programmet avbrytas. Först därefter skapas spelbordet och spelet körs.
Mikael visade sedan en version han själv kallar fulkod, där pseudokoden var översatt rakt av.
Den innehåller medvetet ett par fel som inte hade blivit godkända enligt README-filen, bland annat
sättet programmet avslutas på, men det viktiga är flödet. Huvudprogrammet blir mycket litet, och det
tycker Mikael är vackert. Ibland får han in lösningar med en helt annan struktur på app.js, och det
bör egentligen leda till en komplettering. Enligt klassdiagrammet är playRounds() den enda publika
metoden på CardTable, så i grunduppgiften är det den enda som ska anropas från app.js.
Magiska tal
Section titled “Magiska tal”I fulkoden står talen 5, 26, 3, 52 och 28 utan förklaring. Det kallas magiska tal: värden som är självklara när du skriver dem, men som långt ifrån är det dagen, månaden eller året efter. Ur kodkvalitetssynpunkt bör de lösas på annat sätt, till exempel med namngivna konstanter, men i den här kursen är det helt i sin ordning att skriva dem på det här viset. Det kan som mest bli en diskussion med Mikael.
Kod som är för snygg
Section titled “Kod som är för snygg”Mikael bytte sedan till en AI-genererad version av app.js, skriven utifrån README-filen. Den
hanterar de magiska talen och delar upp koden i små, JSDoc-dokumenterade funktioner. Lite väl
uppdelad, tycker Mikael, men han kan köpa det. Sådan kod ser han i en tredjedel till hälften av
inlämningarna.
I koden fanns också en elegant konstruktion som Mikael aldrig hade sett förut, en one-liner som med en mer objektorienterad design hade krävt tre rader. Mats har börjat se den i lösningar, men ingen kan förklara den när han frågar. Ser Mikael sådant förväntar han sig en riktigt duktig student, och det märks nästan direkt om studenten har koll på läget och vet varför koden ser ut som den gör. Är koden misstänkt snygg vill han därför höra en riktig förklaring, så att han känner att det är studentens egen kod. Helt AI-genererade lösningar är ovanliga, kanske en eller två per inlämning.
Där lösningarna skiljer sig
Section titled “Där lösningarna skiljer sig”Mikael pekade ut tre metoder som brukar bli intressanta att diskutera med studenterna: playRounds()
och playOut(), där själva spelomgången sker, och valueOf() i Player, där du ska klura ut om
ett ess ska räknas som 1 eller 14. Här går det att få koden att fungera, och det är bra jobbat, men
det finns också utrymme att göra den mycket snygg.
Mats påpekar att klassdiagrammet bestämmer vilka metoder som ska finnas, om de är publika eller
privata, vad de tar för parametrar och vad de returnerar. Det kan verka hårt styrt, men det säger
ingenting om vad som ska hända inuti playRounds() eller playOut(). Det är öppet för fri tolkning,
och därför blir lösningarna så olika. Mikael och Mats har valt ut just de här metoderna utifrån
några tusen inlämningar, och kompletteringar kring esset är inte ovanliga.
Till esset hade Mikael skissat pseudokod för en klassisk studentlösning. Han kan själv ha svårt med den här sortens kod och sitter då och tänker och tänker. Att skriva pseudokod hjälper, och ibland visar sig ett smartare synsätt redan medan du skriver den. Gör du vissa antaganden får du mindre kod.
Först en lösning, sedan snygg kod
Section titled “Först en lösning, sedan snygg kod”Lyckas du implementera den klassiska lösningen ska du vara nöjd, säger Mats. Sedan kan du fundera på om det går att göra mer generellt. En del löser korsord på söndagen, andra funderar på om de kan spara in ett tecken i en algoritm. Båda ger tillfredsställelse, men det viktigaste är att du får något som fungerar.
Samma sak står i Clean Code av Robert C. Martin (Uncle Bob), boken som används i kodkvalitetskursen Daniel har berättat om. Den innehåller en förskräcklig massa regler, men det du ska ta fasta på är att det viktigaste är att ha en lösning. Därefter kan du göra koden bättre, elegantare och mer lättförståelig, för dig själv och för andra som läser den.
Mikael ger sällan komplettering för rörig kod med många rader som inte följer DRY, så länge den fungerar. Oftast matchar den studentens förståelse och förmåga så här långt, och har studenten löst uppgiften själv är han nöjd.
Engelska i koden
Section titled “Engelska i koden”En fråga i chatten gällde att Mikaels pseudokod var på svenska. Den bryr han sig inte om, eftersom han alltid städar bort pseudokoden när lösningen är klar. Själva koden, med kommentarer, ska vara på engelska. Mats lägger till att du får arbeta på det sätt och med de språk du känner dig bekväm med medan du utvecklar, men det du lämnar in ska vara enhetligt.
Veckans artiklar
Section titled “Veckans artiklar”Veckans teori finns samlad i två artiklar. Läs dem i ordning; den första lägger grunden för den andra.
-
Webbläsaren som körmiljö – vad som skiljer webbläsaren från Node, hur en sida renderas och hur du laddar in JavaScript som moduler.
-
Webbkomponenter – en introduktion – vad webbkomponenter är och hur de kommer att prägla resten av kursen.
Läsanvisningar
Section titled “Läsanvisningar”Under läsanvisningar hittar du veckans kapitel som ska läsas i kurslitteraturen. Planera upp och dela upp läsningen under veckan.
Övningar
Section titled “Övningar”Under Övningsuppgifter hittar du övningsuppgifter som det är lämpligt att du arbetar med under veckan.
Äldre inspelningar
Section titled “Äldre inspelningar”Inspelningarna från 2021 tar upp samma stoff som artiklarna, men är delvis inaktuella och har presentationer på engelska. Artiklarna räcker, men vill du se genomgångarna i rörlig bild finns de kvar här. Sammanfattningar och presentationer till inspelningarna hittar du i samlingen av inspelningar för delkurs B.
Webbläsaren och JavaScript – hur webbläsaren är uppbyggd och hur du länkar in JavaScript. Motsvarar artikeln Webbläsaren som körmiljö.
Varför JavaScript i webbläsaren? – en kort historik. Motsvarar inledningen av artikeln Webbläsaren som körmiljö.
Introduktion till custom elements och webbkomponenter. Motsvarar artikeln Webbkomponenter – en introduktion.
Handledning
Section titled “Handledning”Examinationsuppgift A3
Section titled “Examinationsuppgift A3”Nu är det hög tid att börja arbeta med examinationsuppgift A3.
Läs mer om “Examinationsuppgift A3 - Tjugoett” här.
Utmaningar
Section titled “Utmaningar”Under Utmaningar hittar du fyra frågor om HTTP och om hur webbläsaren laddar och kör skript, ett bra sätt att stämma av att du har förstått den första artikeln.
Studiefrågor
Section titled “Studiefrågor”Här är ett antal frågor som du kan försöka besvara och diskutera tillsammans med din AI-assistent. Tveka inte att lyfta någon av frågorna till handledningen för att fortsätta diskussionen med lärare och studiekamrater.
- Jag har programmerat JavaScript i Node och ska nu börja i webbläsaren. Vilka är de viktigaste skillnaderna jag behöver känna till? Ge exempel på kod som fungerar i den ena miljön men inte i den andra.
- Vad händer i webbläsaren från det att den har hämtat en HTML-sida tills sidan syns på skärmen? Var i den kedjan kan JavaScript ställa till det?
- Förklara skillnaden mellan
<script>,<script defer>,<script async>och<script type="module">. Ge mig sedan ett HTML-dokument med några skript och låt mig gissa i vilken ordning de körs innan du berättar svaret. - Varför får jag ett CORS-fel när jag öppnar en HTML-fil med en modul direkt från disk, och varför försvinner felet när jag använder en webbserver som Vite?
- Hur tar jag reda på om ett HTML-element, en CSS-egenskap eller ett API fungerar i alla webbläsare som mina användare kan tänkas ha?
- Jag vill skapa ett första eget HTML-element,
<hello-message>, som bara visar en hälsning. Visa den enklaste lösningen och förklara varje rad. Vänta med shadow DOM, det kommer senare i kursen.
Här följer tips till hur du kan prioritera bland kursmaterialet för att komma igång med veckan.
- Nu behöver du komma igång med A3. Det är fortfarande drygt 2 veckor till inlämning, men samtidigt så startar kursen upp med nya saker så håll farten uppe och gör så mycket av A3 som du kan. Det kan vara skönt att ha tid innan inlämningen för att finslipa din kod och testa så att allt fungerar.
- Försök prioritera så du också hinner läsa veckans två artiklar. Du behöver inte börja koda i webbläsaren än, men det är värdefullt om du redan nu börjar titta på hur det fungerar. Inspelningarna är frivilliga.
- När du läst artiklarna så finns det en övningsuppgift på nivån Uppvärmning där du får möjlighet att testa att programmera i webbläsaren och använda den miljön för utveckling. Missa inte att övningsuppgiften har ett inspelat lösningsförslag. Det spelades in för en tidigare version av projektet, så detaljer kan skilja sig från README:n. Följ README:n där de inte stämmer överens.


