Introduktion til programmering
Programmering er en metode til at give en computer beskeder og opgaver, så den ved præcist, hvad den skal udføre. Det er som at give en anden person en liste over opgaver med detaljerede instruktioner for hver enkelt opgave, så de kan udføre dem effektivt og præcist. Det er en kreativ proces, hvor du kan bringe dine idéer til live ved hjælp af logisk kode.
Det kan i høj grad være en udfordrende opgave at lære at beskrive opgaver og processer til en computer. Se denne video, hvor en far beder sine to børn om at fortælle ham, hvordan han, som var han en computer, der kun forstår simple operationer, skal lave en sandwich.
Det er en sjov måde at forklare, hvordan en computer fungerer, og hvor vigtigt det er at være præcis og detaljeret i dine instruktioner. Programmering handler om at tænke logisk og struktureret, så du kan beskrive opgaver på en måde, som en computer kan forstå og udføre.
Computere er enkle maskiner, der kan udføre simple opgaver hurtigt, men de kan kun gøre, hvad de bliver fortalt. Med programmering kan du få computeren til at udføre opgaver for dig ved at skrive kode, der beskriver, hvad du vil have computeren til at gøre, og hvordan den skal gøre det.
Koden kan være samlet i små programmer, der løser simple opgaver. For eksempel kan der på få linjer kode beregnes renter på lån eller tændes og slukkes en lampe baseret på information om solopgang og solnedgang. Men det kan også være millioner af linjer med instruktioner, der sammen løser komplekse opgaver, som f.eks. operativsystemer, skattesystemer med store mængder data og mange brugere, eller systemer bag kunstig intelligens.
Information til undervisere
Denne side bruger jeg og andre (husk at læse forsiden omkrng betingelser for brug) til at undervise/tale om programmering. Der er flere ting jeg synes der er vigtige i denne sektion:
- De studerende skal forstå hvad en computer er for en størrelse - at den ikke gør noget med mindre den konkret bliver bedt om det
- De bør have en helt basal forståelse for talsystemer - binær, hex og decimal. Igen - se https://mcronberg.github.io/csdemo/
- De behøver ikke forstå NAND, AND, OR og andre gates men det vil være godt med en kort introduktion. Forståelsen af hvordan en computere kan lægge sammen (adder) og huske (latch). Jeg bruger mine egne eksempler på kredsløb på https://mcronberg.github.io/csdemo/ - men helt ærligt bliver det hurtigt unødig information for begyndere. Desværre bliver jeg selv lidt grebet af det hele og kommer nogen gange til at bruge for lang tid
- De bør prøve at skrive lidt kode i Notepad, kompilere og afvikle. Brug .NET “Hello World” eller lignende - måske Python. De behøver ikke forstå koden - det er processen der er vigtig
- De skal forstå hvad en hukommelse er for en størrelse, og hvad en variabel er
- De skal helt basalt kende til løkker, betingelser, funktioner og fejlhåndtering
- De må meget gerne kende lidt historie om hardware og om personlighederne
- Hvad med en tur på Teknisk Museum for at lure på DASK
- Inden undervisning sørg for at:
- Visual Studio Code er installeret
- Måske Github Copilot
- .NET er installeret
- Python er installeret
- Git er installeret (og brugernavn og email er sat op)
- git config –global user.name “Dit Brugernavn”
- git config –global user.email “dinemail@eksempel.com“
- GitHub konto er oprettet og klar
- ChatGpt er logget ind
- ZoomIt er installeret
Hvorfor lære programmering?
Softwareudvikling åbner mange muligheder. Uanset om du vil bygge hjemmesider, mobilapps, spil, virksomhedsoftware eller automatisere processer, kan det give mange fordele. Det handler om mere end at skrive kode; det kræver problemløsning, kreativitet, samarbejde og kontinuerlig læring. Selv hvis du ikke arbejder som udvikler, kan de tilegnede færdigheder være værdifulde i andre felter.
Softwareudvikling er en kreativ proces, der involverer at løse problemer og bygge løsninger. Det kræver kreativ tænkning og innovative løsninger. Udviklere er efterspurgte, og behovet stiger. Det giver mange jobmuligheder og mulighed for en stabil og velbetalt karriere. Uanset om du er interesseret i webudvikling, appudvikling, spiludvikling eller noget helt fjerde, er der mange muligheder for at finde et job, der passer til dine interesser og færdigheder.
Softwareudvikling opfordrer til teamwork, kommunikation og videndeling. Det er et felt, hvor man lærer fra andre og opbygger netværk. Der er altid noget nyt at lære, og det kræver, at man holder sig opdateret med de nyeste teknologier. Det er en dynamisk karriere, der tilbyder personlig og professionel vækst.
En anden fordel ved softwareudvikling er, at det kan være en fantastisk hobby. Ligesom at bygge med LEGO, kan du skabe noget unikt og spændende ud fra dine ideer. Det giver en følelse af tilfredsstillelse at se et projekt komme til live, og det kan være en sjov og udfordrende måde at tilbringe din fritid på. Uanset om du udvikler små spil, personlige værktøjer eller eksperimenterer med nye teknologier, kan softwareudvikling være en yderst givende hobby.
Derudover udvikler du værdifulde færdigheder som logisk tænkning og systematisk problemløsning, som er anvendelige i mange andre områder. At lære programmering kan også give dig en bedre forståelse af den teknologi, der omgiver os i hverdagen, og åbne døre til mange spændende muligheder i fremtiden.
Hvorfor lære programmering i en tid med kunstig intelligens?
Selvom kunstig intelligens (AI) og avancerede sprogmodeller som ChatGPT bliver mere udbredte og kraftfulde, er der stadig mange gode grunde til at lære programmering:
-
Forståelse af teknologi: Ved at lære programmering får du en dybere forståelse af, hvordan teknologier som AI fungerer, hvilket gør dig bedre rustet til at anvende og udnytte dem effektivt.
-
Kontrol og tilpasning: AI-værktøjer kan være meget kraftfulde, men de er ikke altid perfekte. Ved at kunne programmere kan du tilpasse og forbedre AI-værktøjerne til dine specifikke behov og sikre, at de fungerer, som du ønsker.
-
Problemløsning: Programmering udvikler dine evner inden for logisk tænkning og systematisk problemløsning, færdigheder der er værdifulde i næsten alle aspekter af livet og arbejde.
-
Jobmuligheder: Selvom AI kan automatisere mange opgaver, er der stadig stor efterspørgsel efter dygtige programmører til at udvikle, vedligeholde og forbedre software og AI-systemer.
-
Kreativitet: Programmering giver dig mulighed for at bringe dine egne idéer til live og skabe unikke løsninger, spil, applikationer og meget mere. Det er en kreativ proces, der ikke kan erstattes fuldstændigt af AI.
-
Personlig udvikling: At lære programmering fremmer en livslang læringstilgang, hvor du konstant udvikler dine færdigheder og tilpasser dig nye teknologier og metoder.
-
Sikkerhed og etik: Med en forståelse af programmering kan du bedre vurdere sikkerheds- og etiske aspekter ved brug af teknologi og AI, og sikre at systemer udvikles og anvendes ansvarligt.
Selvom AI og sprogmodeller fortsætter med at udvikle sig, giver programmering dig de nødvendige værktøjer og færdigheder til at forblive relevant og konkurrencedygtig i en teknologidrevet verden.
Talsystemer
Hvis du er begynder indenfor softwareudvikling, er det vigtigt at have en grundlæggende forståelse af talsystemer - i hvert fald de tre mest almindelige talsystemer: decimal, binær og hexadecimal. Du vil konsekvent støde på disse talsystemer, når du arbejder med software, og det er vigtigt at forstå, hvordan de fungerer og hvordan de konverteres mellem hinanden. Det vil hjælpe dig med at forstå, hvordan computere repræsenterer og behandler data, og hvordan du kan arbejde med tal i din kode.
Så selvom det virker som en tør og teknisk detalje, er det et vigtigt emne at have dækket, inden vi begynder at snakke om programmering.
Det decimale talsystem
Det decimaltalsystem er det talsystem, vi bruger i vores dagligdag. Det er baseret på ti cifre: 0, 1, 2, 3, 4, 5, 6, 7, 8 og 9. Hvert ciffer repræsenterer en potens af 10, hvor positionen af cifferet bestemmer værdien. For eksempel repræsenterer tallet 123 følgende potenser af 10:
- Første position fra højre (3) er \(3 \cdot 10^0\), som er 3.
- Anden position (2) er \(2 \cdot 10^1\), som er 20.
- Tredje position (1) er \(1 \cdot 10^2\), som er 100.
For at finde den decimal værdi, lægger vi disse potenser sammen: \(100 + 20 + 3 = 123\). Dette er en simpel måde at forstå, hvordan decimaltalsystemet fungerer, og hvordan vi repræsenterer tal i vores dagligdag.
Skal man foretage simple beregninger - eksempelvis addition - er det er nemt at bruge det decimale talsystem:
eller
Beregninger som disse kommer naturligvis ikke som nogen overraskelse, men det er vigtigt at forstå, at samme beregningsprincipper gælder for andre talsystemer.
Det binære talsystem
I det binære talsystem bruger vi kun to cifre, 0 og 1 og arbejder i potens af 2, i modsætning til det decimaltalsystem vi normalt anvender, som har ti cifre (0-9) og arbejder i potens af 10. Dette talsystem er fundamentet for al moderne computer teknologi, fordi det er ekstremt effektivt til elektronisk databehandling.
Hvorfor netop binært? Det handler om de mest grundlæggende elektroniske komponenter i en computer – transistorerne. En transistor i en computer kan have to tilstande: tændt eller slukket. Denne enkle, binære tilstand gør det muligt at repræsentere data med kun to cifre, hvor 0 typisk står for ‘slukket’ og 1 for ‘tændt’.
Hver binær cifre kaldes en ‘bit’, som er en sammentrækning af “binary digit”. Bits er byggestenene i det binære talsystem. Når vi kombinerer bits, kan vi danne mere komplekse datastrukturer. For eksempel bruger vi 8 bits til at danne en ‘byte’, og med forskellige kombinationer af otte tændte eller slukkede bits kan vi repræsentere alt fra tal til bogstaver og andre symboler.
Mest kendte forkortelser inden for det binære talsystem
Her er nogle af de mest kendte forkortelser og enheder, du vil støde på, når du arbejder med binære systemer i softwareudvikling:
- Bit (b): Den mindste enhed af data i computeren. En bit kan være enten 0 eller 1.
- Nibble: En halv byte, bestående af 4 bits.
- Byte (B): En samling af 8 bits. En byte kan repræsentere 256 forskellige værdier (fra 0 til 255).
- Word: En samling af bits, typisk 16, 32 eller 64 bits afhængig af computerarkitekturen.
- Kilobit (Kb): 1.000 bits (ikke at forveksle med kibibit, som er 1.024 bits).
- Kilobyte (KB): 1.000 bytes (ikke at forveksle med kibibyte, som er 1.024 bytes).
- Megabit (Mb): 1.000.000 bits (ikke at forveksle med mebibit, som er 1.048.576 bits).
- Megabyte (MB): 1.000.000 bytes (ikke at forveksle med mebibyte, som er 1.048.576 bytes).
- Gigabit (Gb): 1.000.000.000 bits (ikke at forveksle med gibibit, som er 1.073.741.824 bits).
- Gigabyte (GB): 1.000.000.000 bytes (ikke at forveksle med gibibyte, som er 1.073.741.824 bytes).
- Terabit (Tb): 1.000.000.000.000 bits (ikke at forveksle med tebibit, som er 1.099.511.627.776 bits).
- Terabyte (TB): 1.000.000.000.000 bytes (ikke at forveksle med tebibyte, som er 1.099.511.627.776 bytes).
Disse enheder og forkortelser er grundlæggende for forståelsen af, hvordan data måles og håndteres i computere.
For at forstå hvordan vi regner i binært, kan vi tage et simpelt eksempel. Betragt følgende binære tal: 00001011. Dette tal læses fra højre mod venstre, hvor hver position repræsenterer en stigende potens af 2:
- Første position fra højre (1) er \(2^0\), som er \(1\).
- Anden position (1) er \(2^1\), som er \(2\).
- Tredje position (0) er \(2^2\), som er \(4\).
- Fjerde position (1) er \(2^3\), som er \(8\).
- Femte position (0) er \(2^4\), som er \(16\).
- Sjette position (0) er \(2^5\), som er \(32\).
- Syvende position (0) er \(2^6\), som er \(64\).
- Ottende position (0) er \(2^7\), som er \(128\).
For at finde den decimal værdi, lægger vi kun de værdier sammen, hvor der er en 1’er i det binære tal: \(8 + 0 + 2 + 1 = 11\).
Så det binære tal 1011 svarer til det decimal tal 11:
| 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|-----|-----|-----|-----|-----|-----|-----|-----|
| 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 |
= \(0 + 0 + 0 + 0 + 8 + 2 + 1 = 11\)
Det binære tal 10101010 svarer til det decimal tal 170:
| 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|-----|-----|-----|-----|-----|-----|-----|-----|
| 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
= \(128 + 0 + 32 + 0 + 8 + 0 + 2 + 0 = 170\)
Dette system gør det muligt for computere at behandle og lagre en enorm mængde information meget effektivt og er grunden til, at binære talsystem er så fundamentalt i alt fra software programmering til databehandling og digital kommunikation.
Tip
Du kan eksperimentere med binære tal og konverteringer på https://mcronberg.github.io/csdemo/numbers.html. Prøv at konvertere mellem decimal og binær og se, hvordan tallene repræsenteres i de to talsystemer.
Skal man foretage simple beregninger - eksempelvis addition - fungerer det som i det decimale talsystem:
eller
Er det vigtigt for begyndere?
For de fleste begyndere i softwareudvikling er det ikke nødvendigt at have en dyb forståelse af det binære talsystem. Dog er det nyttigt at have en grundlæggende forståelse af, hvordan binære tal fungerer, da det er grundlaget for alt, hvad der sker i en computer. At forstå, hvordan data repræsenteres og behandles i binært, kan hjælpe dig med at forstå, hvordan computere fungerer og hvordan software fungerer på et grundlæggende niveau.
Kan du se hvad klokken er?
På diverse uddannelser er det normale ur over døren skiftet ud med et binært ur. Det er en sjov måde at lære at læse binære tal på. Her er et eksempel på hvordan et binært ur kan se ud:
Repræsentation af værdier i computere
Computere repræsenterer altså data i binær form ved hjælp af bits og bytes, og der er mange forskellige værdier du kunne ønske at gemme. Her er en grundlæggende gennemgang af, hvordan forskellige typer værdier repræsenteres:
Heltal
Heltal kan repræsenteres ved forskellige antal bytes:
- 1 byte (8 bits): Kan repræsentere værdier fra 0 til 255 (uden fortegn) eller fra -128 til 127 (med fortegn).
- 2 bytes (16 bits): Kan repræsentere værdier fra 0 til 65.535 (uden fortegn) eller fra -32.768 til 32.767 (med fortegn).
- 4 bytes (32 bits): Kan repræsentere værdier fra 0 til 4.294.967.295 (uden fortegn) eller fra -2.147.483.648 til 2.147.483.647 (med fortegn).
Tip
Prøv at se https://mcronberg.github.io/csdemo/ram.html for at se hvordan simpel hukommelse i en computer er organiseret.
Negative tal
Negative tal repræsenteres typisk ved hjælp af den såkaldte to-komplement metode. For at repræsentere et negativt tal, inverteres (ændres) alle bits i tallet fra 0 til 1 og fra 1 til 0, og derefter lægges 1 til resultatet.
Eksempel: For et 4-bit system:
- Tallet +3 repræsenteres som 0011.
- For at finde repræsentationen af -3:
- Inverter alle bits i 0011: 1100.
- Læg 1 til resultatet: 1100 + 1 = 1101.
Så i et 4-bit system er +3 repræsenteret som 0011, og -3 er repræsenteret som 1101.
For at konvertere tilbage fra to-komplement til et negativt tal: - Hvis det første (venstre) bit er 1, er tallet negativt. - Inverter alle bits og læg 1 til resultatet.
Eksempel: For at konvertere 1101 tilbage til -3:
- Inverter 1101: 0010.
- Læg 1 til resultatet: 0010 + 1 = 0011.
- Resultatet er -3.
Du behøver ikke at forstå detaljerne i to-komplement metoden - det er mere vigtigt at forstå, at computere bruger denne metode til at repræsentere negative tal.
Kommatal
Kommatal (decimaltal) repræsenteres ved hjælp af IEEE 754 standarden (også kaldet floating point), som deler tallet i tre dele: fortegn, eksponent og mantisse. De to mest almindelige repræsentationer er:
- 32-bit (single precision): Bruger 1 bit til fortegn, 8 bits til eksponent, og 23 bits til mantisse.
- 64-bit (double precision): Bruger 1 bit til fortegn, 11 bits til eksponent, og 52 bits til mantisse.
Således vil man i et 32-bit system kunne repræsentere tal som 3.14159 eller 1.2345678e-10, mens man i et 64-bit system kan repræsentere langt større og mere præcise tal.
Igen, det er ikke nødvigt at forstå detaljerne i IEEE 754 standard - det er vigtigere at forstå, at computere bruger denne metode til at repræsentere kommatal. Men der skal ikke meget fantasi til at forestille sig, at det kan være en udfordring at arbejde med kommatal i et binært system, og at der kan opstå afrundingsfejl hvis man ikke er opmærksom. Det kan resultere i fejl i beregninger, som kan have alvorlige konsekvenser i nogle situationer.
I videoen forklares det, hvordan en lille afrundingsfejl i Patriot missilsystemet under Golfkrigen i 1991 førte til, at systemet fejlede i at opspore og afværge en irakisk Scud-missil, hvilket resulterede i 28 døde og 260 sårede soldater. Fejlen opstod ved konvertering af tidspunkter til binære tal, hvilket resulterede i en positionsfejl på 573 meter.
Bogstaver
Bogstaver og andre tegn repræsenteres ved hjælp af tegnsæt som ASCII eller Unicode:
- ASCII: Bruger 7 bits til at repræsentere 128 forskellige tegn. For eksempel er ‘A’ repræsenteret som 65.
- Unicode: Bruger flere bytes til at repræsentere et stort antal tegn fra forskellige skriftsystemer.
For eksempel repræsenterer Unicode-tegnet ‘A’ stadig 65, mens det japanske tegn ‘あ’ er repræsenteret som U+3042.
Så når du skriver et Word dokument, sender en e-mail eller besøger en hjemmeside, bruger computeren disse tegnsæt til at vise bogstaver, tal og symboler på skærmen. Men alt er stadig baseret på binære tal, som computeren kan forstå og behandle. Så den binære repræsentation af “Hello, World!” kan se sådan ud:
01001000 01100101 01101100 01101100 01101111 00101100 00100000 01010111 01101111 01110010 01101100 01100100 00100001
fordi hvert bogstav er repræsenteret ved hjælp af en binær værdi.
Du kan selv finde en ASCII tabel på nettet og prøve at konvertere “Hello, World!” til binære tal.Summering
Forståelsen af disse grundlæggende repræsentationer er vigtig for at kunne arbejde med data i programmering, da det giver indsigt i, hvordan computere gemmer og behandler information.
Info
Kan du se hvordan alt i en klassisk computer er baseret på binære tal? Det er fundamentet for alt, hvad der sker i en computer, og det er derfor vigtigt at have en grundlæggende forståelse af, hvordan binære tal fungerer.
Du behøver ikke forstå 2-komplement metoden, IEEE 754 standard eller Unicode-tegnsæt - det er mere vigtigt at forstå, at computere bruger disse metoder til at repræsentere data, og at det er grundlaget for alt, hvad der sker i en computer.
Det hexadecimale talsystem
Det hexadecimale talsystem er et positionssystem med basis 16, hvilket betyder, at det bruger 16 forskellige cifre. Disse er de velkendte cifre fra 0 til 9 suppleret med bogstaverne A til F, hvor A repræsenterer 10, B er 11, C er 12, D er 13, E er 14, og F er 15 i det decimale system.
For at forstå hvordan man arbejder med hexadecimale tal, kan vi tage et simpelt eksempel. Betragt følgende hexadecimale tal: 11. Dette tal læses fra højre mod venstre, hvor hver position repræsenterer en stigende potens af 16:
- Første position fra højre (1) er \(1 \cdot 16^0\), som er \(1\).
- Anden position (1) er \(1 \cdot 16^1\), som er \(16\).
For at finde den decimale værdi, lægger vi værdierne sammen: \(1 + 16 = 17\).
Eller hvad med tallet 2E?
- Første position fra højre (E) er \(14 \cdot 16^0\), som er \(14\).
- Anden position (2) er \(2 \cdot 16^1\), som er \(32\).
For at finde den decimale værdi, lægger vi værdierne sammen: \(32 + 14 = 46\).
Hvad så med tallet FF?
- Første position fra højre (F) er \(15 \cdot 16^0\), som er \(15\).
- Anden position (F) er \(15 \cdot 16^1\), som er \(240\).
For at finde den decimale værdi, lægger vi værdierne sammen: \(240 + 15 = 255\).
Slutteligt - hvad med tallet ABCD?
- Første position fra højre (D) er \(13 \cdot 16^0\), som er \(13\).
- Anden position (C) er \(12 \cdot 16^1\), som er \(192\).
- Tredje position (B) er \(11 \cdot 16^2\), som er \(2816\).
- Fjerde position (A) er \(10 \cdot 16^3\), som er \(40960\).
For at finde den decimale værdi, lægger vi værdierne sammen: \(40960 + 2816 + 192 + 13 = 43981\).
Kan du se hvad klokken er?
Tidligere nævnte jeg, at det klassike ur over døren i undervisningslokalerne var skiftet ud med et binært ur. Der findes også hexadecimale ure, og her er et eksempel på hvordan et hexadecimal ur kan se ud:
Det hexadecimale system bruges ofte i programmering og informationsteknologi, fordi det er mere kompakt end det binære system, men stadig kan mappes direkte til det, hvilket gør det enklere at læse og skrive binære data. Hver hexadecimal ciffer kan præcist repræsentere fire binære cifre (bits), hvilket gør oversættelsen mellem de to systemer meget effektiv. For eksempel svarer et enkelt hexadecimal ciffer ‘F’ direkte til de binære cifre ‘1111’, og hexadecimal ‘2’ svarer til ‘0010’.
Denne direkte korrespondance gør det muligt at reducere kompleksiteten og længden af binære tal, hvilket er særligt nyttigt i felter som digital elektronik og computerprogrammering, hvor man ofte skal håndtere lange sekvenser af bits. At arbejde med hexadecimale tal reducerer risikoen for fejl, da det er lettere at skrive og kontrollere færre cifre.
For at konvertere fra binær til hexadecimal, grupperer man de binære cifre i grupper af fire fra højre mod venstre, og omdanner hver gruppe til det tilsvarende hexadecimale tal. Omvendt kan man let omdanne et hexadecimalt tal til binær ved at erstatte hvert hexadecimale ciffer med den tilsvarende gruppe af fire binære cifre.
Her er et par eksempler:
- 0011 svarer til 3 i decimal og 3 i hexadecimal.
- 1001 svarer til 9 i decimal og 9 i hexadecimal.
- 1010 svarer til 10 i decimal og A i hexadecimal.
- 1011 svarer til 11 i decimal og B i hexadecimal.
Ved større binære værdier kan det være nyttigt at opdele dem i grupper af fire for at lette konverteringen til hexadecimal.
For eksempel vil det binære tal 1101110110₂ konverteres til hexadecimal således:
- Opdel det binære tal i grupper af fire fra højre: 1101 1101 10
- Tilføj eventuelt foranstillede nuller for at fuldføre den sidste gruppe: 0011 0111 0110
- Omdan hver gruppe til det tilsvarende hexadecimale tal: 3 7 6
Derfor er 1101110110 binært lig med 376 i hexadecimalt. Denne teknik anvendes bredt i programmering, især til adressering af hukommelse og ved farvekodning i digitale medier, hvor hexadecimal kode er standard.
Det oktale talsystem
Udover det decimale, binære og hexadecimale talsystem, findes også det oktale talsystem, som er baseret på otte cifre (0-7). Dette talsystem bruges sjældent i moderne computere. Det oktale talsystem er dog stadig relevant i nogle sammenhænge, især i gamle systemer og i nogle former for digital kommunikation.
Hvorfor kan man købe en t-shirt med 2A på?
Tidligere så vi, hvordan “Hello, World!” kunne repræsenteres i binære tal. Hvad med den hexadecimale repræsentation af “Hello, World!” - kunne der være en årsag til at man kan købe en t-shirt med “48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21” på brystet?
Måske har du læst “Hitchhiker’s Guide to the Galaxy” af Douglas Adams, hvor svaret på alt er 42. I ASCII er 42 repræsenteret som ‘*’, så måske er svaret på alt et stjernetegn - der som bekendt i mange operativsystemer repræsenterer “alt”? Kan det forklare en t-shirt med “42” i binær form (00101010) eller hexadecimale form (2A)? Er 2A virkelig svaret på alt?
Lidt om hardware
For bedre at forstå softwareudvikling er det vigtigt at have en grundlæggende forståelse af, hvordan computere fungerer, herunder både traditionelle og kvantecomputere. Traditionelle computere bruger binær logik og transistorer til at behandle information. Kvantecomputere derimod opererer på principperne om kvantemekanik. De bruger qubits, som kan repræsentere flere tilstande samtidig, hvilket gør dem meget mere kraftfulde i visse scenarier. For nuværende skal du blot huske: traditionelle computere bruger binær logik og transistorer, mens kvantecomputere bruger qubits og kvanteporte.
En kort historie om computing
“Computing” begyndte med simple mekaniske enheder til aritmetiske operationer. Disse udviklede sig til sofistikerede elektroniske systemer. Tidlige computere, som ENIAC og UNIVAC, var massive maskiner, der brugte relæer og radiorør. Opfindelsen af transistoren i slutningen af 1940’erne revolutionerede computing, hvilket muliggjorde mindre, hurtigere og mere pålidelige computere. Senere gjorde integrerede kredsløb og mikrochips computere endnu mindre og førte os ind i den digitale tidsalder.
Mens der er meget mere at fortælle om computerens historie, skal du for nuværende blot sætte pris på rejsen fra tidlige mekaniske enheder til nutidens kraftfulde computere.
Note
At udforske computerens historie kan være fascinerende og hjælper dig med at værdsætte moderne teknologi. Mange museer viser udviklingen af computing, som:
- Computer History Museum (USA)
- The National Museum of Computing (UK, Bletchley Park)
- Deutsches Museum (Tyskland)
- Science Museum (UK)
- Living Computers: Museum + Labs (USA)
- Musée des Arts et Métiers (Frankrig)
- IBM Museum of Computing (Tyskland)
- Museo Nazionale della Scienza e della Tecnologia Leonardo da Vinci (Italien)
Der er også film og dokumentarer, der dækker computerens historie, såsom “The Imitation Game” (2014), “The Social Network” (2010), “Pirates of Silicon Valley” (1999), “Triumph of the Nerds” (1996) og “The Machine That Changed the World” (1992). Se i det mindste “The Imitation Game”—det er en fantastisk film om Alan Turing, Enigma-maskinen og kodebryderne i Bletchley Park under Anden Verdenskrig. Det er også en hyldest til en af de store hjerner i computerhistorien, og historien om hans liv er både fascinerende og tragisk.
Transistorer
I hjertet af enhver moderne elektronisk enhed er transistoren. En transistor er en lille elektronisk switch, der kan tænde eller slukke en strøm, hvilket repræsenterer de binære tilstande 0 og 1 (tændt eller slukket, sandt eller falsk). Disse binære tilstande er grundlaget for al digital computing. Transistorer er pakket i integrerede kredsløb eller mikrochips, der udfører de logiske operationer og beregninger, der er nødvendige for at køre software. I dag kan milliarder af transistorer placeres på en enkelt mikrochip, hvilket muliggør de kraftfulde enheder, vi bruger hver dag.
Info
Du har måske hørt om Moores lov, som siger, at antallet af transistorer på en mikrochip fordobles cirka hvert andet år. Denne observation, foretaget af Gordon Moore i 1965, har holdt stik i flere årtier og har drevet den hurtige udvikling af computerteknologi.
Traditionel computer
Traditionelle computere, ofte kaldet klassiske computere, er afhængige af binær logik til at behandle information. Transistorer og logiske porte er byggestenene i disse computere, hvilket giver dem mulighed for at udføre beregninger, lagre data og køre programmer. Som begynder behøver du ikke at vide meget om logiske porte, men det er godt at have en grundlæggende forståelse af, hvordan de fungerer.
Porte og logik
En logisk port er en grundlæggende byggesten i digitale kredsløb, der udfører en grundlæggende logisk operation. Der er flere typer logiske porte, herunder AND-, OR- og NOT-porte, hver med deres egen funktion. Tænk på en port som en meget lille elektronisk komponent, der tager en eller flere indgange og producerer en udgang baseret på indgangene. Input og output er binære, hvilket betyder, at de kan være enten 0 eller 1.
NOT-port
En NOT-port er den simpleste komponent. Den tager én input (A) og outputter den modsatte værdi (Q). Hvis A er 0, er Q 1, og omvendt. Dette kan skrives som Q = NOT A, og det kaldes også en inverter. Du vil se dette meget i programmering, især når du arbejder med binære værdier. NOT-porten kan vises i en sandhedstabel:
A | Q |
---|---|
0 | 1 |
1 | 0 |
Læs tabellen sådan: Hvis A er 0, er Q 1. Hvis A er 1, er Q 0.
AND-port
En AND-port tager to eller flere inputs og producerer en output på 1, kun hvis alle inputs er 1. Hvis nogen input er 0, vil output være 0. Dette kan skrives som Q = A AND B. Sandhedstabellen for en to-input AND-port ser sådan ud:
A | B | Q |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
Læs tabellen sådan: Q er 1, kun når både A og B er 1.
OR-port
En OR-port tager to eller flere inputs og producerer en output på 1, hvis mindst én af inputs er 1. Output er 0, kun hvis alle inputs er 0. Dette kan skrives som Q = A OR B. Sandhedstabellen for en to-input OR-port er:
A | B | Q |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
Læs tabellen sådan: Q er 1, hvis enten A eller B er 1, eller hvis begge er 1.
XOR-port
En XOR (exclusive OR) port tager to inputs og producerer en output på 1, hvis præcis én af inputs er 1. Hvis begge inputs er ens, er output 0. Dette kan skrives som Q = A XOR B. Sandhedstabellen for en to-input XOR-port er:
A | B | Q |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
Læs tabellen sådan: Q er 1, kun når A og B er forskellige.
Tip
Du kan eksperimentere med logiske porte og sandhedstabeller på https://mcronberg.github.io/csdemo/gates.html. Prøv at ændre input og se, hvordan output ændres baseret på logikken for hver port.
NAND-, NOR- og NXOR-porte
NAND (NOT AND), NOR (NOT OR) og NXOR (NOT XOR) porte er kombinationer af de grundlæggende porte, vi har diskuteret. De kaldes universelle porte, fordi de kan bruges til at skabe enhver anden type logisk port. For eksempel kan en AND-port skabes ved at kombinere en NAND-port med en NOT-port. Disse porte er essentielle i digital kredsløbsdesign og er grundlaget for moderne computing.
Selvom du er nybegynder, kan forståelsen af disse grundlæggende begreber hjælpe dig med at sætte pris på, hvordan computere behandler information og udfører programmer. Mens du ikke behøver at være ekspert i digital logik, kan det at have en grundlæggende forståelse af logiske porte være gavnligt, når du dykker dybere ned i softwareudvikling. Det er ligesom at kende alfabetet, før du lærer at læse og skrive.
Info
Alle programmeringssprog bruger binær logik og udtryk, så forståelse af hvordan binær logik fungerer, kan hjælpe dig med at skrive bedre kode og forstå, hvordan computere behandler information. Du vil skrive mange AND- og OR-operationer i kode, og du vil ofte se binære operationer i kode. For eksempel udfører bitwise AND-operatoren (&
) i C, C++, Java og andre sprog en logisk AND-operation på hvert par af tilsvarende bits. Forståelse af binær logik kan hjælpe dig med at skrive mere effektiv kode og forstå, hvordan computere behandler information.
Kombinationer af logiske porte
Kombinationen af logiske porte og transistorer danner grundlaget for digital computing. Ved at kombinere disse byggesten kan du opbygge mere komplekse kredsløb, der udfører avancerede operationer og beregninger.
Her er et eksempel på en fuldadder, der bruger AND-, OR- og XOR-porte til at udføre en binær addition af to bits. Denne kreds tager to bits (A og B) som input og producerer to output (Sum og Carry). Sum er resultatet af additionen, mens Carry er en overførsel fra en tidligere beregning. Denne kreds er en grundlæggende byggesten i digitale computere og bruges til at udføre binære additioner.
Prøv den selv på https://mcronberg.github.io/csdemo/fulladder.html.
Samme logiske porte bruges også til at gemme information. Når en transistor er tændt (1), kan den repræsentere et stykke data. Ved at organisere millioner af transistorer i et komplekst system af gates kan vi gemme og hente store mængder data.
Her er et eksempel på en latch, der bruger porte til at gemme en bit af data. Latchen kan gemme en bit, indtil den nulstilles. Dette er en simpel form for hukommelse, der bruges i computere til at gemme midlertidige data.
Prøv den selv på https://mcronberg.github.io/csdemo/srandorlatch.html.
CPU
Alle disse logiske porte og transistorer samles i computerens centralenhed (CPU). CPU’en er computerens hjerne, der er ansvarlig for at udføre instruktioner, udføre beregninger og håndtere data. Den består af flere komponenter, herunder den aritmetiske logiske enhed (ALU), kontrolenheden og registre. CPU’en henter instruktioner fra hukommelsen, dekoder dem og udfører dem for at udføre de opgaver, som softwaren kræver. Dens kompleksitet er forbløffende, men helt grundlæggende er CPU’en en samling af logiske porte og transistorer, der arbejder sammen for at behandle information.
Alle de forskellige funktioner i CPU’en, såsom at udføre beregninger, håndtere hukommelse og udføre instruktioner, kan udføres af et antal instruktioner, som CPU’en kan forstå. Disse instruktioner er skrevet i maskinkode, som er et lavniveau programmeringssprog, der direkte svarer til de binære instruktioner, som CPU’en kan udføre. Du kan se det som en binær kode (nuller og ettaller), der fortæller CPU’en, hvad den skal gøre, og nullerne og ettallerne er direkte relateret til strømmen i de elektroniske kredsløb. Basalt er det meget logisk og simpelt, men det kan være meget komplekst, når du ser på det store billede, og når du tilføjer hastighed til ligningen, øges kompleksiteten.
Alle CPU’er har en clock frekvens, som er antallet af cyklusser pr. sekund, som CPU’en kan udføre. Hver gang “uret” tikker, kan CPU’en udføre en instruktion (det er lidt mere komplekst end det - men du forstår pointen). Jo hurtigere klokfrekvensen er, jo flere instruktioner kan CPU’en udføre på en given tid. Dette er grunden til, at CPU’er med højere klokfrekvens generelt er hurtigere og mere kraftfulde end dem med lavere klokfrekvens. Hastigheden måles i Hertz (Hz), og 1 Hz er én cyklus pr. sekund. Moderne CPU’er har klokfrekvenser i gigahertz (GHz) området, hvilket betyder, at de kan udføre milliarder af instruktioner pr. sekund.
Hukommelse
Hukommelse er en anden væsentlig komponent i en computer. Den gemmer data og instruktioner, som CPU’en har brug for til at køre programmer. Der er forskellige typer hukommelse i en computer, såsom RAM (random access memory) og ROM (read-only memory). RAM er flygtig hukommelse, der gemmer data midlertidigt, mens computeren kører. Det er hurtigt, men mister sit indhold, når computeren slukkes. ROM, derimod, er ikke-flygtig hukommelse, der gemmer vigtige instruktioner til opstart af computeren. Det er langsommere end RAM, men beholder sit indhold, selv når computeren er slukket.
Fra et elektronisk perspektiv er hukommelse (igen) lidt som en stor matrix af elektroniske komponenter baseret på transistorer, der kan tændes eller slukkes. Hver transistor kan gemme en bit (0 eller 1), og ved at kombinere mange komponenter kan du gemme en masse data. CPU’en kan læse og skrive til hukommelsen, og hukommelsen kan tilgås tilfældigt (deraf navnet random access memory). Hukommelsen er forbundet med CPU’en med en bus, (lidt som er et sæt ledninger), der kan overføre data mellem CPU’en og hukommelsen. Databussen er som en motorvej for data, og jo bredere bussen er, jo mere data kan overføres på én gang. Derfor vil du ofte se computere beskrevet som 8-bit, 16-bit, 32-bit eller 64-bit computere, hvilket refererer til bredden af databussen.
Som nybegynder i softwareudvikling behøver du ikke at kende alle detaljerne om, hvordan hukommelsen fungerer, men forståelsen af, at midlertidige data gemmes i hukommelsen, mens computeren kører, kan hjælpe dig med at forstå begreber som variable, arrays, objekter og pointers i programmering. Hukommelsesstyring er en væsentlig del af softwareudvikling, og at vide, hvordan hukommelsen fungerer på et højt niveau, kan være gavnligt, når du skriver kode og bygger software.
Lager
Udover hukommelse har computere lagringsenheder som harddiske, solid-state drives (SSD’er) og flashdrev. Disse enheder gemmer data permanent, selv når computeren er slukket. Lagringsenheder er langsommere end hukommelse, men har meget større kapacitet. De bruges til at gemme operativsystemer, applikationer, filer og andre data, der skal bevares over tid. Når du gemmer en fil på din computer, gemmes den på en lagringsenhed, ikke i hukommelsen.
Lagringsenheder er som store biblioteker, hvor du kan gemme data i lang tid. Dataene gemmes på magnetiske diske eller flashhukommelseschips, og computeren kan læse og skrive data til og fra lagringsenhederne. Lagringsenhederne er forbundet med computeren med en bus, ligesom hukommelsen, men lagringsenhederne er langsommere end hukommelsen. Dette er grunden til, at du ikke kan køre programmer direkte fra en lagringsenhed; du skal først indlæse programmet i hukommelsen. Lagringsenhederne bevarer deres data, selv når computeren er slukket - i modsætning til RAM.
I/O-enheder
Input/output (I/O) enheder er periferiudstyr, der giver dig mulighed for at interagere med computeren. Disse enheder inkluderer tastaturer, mus, skærme, printere, scannere og netværksadaptere. I/O-enheder gør det muligt for dig at indtaste data i computeren og modtage output fra den. De er forbundet til computeren gennem porte, såsom USB, HDMI, Ethernet og andre. I/O-enheder er essentielle for at interagere med software og hardware, og de spiller en afgørende rolle i, hvordan du bruger en computer.
Bundkort
Bundkortet er computerens hovedkredsplade. Det forbinder alle computerens komponenter, såsom CPU, hukommelse, lagringsenheder og I/O-enheder. Bundkortet leverer de elektriske forbindelser og veje, der tillader data at flyde mellem komponenterne. Det er som computerens centralnervesystem, der koordinerer alle aktiviteterne og sikrer, at alt fungerer sammen uden problemer.
Tip
Hvis du er nysgerrig efter at vide, hvordan computere fungerer på et dybere niveau, kan du overveje at udforske området computerarkitektur. Det dykker ned i design og organisering af computersystemer, herunder CPU, hukommelse, lagring og I/O-enheder. Forståelse af computerarkitektur kan give dig en dybere forståelse for computerens indre funktioner og hvordan software interagerer med hardware.
Der er selvfølgelig mange ressourcer på internettet, der kan hjælpe dig med at forstå computerarkitektur, og du kan finde mange bøger om emnet. For begyndere, der bare vil have en grundlæggende forståelse af, hvordan computere fungerer, vil jeg anbefale at læse “But How Do It Know? - The Basic Principles of Computers for Everyone” af J. Clark Scott. Det er en god bog, der forklarer, hvordan computere fungerer fra bunden uden at blive for teknisk. En anden måde at få et indblik i, hvordan computere fungerer, er at bygge din egen computer. Det er ikke så svært, som det lyder, og der er mange vejledninger på internettet, der kan hjælpe dig med at bygge din egen computer fra bunden. Jeg vil anbefale at se Ben Eater’s YouTube-serie om at bygge en 8-bit computer fra bunden. Det er en fantastisk måde at lære om computerarkitektur og hvordan computere fungerer.
Hvis du er klar til opgaven, kan du endda købe en gammel CPU som 6502 eller Z80 fra 1980’erne (ja - de produceres stadig) og bygge din egen computer omkring den. Det er et projekt til 10-20 dollar og meget sjovt.
En meget simpel CPU
Alle computere har basalt kun nogle få opgaver de kan udføre.
- Opbevare og hente data fra hukommelsen
- Flytte data fra et sted til et andet
- Udføre beregninger
- Kommunikere med omverdenen (tastatur, skærm, netværk, osv.)
Alle disse operationer udføres typisk af en CPU (Central Processing Unit), og består i virkeligheden af en meget stor samling af transistorer and andre elektroniske komponenter samlet i logiske gates. Komponenterne er samlet i forskellige overordnede blokke som kan udføre forskellige opgaver:
- Registre - opbevarer data
- Databus - forbindelse til andre enheder
- Clock - flytter data fra et sted til et andet ved at åbn og lukke for forbindelser i en rasende fart
- Control Unit - styrer de andre komponenter
- Arithmetic Logic Unit (ALU) - udfører beregninger
- RAM - hukommelse til midlertidig opbevaring af data
- ROM - hukommelse til permanent opbevaring af data
- I/O - kommunikation med omverdenen
Alle disse komponenter kan styres af kontrollinjer som kan tændes og slukkes - og den helt simple forklaring på hvad programmering er, er at tænde og slukke for disse kontrollinjer. Det sker med binære instruktioner som CPU’en kan forstå, og der er ikke noget i vejen for at du selv kan skrive disse instruktioner ved at kigge på CPU’ens instruktionsmanual. Dette form for programmering kaldes for maskinkode, og er meget svært at lære og arbejde med fordi det er rene binære værdier og kræver en dyb forståelse for hvordan en CPU er opbygget.
Heldigvis findes der mange andre måder at skrive programmer på, og det er disse vi skal kigge på senere.
Det ligger langt uden for dette kapitel at forklare hvordan en CPU rent faktisk udfører opgaver, men hvis du har lyst kan du læse mere om det i min SAP CPU (simple as possible CPU). Der er også en del referencer på siden - herunder til Ben Eater, som har en samling forrygende videoer der viser hvor en CPU kan opbygges på breadboards.
Kvantecomputing
Kvantecomputing er et fascinerende og hurtigt udviklende felt, der lover at revolutionere computing. I modsætning til klassiske computere, der bruger binær logik og transistorer, opererer kvantecomputere på principperne om kvantemekanik (kvantefysik).
Designet af klassiske computere er baseret på transistorer og logiske porte til at behandle binær information. I sammenligning bruger kvantecomputere kvanteporte til at manipulere såkaldte qubits. Kvanteporte er mere komplekse og afhænger af kvantefænomener som superposition (superposition tillader qubits at være i flere tilstande på samme tid, hvilket betyder, at en qubit kan være både 0 og 1 samtidigt) og sammenfiltring (engelsk: entanglement, hvor to eller flere qubits bliver så tæt forbundne, at tilstanden af en qubit øjeblikkeligt kan påvirke tilstanden af en anden, uanset afstanden mellem dem). Denne fundamentale forskel gør det muligt for kvantecomputere at behandle flere muligheder på én gang, hvilket potentielt gør dem meget hurtigere til at løse visse komplekse problemer.
Hardware i kvantecomputere er også meget anderledes end i klassiske computere. Mens klassiske computere bruger siliciumbaserede chips med transistorer, bruger kvantecomputere fysiske elementer som atomer, ioner, fotoner eller superledende kredsløb til at skabe og manipulere qubits. Mange kvantecomputere bruger superledende kredsløb nedkølet til nær absolut nul, hvilket hjælper med at bevare kvantetilstande i længere perioder. Andre bruger fangede ioner i elektromagnetiske felter, manipuleret af lasere til at skabe og kontrollere qubits. Desuden bruger nogle kvantecomputere lyspartikler, eller fotoner, til at repræsentere qubits, der manipuleres med optiske enheder som strålesplittere og faseskiftere.
Programmering af kvantecomputere adskiller sig også markant fra programmering af klassiske computere. Klassisk programmering bruger traditionelle sprog som C, Python og Java, hvor programmer skrives som sekvenser af instruktioner, der manipulerer bits. Kvanteprogrammering bruger derimod specialiserede sprog som Qiskit, Cirq, Q#, og Quantum Assembly Language (QASM). Disse sprog giver programmører mulighed for at skrive kvantealgoritmer, der udnytter kvantemekanikkens egenskaber.
For eksempel, for at løse en labyrint ville en klassisk computer tjekke hver sti én efter én. En kvantecomputer derimod kan udforske flere stier samtidig og potentielt finde løsningen meget hurtigere. Denne parallelle behandlingskapacitet er en af de centrale fordele ved kvantecomputing.
Historisk set har mange store videnskabsmænd som Niels Bohr og Albert Einstein bidraget til udviklingen af kvantefysik. Bohr udviklede Bohr-modellen af atomet, mens Einstein, kendt for sin modstand mod nogle aspekter af kvantemekanikken, alligevel bidrog væsentligt med sin forklaring af den fotoelektriske effekt og teorier om kvanteentanglement.
Sammenfattende tilbyder kvantecomputere en ny måde at behandle information på, der udnytter de unikke egenskaber ved kvantemekanik. Mens klassiske computere er yderst effektive til mange opgaver, har kvantecomputere potentialet til at tackle problemer, der i øjeblikket ligger uden for rækkevidde for klassisk computing.
Tip
Hvis du er interesseret i kvantecomputing, er der mange ressourcer til at lære mere om emnet. IBM, Google, Microsoft og Rigetti er nogle af de førende virksomheder inden for kvantecomputing, og de tilbyder online ressourcer, kurser og værktøjer til at udforske kvantecomputing. Der er også mange bøger og artikler om emnet, såsom “Quantum Computing for Everyone” af Chris Bernhardt. At lære om kvantecomputing kan være en spændende rejse ind i en ny verden af computing og teknologi.
Programmering
Programmering handler om at løse problemer med hjælp af logik (betingelser og løkker), matematik (addere, substrahere, multiplicere mv) samt at opbevare værdier midlertidligt (variabler). På denne måde kan du løse en lang række opgaver, der ellers ville være tidskrævende eller måske endda praktisk umulige at løse manuelt.
Maskinkode
Med programmering skriver du instruktioner til en CPU, og i sin grundform er det en samling af binære værdier, som CPU’en kan forstå som et såkaldt instruktionssæt. Disse instruktiopner fortæller CPU’en, hvad den skal gøre, og hvordan den skal gøre det, og i virkeligheden er instruktionerne meget simple - som f.eks. at flytte en værdi fra et sted til et andet, at sammenligne to værdier, at udføre en beregning eller at springe til en anden del af programmet. Instruktionerne er helt basalt besked om at tænde og slukke for kontrollinjer i CPU’en ved hjælp af spænding.
Hver CPU har sit eget instruktionssæt, som definerer de operationer, den kan udføre, og hvordan den udfører dem. Instruktionssættet er unikt for hver CPU og er designet til at udnytte CPU’ens specifikke egenskaber og funktioner.
Som et eksempel kan den gamle 6502 CPU (Apple II, Commodore 64 mv) gemme en værdi i et lille register i CPU’en med en enkelt instruktion 10101001
, som fortæller hvilke kontrollinjer der skal tændes og slukkes for at gemme en værdi i registeret. Instruktionen kombineres med en værdi, der skal gemmes - eksempelvis 00001010
for at gemme værdien 10 (decimalt). Den samlede kommado vil så være 10101001 00001010
- eller skrevet i hexadecimale værdier A9 0A
. Næste instruktion kunne være at flytte værdien fra register A til register X. Den kommando hedder 10001010
eller 8A
i hexadecimale værdier. Næste kommenda kunne være at lægge 1 til værdien i register X. Den kommando hedder 11101000
eller E8
i hexadecimale værdier. Så med tre kommandoer
har vi gemt værdien 10 i register A, flyttet værdien fra register A til register X og lagt 1 til værdien i register X så den nu indeholder 00001011 (11 decimalt).
Det er lidt nemmere at skrive i hexadecimale værdier:
men i sidste ende er det blot en samling af binære værdier, som CPU’en kan forstå.
Denne form for programmering kaldes for maskinkode (enkelt operationer for opcode), og det er meget komplekst og kræver en dyb forståelse for, hvordan en CPU er opbygget. Det er også meget tidskrævende og fejlfølsomt, da en enkelt fejl kan få hele programmet til at bryde sammen.
Men alle programmer vil kunne skrives i rå maskinkode. Det vil tage en krig af tid og vil være meget svært at læse - men det er muligt.
Maskinsprog (assembly)
For at gøre det lidt lettere at skrive programmer i maskinkode, er der udviklet et sprog kaldet assembly, som er et lavniveau (tæt på hardware) programmeringssprog, der er tæt knyttet til CPU’ens instruktionssæt. Assembly giver programmører mulighed for at skrive instruktioner, der svarer til CPU’ens binære instruktioner. Hver assembly instruktion svarer direkte til en binær instruktion, og det gør det lettere at skrive og læse programmer sammenlignet med ren maskinkode.
Førnævte 6502 CPU program kunne skrives i assembly, og det kunne se sådan ud:
LDA betyder “load accumulator”, som er et register i CPU’en. #$0A
betyder at værdien 10 skal gemmes i registeret. TAX betyder “transfer accumulator to X register”, og INX betyder “increment X register by one”. Så disse tre instruktioner gør det samme som de tre maskinkode instruktioner ovenfor.
Det er meget nemmere for os mennesker at forstå og skrive, men CPU’en forstår jo naturligvis intet af disse instruktioner - de skal oversættes til binære instruktioner, som CPU’en kan forstå. Dette gøres med et program kaldet en assembler, som oversætter assembly koden til binære instruktioner.
I sin helt grundlæggende form er en assembler blot et program som, ved hjælp af en tabel, oversætter assembly instruktioner til binære instruktioner, som CPU’en kan udføre. I mere moderne assembly sprog er der også mulighed for at bruge labels, som er symboler der repræsenterer en hukommelsesadresse, samt makroer, som er en måde at genbruge kode på. Dette gør det lettere at skrive og vedligeholde assembly programmer.
Men selvom assembly er lettere at skrive og læse end maskinkode, er det stadig meget tæt på hardwaren og kræver en dyb forståelse for CPU’ens instruktionssæt og funktioner. Assembly programmering er ofte brugt i systemnære programmer, drivere og andre applikationer, der kræver direkte kontrol over hardwaren, og mange programmeringssprog oversætter “blot” deres kode til assembly, som så igen oversættes til binære instruktioner.
Du vil opdage, at programmering i mange henseender er abstraktion på abstraktion på abstraktion på … Allerede nu ved du, at maskinekode er for svært at arbejde med, og at assembly er en smule lettere. Senere vil du lære om højniveau programmeringssprog, som er endnu lettere at arbejde med. Men abstaktion er ikke blot en fordel - jo længere du kommer væk fra hardwaren, jo mindre kontrol har du over, hvad der sker, og jo mindre effektivt vil dit program køre. Så det er en balancegang mellem kontrol og effektivitet på den ene side og kompleksitet og abstraktion på den anden.
Info
Blot for at få nogle begreber på plads: Det at programmere kaldes også at udvikle eller skrive kode, instruktioner kaldes også for kodelinjer, og en samling af instruktioner kaldes for kildekode.
Højniveau programmeringssprog
For at gøre det endnu lettere at skrive programmer, er der udviklet højniveau programmeringssprog, som er designet til at være mere læselige og forståelige for mennesker. Disse sprog bruger mere naturlige og abstrakte begreber, som gør det lettere at skrive og læse kode. Højniveau programmeringssprog er mere abstrakte end assembly og maskinkode, og de giver programmører mulighed for at fokusere på problemløsning og logik i stedet for at bekymre sig om de tekniske detaljer i CPU’en.
Simpelt eksempel på kode i flere sprog
Her er et eksempel kode som tæller fra 1 til 9, og udskriver om tallet er mindre end 5 eller større eller lig med 5 - altså:
1 is less than 5
2 is less than 5
3 is less than 5
4 is less than 5
5 is greater or equal to 5
6 is greater or equal to 5
7 is greater or equal to 5
8 is greater or equal to 5
9 is greater or equal to 5
Koden viser nogle af de begreber du finder i alle programmeringssprog – variabler, løkker, betingelse og muligheden for at kommunikere med brugeren. Mere om disse begreber senere – her er først koden skrevet visuelt :
Maskinkode
Her er koden skrevet i rå maskinkode for en x86 (ish) CPU - det er meget svært at læse og forstå:
1011 1110 0100 0000 0000 0000 1010 1100 0011 1100 0000 0000 0111 0100 0000 0101 1010 0010 0100 0100 0000 0000 0010 1100 0011 0000 0000 0100 0011 000 1010 0010 0100 0100 0000 0000 0011 1100 0011 0101 0111 0010 0000 0101 1110 1011 1110 0111 1000 0000 0011 1110 0000 0000 0000 0000 0111 0100 0000 0101 1110 1011 1110 0111 1011 1000 0000 0001 0000 0000 0011 0001 1101 1011 1100 1101 1000 0000
Det gør det ikke meget lettere at læse som hexadecimale værdier:
BE 40 00 AC 3C 00 74 05 A2 44 00 2C 30 04 30 A2 44 00 3C 35 72 05 EB E7 80 3E 00 00 00 00 74 05 EB E7 B8 01 00 31 DB CD 80
Ingen ville skrive kode på denne måde men det er det eneste en CPU forstår!
Assembly
Lidt lettere at læse og forstå er koden skrevet i assembly (her i syntaxen der forstås af https://www.onecompiler.com):
section .data
less_than_five db ' is less than 5', 10, 0
greater_equal_five db ' is greater or equal to 5', 10, 0
numbers db '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0, '9', 0
section .bss
number resb 4
section .text
global _start
_start:
mov esi, numbers
loop_start:
lodsb ; Load byte at address (ESI) into AL and increment ESI
cmp al, 0 ; Compare AL with 0 (end of string)
je check_next ; If AL is 0, check the next number
mov [number], al ; Store AL into number
mov byte [number + 1], 0 ; Null terminate for print_number
sub al, '0' ; Convert ASCII to integer
add al, '0' ; Convert back to ASCII for printing
mov [number], al ; Store back the ASCII character in number
cmp al, '5' ; Compare with ASCII '5'
jb print_less_than_five ; Jump if below 5
print_greater_equal_five:
mov ecx, number
call print_number
mov edx, 26 ; Length of " is greater or equal to 5" + newline
mov ecx, greater_equal_five
mov ebx, 1
mov eax, 4
int 80h
jmp loop_start
print_less_than_five:
mov ecx, number
call print_number
mov edx, 16 ; Length of " is less than 5" + newline
mov ecx, less_than_five
mov ebx, 1
mov eax, 4
int 80h
jmp loop_start
check_next:
cmp byte [esi], 0 ; Check if next byte is also 0 (end of array)
je end_program ; If yes, end the program
jmp loop_start ; Otherwise, continue the loop
print_number:
mov edx, 1
mov ebx, 1
mov eax, 4
int 80h
ret
end_program:
mov eax, 1
xor ebx, ebx
int 80h
Det er stadig meget tæt på hardwaren, men det er meget lettere at læse og forstå end maskinkode. Assembly programmering er stadig meget kompleks og kræver en dyb forståelse for CPU’ens instruktionssæt og funktion.
Prøv at se om det virker på https://www.onecompiler.com/assembly.
Basic
Så vi vil langt hellere skrive koden i et højniveau programmeringssprog som f.eks. BASIC, Python eller C#.
Her er samme kode skrevet i et af de helt gamle programmeringssprog kaldet BASIC:
DIM i as Integer
FOR i = 1 TO 9
IF i < 5 THEN
PRINT i & " is less than 5"
ELSE
PRINT i & " is greater or equal to 5"
END IF
NEXT i
Prøv at se om det virker på https://www.onecompiler.com/basic.
Python
Her - samme kode i et ældre men stadig meget populært sprog kaldet Python:
for i in range(1, 10):
if i < 5:
print(str(i) + " is less than 5")
else:
print(str(i) + " is greater or equal to 5")
Prøv at se om det virker på https://www.onecompiler.com/python.
C
Her er koden i programmeringssproget C:
#include <stdio.h>
int main() {
int i;
for (i = 1; i < 10; i++) {
if (i < 5) {
printf("%d is less than 5\n", i);
} else {
printf("%d is greater or equal to 5\n", i);
}
}
return 0;
}
Se om det virker på https://www.onecompiler.com/c.
Java
public class Main {
public static void main(String[] args) {
for (int i = 1; i < 10; i++) {
if (i < 5) {
System.out.println(i + " is less than 5");
} else {
System.out.println(i + " is greater or equal to 5");
}
}
}
}
Se om det virker på https://www.onecompiler.com/java.
C#
using System;
class Program {
static void Main() {
for (int i = 1; i < 10; i++) {
if (i < 5) {
Console.WriteLine(i + " is less than 5");
} else {
Console.WriteLine(i + " is greater or equal to 5");
}
}
}
}
Se om det virker på https://www.onecompiler.com/csharp.
JavaScript
for (let i = 1; i < 10; i++) {
if (i < 5) {
console.log(i + " is less than 5");
} else {
console.log(i + " is greater or equal to 5");
}
}
Se om det virker på https://www.onecompiler.com/javascript.
Haskell
main :: IO ()
main = do
mapM_ checkNumber [1..9]
checkNumber :: Int -> IO ()
checkNumber i =
if i < 5
then putStrLn (show i ++ " is less than 5")
else putStrLn (show i ++ " is greater or equal to 5")
Se om det virker på https://www.onecompiler.com/haskell.
Ruby
(1..9).each do |i|
if i < 5
puts "#{i} is less than 5"
else
puts "#{i} is greater or equal to 5"
end
end
Se om det virker på https://www.onecompiler.com/ruby.
Kompilering
Oversættelsen fra kildekoden til assembler og fra assembler til binære instruktioner kaldes kompilering, og denne proces er ofte automatiseret af et værktøj kaldet en kompiler. Hvis du installerer et programmeringssprog som Python, C# eller Java er det i virkeligheden denne kompiler, samt en del andre værktøjer du installerer.
I princippet kunne du altså selv skrive de rå binære instruktioner hvis du kender instruktionsmanualen til den pågældende CPU. Noget nemmere ville det være for dig at skrive assembler som så oversættes til binære instruktioner af en kompiler, og langt nemmere vil det være at skrive C#, Python eller andre sprog. Denne forskel i abstraktionsniveau er årsagen til, at de moderne sprog kaldes højniveau sprog, hvor mellemkode og assembler kaldes lavniveau sprog.
Liste over forskellige programmeringssprog
Liste over forskellige programmeringssprog
Der findes en masse programmeringssprog og der udvikles hele tiden nye. Her er en liste over nogle af de mest kendte. Bemærk i øvrigt hvor mange danskere (med fed) der har bidraget til udvikling af forskellige sprog:
- COBOL fra 1960’erne
- Howard Bromberg og flere
- BASIC
- John George Kemeny og Thomas Eugene Kurtz på Dartmouth College (USA) i starten af 1960’erne
- C
- Dennis Ritchie (Bell Labs) i starten af 1970’erne
- C++
- Bjarne Stroustrup (Bell Labs) i starten af 1980’erne
- Objective-C
- Tom Love og Brad Cox er også fra 1980’erne
- Java
- James Gosling fra Sun Microsystems (nu Oracle) fra 90’erne
- JavaScript (som ikke må forveksles med Java)
- Brendan Eich (Netscape - senere Mozilla/Firefox) i 1990’erne
- C#
- Anders Hejlsberg hos Microsoft (2002)
- PHP
- Rasmus Lerdorf omkring 1995
- Delphi
- Anders Hejslberg hos Borland i 90’erne
- Ruby
- Yukihiro Matsumoto i 1995
- Python
- Guido van Rossum i 1991
- Dart
- Lars Bak og Kasper Lund
Se StackOverflow’s survey - her fra 2021 men find selv sidste version.
Tip
Der findes et super spændende værktøj kaldet OneCompiler som kan oversætte kildekode fra mange forskellige sprog og se resultatet - uden at skulle downloade en compiler. Der er også mange opgaver og eksempler på kode.
Igen et par begreber at slå fast: Kildekode er instruktioner skrevet i en speciel syntaks som sprogets kompiler forstår og kan oversætte. Denne proces kaldes kompilering. Tit bliver det også omtalt som at bygge. Kildekode oversat til binære instruktioner som kan afvikles af et operativsystem kaldes et program, applikation eller blot en app.
Udviklingsmiljøer
Alle former for programmering ender i sidste ende i tekstfiler (py-filer for Python, cpp-filer for C++, cs-filer for C#, js-filer for JavaScript mv), og i princippet kunne man sagtens bruge simple teksteditorer som Notepad, VIM og andre lignende. Men en stor del af det at lære at programmere handler også om at benytte det rigtige udviklingsværktøj.
Når du programmerer, kan det være en fordel at bruge et dedikeret udviklingsmiljø, også kaldet en IDE (Integrated Development Environment). En IDE tilbyder en række funktioner, der kan gøre kodningen lettere og mere effektiv. For eksempel inkluderer en IDE typisk funktioner som syntaksfremhævning, auto-fuldførelse af kode, debugging-værktøjer og versionstyring.
- Syntaksfremhævning hjælper med at gøre koden mere læsbar ved at farvekode forskellige elementer som nøgleord, variabler og kommentarer. Dette kan gøre det lettere at spotte fejl og forstå koden hurtigt.
- Auto-fuldførelse af kode foreslår automatisk kode, mens du skriver, hvilket kan spare tid og mindske risikoen for stavefejl. For eksempel, hvis du skriver en variabels navn, vil IDE’en foreslå fuldførelsen af navnet, så du ikke behøver at skrive det hele.
- Debugging-værktøjer gør det muligt at finde og rette fejl i koden mere effektivt. Du kan sætte breakpoints, som stopper eksekveringen af koden på bestemte steder, og derefter inspicere værdierne af variablerne for at forstå, hvad der går galt.
- Mange IDE’er har indbygget understøttelse af versionsstyring, såsom Git. Dette gør det muligt at holde styr på ændringer i koden, samarbejde med andre udviklere og rulle tilbage til tidligere versioner af koden, hvis der opstår problemer.
Eksempler på IDE’er
Der findes mange forskellige IDE’er, hver med sine egne fordele og ulemper. Her er nogle populære eksempler:
- Visual Studio: En kraftfuld IDE fra Microsoft, der understøtter mange forskellige programmeringssprog, herunder C#, og har mange avancerede funktioner.
- JetBrains Rider: En IDE specielt designet til .NET-udvikling, som tilbyder hurtig ydeevne og mange produktivitetsværktøjer.
- Visual Studio Code: En letvægts, men alligevel kraftfuld editor, der kan tilpasses med udvidelser til at understøtte mange forskellige programmeringssprog og funktioner.
- Eclipse: En populær IDE, især kendt for Java-udvikling, men den understøtter også mange andre sprog gennem plugins. Eclipse er open source og har et stort økosystem af udvidelser, der gør det muligt at tilpasse og udvide funktionaliteten efter behov.
- IntelliJ IDEA: En IDE fra JetBrains, der er meget brugt til Java-udvikling, men også understøtter en bred vifte af andre sprog og teknologier. IntelliJ IDEA er kendt for sin smarte kode-assistance, fejlkorrektion og dybdegående integration med forskellige byggesystemer og versionstyringsværktøjer.
- PyCharm: En IDE fra JetBrains, der er specialiseret til Python-udvikling. PyCharm tilbyder avanceret syntaksfremhævning, debugging, integration med populære web-frameworks som Django og Flask, samt support for data science-værktøjer som Jupyter notebooks.
Hver af disse IDE’er har sine egne unikke funktioner og fordele, der kan gøre dem velegnede til specifikke typer af projekter og udviklingsmiljøer.
Prøv det selv - Hello World
Den bedste måde at lære at programmere på er at prøve det selv – skrive noget kode, få det kompileret og efterfølgende afviklet. Du kan finde en guide her. Du kan nu prøve at åbne filen Program.cs som er din kildekode. Den ser nogenlunde således ud:
Sørg for at koden kan kompilere og afvikles (se førnævnte guide), og prøv så at tilrette koden, gemme og kompilere og afvikle igen. Se om du kan retten teksten til at skrive noget andet. Prøv også at lave en fejl ved eksempelvis at slette et semikolon, gemme samt kompilere og afvikle igen. Nu burde kompileren fortælle dig at der er noget den ikke kan finde ud af.
Du kan også prøve at lege lidt med Python - se en kort intro her.
Hvis det er første gang du har prøvet at skrive og afvikle et program så velkommen i vores verden!
Variabler
Variabler er et grundlæggende koncept i programmering, og kan findes i alle programmeringssprog. De defineres med et simpelt navn, og repræsenterer en værdi eller en reference til en værdi der er gemt i hukommelsen medens dit program bliver afviklet. Hvis du ikke havde variabler, ville du selv skulle skrive koden til få rettigheder fra operativsystemet til at bruge noget af hukommelsen, koden til at gemme eller hente en binær værdi et givet sted i hukommelsen, samt konvertere den binære værdi til noget du nemt kan bruge i din applikation.
Afhængig af programmeringssprog kan variabler navngives på forskellig måde. I nogen sprog er der ingen forskel på variabelnavne med store og små bogstaver, i nogen sprog må man ikke benytte specialtegn, og i helt gamle sprog er man begrænset i længden af et variabelnavn. De fleste sprog kræver at man først erklærer en variabel inden man kan benytte den, men der er også nogen sprog hvor det ikke er nødvendigt.
Værdien af en variabel skal i nogen sprog defineres til en bestemt type, såsom heltal, decimaltal, tekst eller endda en kompleks type som en liste eller en struktur. I andre sprog finder kompileren selv ud af det.
I et sprog som C# er der eksempelvis forskel på variabler navngivet med store og små bogstaver, alle variabler skal erklæres og tildeles en værdi før brug, og man erklære altid variabler af en konkret variabeltype. Et sådan sprog kaldes for et typestærkt sprog. Det gør det lidt besværligt at arbejde med variabler i sammenligning med typesvage sprog som eksempelvis Python, men det betyder at kompileren bedre kan holde øje med at du ikke lave dumme fejl ved tildeling og aflæsning ligesom den har nemmere ved at optimere koden ved afvikling.
Her er et simpelt eksempel på brug af tre variabler i det typesvage Python sprog:
og her er samme kode i det typestærke C#:
Bemærk forskellen på de to sprog. I Python bruges alle variablerne (a, b og c) uden nogen erklæring og definition overhovedet. I C# skal variablerne ikke bare erklæres, men de skal også erklæres af en speciel type. Python-koden er hurtigt at skrive men det nemt at lave fejl senere i programmet fordi kompileren ikke kan være sikker på hvad der egentlig er opbevaret i variablerne. I C# koden har kompileren helt styr på hvilke variabler du ønsker samt hvilken type og kan der med i langt højere grad advare dig hvis du laver fejl, og optimere programmet på flere måder.
Du skal dog ikke se Python som et sprog der er dårligere eller er væsentlig langsommere end C#. Der er mange måder at optimere typesvage sprog på så de i virkeligheden er lige så hurtige som typesvage sprog. Det handler i højere grad om den sikkerhed det giver at kompileren har bedre muligheder for at følge med i hvad du laver.
Flow
Flow-instruktioner er en del af alle programmeringssprog. De har til formål at styre hvordan en applikation afvikles ved hjælp af forskellige typer af betingelser og løkkestrukturer.
En betingelse er baseret på resultatet af en operation som enten ender i sand (true) eller falsk (false).
Her er et eksempel hvor man i en applikation ønsker at spille plat eller krone:
Hvis spillet skulle implementeres i et visuelt programmeringssprog som Google Blocky kunne det se således ud:
Hvis spillet skulle implementeres i Python, kunne det se således ud:
import random
random_number = random.random()
if random_number < 0.5:
result = "Heads"
else:
result = "Tails"
print(result)
Og her er samme kode i C#:
Random random = new Random();
double random_number = random.NextDouble();
string result;
if (random_number < 0.5)
{
result = "Heads";
}
else
{
result = "Tails";
}
Console.WriteLine(result);
Bemærk de forskellige måder at definere betingelsen – men de ender alle sammen i det samme.
Der findes typisk flere forskellige måder at skrive en betingelse på i de forskellige programmeringssprog – C# har eksempelvis både “if” og “switch” som du skal se senere.
En anden måde at styre flowet i en applikation er løkker, som har til formål at gentage instruktioner for at undgå gentaget kode. Her er en et eksempel på en løkke i en visuel repræsentation:
Koden skaber en tælle-variabel (a) og afvikler en enkelt instruktion 10 gange. For hver gang løkken gennemløbes opskrives tællevariablen med 1.
Samme kode ser således ud i Python:
og her i C#:
Koden benytter en såkaldt While-struktur til at tælle til ti, men de fleste programmeringssprog kan ”loope kode” på mange måde. Her er et andet Python eksempel:
og her i C#:
Så løkker og betingelser er meget vigtige for at styret flow’et i applikationen, og er at finde i alle programmeringssprog.
Prøv det selv: Gæt et tal
Uden nødvendigvis at forstå hele koden kan du prøve at skabe en konsol applikation som følger:
- Opret en ny simpel “Hello World” applikation - se hvordan her.
- Sørg for at koden kan kompilere og afvikles (se førnævnte guide)
- Fjern koden i Program.cs og erstat den med
Random rand = new Random();
int secretNumber = rand.Next(1, 101);
int guess;
Console.WriteLine("Guess a number between 1 and 100");
do
{
Console.Write("Enter your guess: ");
guess = Convert.ToInt32(Console.ReadLine());
if (guess < secretNumber)
{
Console.WriteLine("The number is higher");
}
else if (guess > secretNumber)
{
Console.WriteLine("The number is lower");
}
else
{
Console.WriteLine("You got it right!");
}
} while (guess != secretNumber);
Kompiler og kør applikationen.
Applikationen finder et tilfældigt tal mellem 1 og 100 og anmoder brugeren om at indtaste et gæt. Herefter udskrives om gættet er større eller mindre end det hemmelige tal, og det gentages indtil brugeren gætter tallet.
Bemærk brugen af en betingelse (større, mindre eller lig med) samt løkken rundt det hele.
Husk – den bedste måde at lære at programmere er at gøre det. Også selvom du bare skriver af og mangler lidt forståelse for hvorfor en syntaks netop skal skrives sådan. Det er underordnet. Få skrevet noget kode og lær af fejlene.
Tip
Brug endelig kunstig intelligens til at både skrive og forstå kode. Kopier eventuelt koden til spillet til en GPT AI, og bed den forklare, omskrive eller udvide koden. GPT står for Generative Pretrained Transformer. Det er en type af kunstig intelligens-model, der er trænet med en enorm mængde tekstdata for at generere tekst. I skrivende stund er GTP modeller tilgængelig fra OpenAI (ChatGPT), Microsoft Bing og Google Bard.
Funktioner
En anden måde at undgå gentaget kode og samtidigt gøre koden meget læsbar er brugen af funktioner. I forskellige sprog kaldes funktioner også for metoder, procedurer, eller subrutiner. Begreberne dækker konceptuelt over det samme – at kunne samle instruktioner i en blok for at kunne genbruge koden.
Nogle funktioner udfører blot en samling instruktioner, og andre funktioner kan ses som en matematisk funktion, som returnerer et decideret resultat. Slutteligt kan en funktion (men behøver ikke) tage input den skal bruges til at udføre instruktionerne. Det kaldes typisk parametre.
Her er et eksempel i visuel programmering hvor funktioner MyPrint bruges til at tælle til et givet antal som bestemmes af en parameter kaldet count.
Bemærk at funktionen afvikles (man siger også den kaldes) to gange – først med argumentet 5 og herefter med argumentet 25. Formålet med MyPrint er altså at gøre det nemt at tælle til et givet antal.
Her er samme kode i Python, hvor en funktion defineres med et def-kodeord:
og her i C# som du vi lære senere:
void MyPrint(int count)
{
for (int i = 1; i <= count; i++)
{
Console.WriteLine(i);
}
}
MyPrint(5);
MyPrint(25);
Bemærk, at man i C# bruger void-kodeordet for at fortælle kompileren, at denne funktion (eller nærmere metode, som man kalder det i C#) ikke returnerer nogen værdi. Kodeordet ”void” kan oversættes til ”tom”.
Men man kan også vælge at skabe en funktion som returnerer en værdi der kan ses som et resultat. Et eksempel kunne være en funktion som lægger to tal sammen.
Funktionen AddNumbers kan bruges til at lægge to tal sammen og returnere et resultat.
Samme kode ser således ud i Python:
def AddNumbers(num1, num2):
result = num1 + num2
return result
# Example of use
sum = AddNumbers(5, 5)
print("The sum is:", sum)
Og her i C#:
int AddNumbers(int num1, int num2)
{
int result = num1 + num2;
return result;
}
// Example of use
int sum = AddNumbers(5, 5);
Console.WriteLine("The sum is: " + sum);
Funktioner (eller metoder som det hedder i C#) er et uundværligt værktøj i udviklingen af en applikation fordi det gør det nemt at genbruge funktionalitet.
Fejlhåndtering
Når du afvikler applikationer, vil der altid være risiko for at der sker fejl. Det kan både være fejl som skyldes forkert kode eller at applikationen afvikles i et miljø som i en eller anden form er fejlbehæftet.
Debugging
Begrebet “debugging” i programmering har en interessant historisk oprindelse. Ordet “bug” blev oprindeligt brugt for at beskrive fejl eller defekter i maskineri og udstyr. Den mest berømte anekdote, der forbindes med udtrykkets oprindelse i computerverdenen, handler om datalog og opfinder Grace Hopper. I 1940’erne, mens hun arbejdede på Harvard University’s Mark II-computer, opdagede hendes team en reel fysisk insekt – en møl – fanget i en af relæerne, hvilket forårsagede en fejl i maskinen. De fjernede insektet og noterede hændelsen som “debugging the system”, hvilket bogstaveligt talt betød at fjerne en bug (insekt) fra systemet. Selvom brugen af “bug” for at beskrive fejl i teknisk udstyr eksisterede før denne hændelse, hjalp denne beretning med at popularisere udtrykket “debugging” i forbindelse med fejlfinding og rettelse af problemer i computerprogrammer.
Eksempel på en kodefejl kunne være at “komme til” at dividere et tal med 0 hvilket er matematisk umuligt. Her er lidt C# kode som viser problemet:
Bemærk, at beregningen vil forsøge at dividere 100 med 0, og det vil skabe en fejl.
Fejl behøver ikke nødvendigvis være baseret på kodefejl men kan skyldes fejl i det miljø applikationen afvikles i. Her eksempelvis C# kode der forsøger at læse tekst fra en fil, og hvis den ikke kan findes på disk vil det skabe en fejl:
Udfordringen med sådan en fejl er jo at den ikke nødvendigvis sker på den maskine hvor applikationen bliver udviklet. Problemet kan løses ved at kontrollere om filen findes inden den åbnes, men det løser ikke nødvendigvis alle problemer. Der kunne også ske en fejl hvis filen findes men den bruger applikationen afvikles under ikke har de nødvendige rettigheder.
En fejl hedder i de fleste moderne programmeringssprog en exception, og kan enten være unhandled (ikke håndteret) eller handled (håndteret).
At håndtere en fejl sker typisk ved at prøve noget kode af, og hvis der sker en fejl kan der afvikles noget andet kode. De fleste moderne sprog har en eller anden ”try/catch” struktur til formålet.
I Python ser det eksempelvis således ud:
try:
# try some code
except Exception as ex:
# handle the exception
finally:
# execute code no matter what
I C# er det næste det samme:
try
{
// try some code
}
catch (Exception ex)
{
// handle the exception
}
finally
{
// execute code no matter what
}
Begrebsmæssigt siger man typisk i de fleste moderne sprog at der bliver kastet eller smidt en exception, og at en exception bliver fanget eller håndteret.
Prøv det selv: Applikation der fejler
Uden nødvendigvis at forstå koden kan du prøve at skabe en C# konsol applikation som følger:
- Opret en ny simpel “Hello World” applikation - se hvordan her
- Sørg for at koden kan kompilere og afvikles (se førnævnte guide)
- Fjern koden i Program.cs og erstat den med
Kompiler og kør applikationen.
Bemærk, at applikationen smider en DivideByZeroException fordi koden forsøger at dividere et tal med nul.
Hvis du har lyst kan du prøve at rette koden til følgende:
try
{
int tal1 = 100;
int tal2 = 0;
int res = tal1 / tal2;
}
catch (Exception ex)
{
// Missing log code
Console.WriteLine("Error: " + ex.Message);
}
Nu pakkes koden ind i en try/catch som fanger en eventuel fejl, og i dette eksempel blot udskriver en ”pæn” fejlmeddelelse. Der kan dog tilføjes anden kode som eksempelvis kode til at logge fejl i en fil eller database. Log er typisk en integreret del af fejlhåndtering.
Debugging
Debugging er processen med at finde og rette fejl i en computerprogram. Når du skriver kode, er det næsten uundgåeligt, at der opstår fejl, også kaldet bugs. Debugging hjælper dig med at identificere og løse disse fejl, så dit program fungerer som forventet. For begyndere kan debugging virke skræmmende, men det er en essentiel del af programmeringsprocessen og en værdifuld færdighed at mestre.
Grundlæggende principper
-
Identifikation af fejl: Når dit program ikke fungerer som forventet, skal du først identificere, hvad der går galt. Dette kan være alt fra syntaksfejl, som forhindrer programmet i at køre, til logiske fejl, som får programmet til at opføre sig forkert.
-
Brug af print statements: En simpel metode til at debugge er at bruge print statements (f.eks.
Console.WriteLine
i C#) til at udskrive værdier af variabler på forskellige punkter i koden. Dette kan hjælpe dig med at forstå, hvad der sker i programmet og hvor det går galt.
int number = 10;
Console.WriteLine("Number is: " + number);
number += 5;
Console.WriteLine("Number after addition is: " + number);
-
Sæt breakpoints: I en IDE kan du sætte breakpoints, som stopper programmet midt i eksekveringen på et bestemt sted i koden. Når programmet er stoppet, kan du inspicere værdier af variabler og udføre trin-for-trin eksekvering for at forstå, hvordan koden kører.
-
Trin-for-trin eksekvering: Når programmet er stoppet ved et breakpoint, kan du bruge trin-for-trin eksekvering til at gå gennem koden linje for linje. Dette hjælper dig med at se, præcis hvordan data ændrer sig, og hvor en fejl kan opstå.
-
Inspektion af variabler: Mens du debugger, kan du inspicere variablernes værdier for at sikre, at de indeholder de forventede data. Dette kan hjælpe dig med at opdage, hvis en variabel bliver ændret på en uventet måde.
Eksempel
Lad os sige, at du har en simpel funktion, der skal lægge to tal sammen, men resultatet er ikke som forventet:
int Add(int a, int b)
{
return a - b; // Der er en fejl her - vi skulle bruge + i stedet for -
}
int result = Add(5, 3);
Console.WriteLine("Result: " + result); // Forventet resultat er 8, men vi får 2
For at debugge denne fejl kan du sætte et breakpoint på linjen med return-sætningen og inspicere værdierne af a
og b
. Når du ser, at der bruges -
i stedet for +
, kan du rette fejlen:
int Add(int a, int b)
{
return a + b; // Fejlen er rettet
}
int result = Add(5, 3);
Console.WriteLine("Result: " + result); // Nu får vi det forventede resultat 8
Debugging er en kraftfuld teknik, som alle programmører bør mestre. Det hjælper dig med at forstå din kode bedre, finde og rette fejl mere effektivt, og i sidste ende skrive mere pålidelig software.
Pakkesystemer i softwareudvikling
I moderne softwareudvikling er det sjældent, at en applikation bygges helt fra bunden uden at trække på eksterne ressourcer. Dette er, hvor pakkesystemer kommer ind i billedet. Et pakkesystem er et værktøj, der gør det muligt for udviklere at administrere og integrere eksterne biblioteker og værktøjer i deres projekter. Disse eksterne ressourcer, ofte kaldet “pakker” eller “moduler”, kan indeholde alt fra simple kodebiblioteker til komplekse frameworks.
Pakkesystemer er vigtige af flere årsager:
- Forenkling af afhængigheder: Pakkesystemer automatiserer processen med at hente, installere og opdatere eksterne biblioteker. Dette sikrer, at alle nødvendige afhængigheder er til stede og i de korrekte versioner.
- Versionering: Udviklere kan specificere præcise versioner af pakker, hvilket sikrer kompatibilitet og stabilitet i applikationen.
- Centraliseret opbevaring: De fleste pakkesystemer har et centralt repository, hvor udviklere kan uploade og dele deres pakker.
De mest populære pakkesystemer
- NuGet: Dette er det primære pakkesystem for .NET-udvikling. Det gør det nemt for udviklere at inkludere .NET-biblioteker og værktøjer i deres projekter.
- pip: Dette er pakkesystemet for Python. Med pip kan Python-udviklere nemt installere og administrere biblioteker og værktøjer fra Python Package Index (PyPI).
- npm: Node Package Manager er det mest populære pakkesystem for JavaScript, især for Node.js-udvikling.
- Maven/Gradle: Disse er populære pakkesystemer inden for Java-verdenen, hvor Maven primært fokuserer på livscyklusstyring og Gradle tilbyder en fleksibel byggeautomatisering.
I takt med at softwareudviklingslandskabet fortsætter med at udvikle sig, vil pakkesystemer fortsat spille en afgørende rolle i at sikre, at udviklere kan bygge på andres arbejde, samtidig med at de opretholder konsistens og stabilitet i deres egne projekter.
Programmeringsparadigmer
Programmeringsparadigmer er forskellige tilgange eller stilarter til at skrive kode. De definerer, hvordan programmeringsproblemer tænkes over og løses. Her er nogle af de mest almindelige paradigmer:
Imperativ Programmering
I denne stil beskriver man trin-for-trin, hvad computeren skal gøre. Det er som at give en detaljeret opskrift. De allerførste programmeringssprog var imperativt orienterede.
Eksempel: assembler og C.
Procedural Programmering
Dette er en underkategori af imperativ programmering, hvor der fokuseres på at opdele kode i mindre procedurer eller funktioner. Procedural programmering gør det lettere at organisere og genbruge kode.
Eksempel: COBOL, Pascal, VBA, Java, C#
Deklarativ Programmering
I stedet for at beskrive, hvordan noget skal gøres, beskriver man, hvad man ønsker at opnå, og lader systemet finde ud af, hvordan det gøres. Deklarativ programmering er nyttig i situationer, hvor det er mere vigtigt at beskrive resultatet end processen.
Eksempel: SQL (for databaser) og CSS (for styling af websider)
Objektorienteret Programmering (OOP)
Her grupperes data og funktioner i objekter. Dette paradigme fokuserer på genbrug af kode og modellering af virkelige verdens objekter. OOP understøtter nøglebegreber som arv, polymorfi og indkapsling, hvilket gør det muligt at bygge fleksible og vedligeholdelsesvenlige systemer.
Eksempel: Java, C#
Funktionel Programmering
I denne stil behandles beregninger som en række matematiske funktioner. Det undgår at ændre tilstand og mutable data, hvilket gør funktionel programmering særligt egnet til parallelle og asynkrone applikationer. Funktionelle programmeringssprog understøtter højere ordens funktioner og rekursion som centrale koncepter.
Eksempel: Haskell, Lisp
Logisk Programmering
Dette paradigme er baseret på formel logik. Man beskriver relationer mellem objekter og lader systemet udføre deduktioner. Logisk programmering anvendes ofte i kunstig intelligens og problemløsning, hvor regler og fakta er defineret, og systemet finder svar baseret på disse regler.
Eksempel: Prolog
Hændelsesdrevet Programmering
Her skrives kode, der reagerer på eksterne hændelser eller brugerinput, som ofte bruges i grafiske brugerflader og realtidsapplikationer. Hændelsesdrevet programmering er centralt i udviklingen af interaktive systemer, hvor handlinger udløses af brugerinput, systembegivenheder eller beskeder fra andre applikationer.
Eksempel: JavaScript (i webudvikling), Windows Forms (i C#), Node.js
Asynkron Programmering
Asynkron programmering gør det muligt at udføre operationer, der tager tid (som netværksanmodninger eller filsystemoperationer) uden at blokere hovedprogramflowet. Dette forbedrer applikationens reaktivitet og ydeevne, især i miljøer, hvor mange opgaver skal håndteres samtidigt. Asynkron programmering bruger ofte begreber som callbacks, løfter (promises) og fremtidige (futures) for at håndtere asynkrone operationer. I C# gør async/await det muligt at skrive asynkron kode på en måde, der ligner synkron kode, hvilket gør den lettere at læse og vedligeholde.
Eksempel: Async/await i C# og JavaScript.
Ved at forstå og anvende de forskellige programmeringsparadigmer kan man vælge den mest passende tilgang til forskellige typer af problemer, hvilket fører til mere effektiv og vedligeholdelsesvenlig kode.
Algoritmer
En algoritme kan forstås som en samling instruktioner eller trin til at løse et problem eller udføre en opgave. Vi bruger algoritmer i vores daglige liv, ofte uden at være bevidste om det. Tag for eksempel din morgenrutine, som inkluderer at stå op, børste tænder og spise morgenmad. Hvert trin i denne rutine er en del af en ‘algoritme’ for at starte din dag.
I computerverdenen bliver algoritmer mere komplekse og kræver præcision. De fortæller computeren, hvordan den skal udføre specifikke opgaver. Et enkelt eksempel er processen med at lave en peanut butter sandwich, hvor hvert trin skal beskrives nøjagtigt: åbning af brødposen, tagning af to skiver brød, smøring af peanut butter på den ene skive, og så videre. Hvis instruktionerne ikke er præcise og i den rigtige rækkefølge, vil det resultere i fejl – det samme gælder i computerprogrammering.
Et klassisk eksempel på en algoritme fra den fysiske verden er den måde, man tidligere fandt navne i en telefonbog. I stedet for at gennemgå hver side en efter en (en lineær søgning), kunne man bruge en mere effektiv metode, som at åbne bogen på midten og afgøre, om man skulle søge til venstre eller højre (en form for binær søgning). Denne form for at opdele problemet i mindre dele og løse hver del effektivt er essensen i mange computer algoritmer.
I programmering er præcision afgørende. En computer vil kun udføre de instruktioner, den får, og kan ikke selv rette fejl eller gætte sig til manglende trin. Derfor skal hver detalje i en algoritme være korrekt specificeret. Et andet eksempel på en algoritme i programmering er ‘bubblesort’, hvor tal eller elementer bliver sorteret ved gentagne gange at sammenligne naboelementer og ombytte dem, hvis de er i den forkerte rækkefølge. Denne proces fortsætter, indtil ingen elementer skal ombyttes, og listen er sorteret. Selvom denne metode er simpel, illustrerer den vigtigheden af trinvise processer og præcision i algoritmisk tænkning.
Muligheder i Programmering
Programmering spænder over en bred vifte af applikationer og platforme. Her er nogle af de mest almindelige områder, hvor programmering anvendes.
Konsolapplikationer
Dette er tekstbaserede programmer, der kører i kommandoprompten eller terminalen. De er ofte hurtige at udvikle og bruges til scripts og værktøjer. Eksempel: Bash scripts, Python scripts
Desktopapplikationer
Dette er programmer, der kører på en computers skrivebord. De kan have grafiske brugerflader og udnytte computerens fulde ressourcer. Eksempel: Microsoft Word, Photoshop
Webapplikationer
Programmer, der kører i en webbrowser. De kan tilgås fra enhver enhed med en browser og internetforbindelse. Eksempel: Facebook, Google Docs
Mobilapplikationer
Applikationer designet specifikt til mobile enheder som smartphones og tablets. Eksempel: Instagram, MobilePay
RESTful Services
REST (Representational State Transfer) er en arkitektonisk stil, der definerer et sæt begrænsninger og egenskaber baseret på HTTP. RESTful services, ofte blot kaldet RESTful APIs, er webtjenester, der implementerer REST-principperne.
-
Stateless: Hver anmodning fra en klient til en server skal indeholde alle de oplysninger, der er nødvendige for at forstå og behandle anmodningen. Serveren må ikke gemme kontekstinformation mellem anmodninger.
-
Client-Server: RESTful services følger en client-server model, hvor client og server opererer uafhængigt. Dette adskiller brugergrænsefladen fra dataopbevaring, hvilket gør det muligt at ændre dem uafhængigt af hinanden.
-
Cacheable: Responsdata skal kunne caches på klienten. Dette kan forbedre ydeevnen ved at reducere genanvendelige anmodninger.
-
Uniform Interface: For at forenkle interaktionen mellem klient og server, skal RESTful services have et ensartet interface, som ofte er defineret ved hjælp af standardiserede metoder som GET, POST, PUT og DELETE.
Mikroservices
Mikroservices er en arkitektonisk stil, hvor en applikation er sammensat af små, uafhængige services, der kører i deres egne processer og kommunikerer med letvægtsmekanismer, ofte over HTTP. Disse tjenester er bygget omkring forretningsfunktioner og kan udvikles, implementeres og skaleres uafhængigt.
Microprocessorer og Indlejret Software
Dette er kode, der kører på specialiserede chips eller indlejrede systemer, ofte uden en traditionel OS. Eksempel: Firmware på en router, software i en vaskemaskine
Fjernsyn og Medieafspillere
Software, der driver moderne smart-tv’er og streamingenheder, giver brugerne mulighed for at se indhold og interagere med apps. Eksempel: Netflix-appen på et smart-tv, Roku medieafspiller
Spiludvikling
Udvikling af interaktive spil, der kan spilles på forskellige platforme. Eksempel: Fortnite, Minecraft
Hver af disse muligheder har sine egne udfordringer og krav, men de giver også programmører mulighed for at skabe en bred vifte af spændende og nyttige produkter.
Roller i Softwareudvikling
I softwareudvikling spiller forskellige roller en afgørende rolle for at sikre, at et projekt bliver succesfuldt. Her er en oversigt over nogle af de mest almindelige roller:
Projektleder (PM)
En projektleder (Project Manager - PM) er ansvarlig for at styre projektet fra start til slut. De planlægger, organiserer og overvåger alle aspekter af projektet, herunder tidsplaner, budgetter og ressourcer. PM’en sikrer, at teamet arbejder effektivt og opfylder målene inden for de fastsatte tidsrammer.
Frontend-udvikler
Frontend-udviklere fokuserer på den del af applikationen, som brugerne interagerer med. De arbejder med teknologier som HTML, CSS og JavaScript for at skabe en brugervenlig og æstetisk tiltalende grænseflade. Frontend-udviklere sørger for, at applikationen fungerer godt på forskellige enheder og browsere.
Backend-udvikler
Backend-udviklere arbejder med den server-side logik, der driver applikationen. De udvikler og vedligeholder databaser, servere og applikationslogik ved hjælp af programmeringssprog som C#, Java eller Python. Backend-udviklere sikrer, at data flyder korrekt mellem frontend og backend, og at applikationen er skalerbar og sikker.
UI Designer
UI (User Interface) designere fokuserer på udseendet og følelsen af en applikation. De skaber layout, farveskemaer, typografi og ikoner, der sikrer en sammenhængende og attraktiv brugeroplevelse. UI designere arbejder tæt sammen med frontend-udviklere for at sikre, at designet bliver korrekt implementeret.
UX Designer
UX (User Experience) designere har til opgave at forbedre den samlede brugeroplevelse. De udfører brugerundersøgelser, skaber wireframes og prototyper, og tester applikationens brugervenlighed. UX designere arbejder på at sikre, at applikationen er intuitiv og opfylder brugernes behov og forventninger.
Tester
Testere, også kendt som QA (Quality Assurance) specialister, spiller en vigtig rolle i at sikre, at applikationen er fejlfri og fungerer som forventet. De udvikler og udfører testplaner, herunder enhedstest, integrationstest og brugeraccepttest. Testere arbejder tæt sammen med udviklingsteamet for at identificere og rette fejl, samt sikre at alle krav er opfyldt.
Disse roller arbejder ofte tæt sammen og er afhængige af hinanden for at levere et vellykket softwareprodukt. Hver rolle bidrager med sin unikke ekspertise og perspektiv, hvilket hjælper med at skabe en holistisk og funktionel løsning.
Versionsstyring
Når man arbejder på større projekter - især i teams - er det vigtigt at have en metode til at spore ændringer i koden og samarbejde med andre. Versionsstyringssystemer som Git giver udviklere mulighed for at tage “snapshots” af deres kode, samarbejde med andre og flette ændringer sammen.
Hvad er versionsstyring?
Versionsstyring er en metode til at holde styr på ændringer i dokumenter, programmeringskode og andre samlinger af information. Det giver mulighed for at gendanne tidligere versioner af et projekt, analysere historiske ændringer og samarbejde effektivt i teams. Med versionsstyring kan man undgå konflikter og tab af data, som kan opstå, når flere personer arbejder på det samme projekt samtidig.
Git
Git er et populært distribueret versionsstyringssystem opfundet af Linus Torvalds. Det bruges til at spore ændringer i kildekoden under udvikling. Git giver hver udvikler en fuld kopi af hele historikken for projektet, hvilket muliggør effektiv branching, merging og muligheden for at arbejde offline. Git gør det nemt at arbejde sammen, da man kan flette ændringer fra forskellige udviklere uden at miste noget arbejde.
Læs mere her.
GitHub
GitHub er en webbaseret platform bygget oven på Git, som tilbyder versionsstyring og samarbejdsværktøjer til udviklere. Det giver et grafisk interface, hvor man kan se, dele og samarbejde om projekter. GitHub tilbyder også funktioner som pull requests, issues, og projektstyring, hvilket gør det lettere at administrere og bidrage til open source-projekter. GitHub bruges af millioner af udviklere verden over til at hoste og gennemgå kode, administrere projekter og bygge software sammen.
Azure DevOps
Azure DevOps er en samling af udviklingsværktøjer fra Microsoft, som understøtter hele udviklingscyklussen, fra planlægning til kodning, bygging, testning og deployering. Det inkluderer funktioner som Git-repositories, CI/CD pipelines, boards til projektstyring, og testplanlægning. Azure DevOps integreres problemfrit med andre Microsoft-produkter og -tjenester, hvilket gør det til et kraftfuldt værktøj for teams, der arbejder i et Microsoft-økosystem.
Ved at bruge versionsstyringsværktøjer som Git, platforme som GitHub og integrerede løsninger som Azure DevOps, kan udviklere og teams arbejde mere effektivt og samarbejde bedre, hvilket resulterer i mere pålidelige og veldokumenterede softwareprojekter.
Databaser
Data er hjertet i mange applikationer. At forstå, hvordan man opbevarer, henter og manipulerer data, er afgørende. Databaser som SQL Server, MySQL eller MongoDB giver mulighed for at opbevare data på en struktureret måde og hente dem effektivt gennem forespørgsler. Læs mere her.
Relationsdatabaser
Relationsdatabaser organiserer data i tabeller, der er forbundet gennem relationer. De bruger SQL (Structured Query Language) til at definere og manipulere data. Eksempler på relationsdatabaser inkluderer:
- SQL Server: En relationel databaseudviklet af Microsoft, der understøtter en bred vifte af transaktionsbehandlings-, business intelligence- og analytiske applikationer.
- MySQL: En open source relationsdatabase, der er kendt for sin hastighed og pålidelighed, ofte brugt i webapplikationer og online-tjenester.
- PostgreSQL: En avanceret open source relationsdatabase, der er kendt for sin omfattende support til avancerede datatyper og ydeevneoptimering.
Objektdatabaser
Objektdatabaser gemmer data i form af objekter, som de defineres i objektorienterede programmeringssprog. Dette gør det nemmere at lagre komplekse data strukturer, der matcher de objekter, der bruges i applikationerne. Eksempler på objektdatabaser inkluderer:
- MongoDB: En NoSQL database, der gemmer data i JSON-lignende dokumenter, hvilket giver en fleksibel og skalerbar måde at håndtere data på.
- ObjectDB: En ren Java-database, der er designet til at fungere som en højtydende objektdatabase for Java-applikationer.
Ved at vælge den rette type database og forstå dens styrker og begrænsninger kan man sikre, at dataene opbevares, hentes og manipuleres på den mest effektive måde for den givne applikation.
Docker og containerisering
I takt med at applikationer bliver mere komplekse, bliver behovet for at sikre, at de kører ensartet på tværs af forskellige miljøer, mere presserende. Docker og andre container-teknologier giver udviklere mulighed for at “pakke” deres applikationer sammen med alle deres afhængigheder, hvilket sikrer konsistens uanset, hvor applikationen kører. Læs mere her.
Testning
I enhver softwareudviklingsproces er testning afgørende for at sikre, at softwaren fungerer korrekt og opfylder de specificerede krav. Testning hjælper med at identificere fejl, mangler eller uoverensstemmelser i forhold til de forventede resultater.
-
Unit Tests: Disse tester enkelte dele af koden isoleret fra resten (f.eks. en funktion eller metode). Formålet er at bekræfte, at hver enkelt enhed fungerer som forventet.
-
Integration Tests: Disse tester interaktionen mellem flere enheder eller komponenter for at sikre, at de arbejder godt sammen.
-
End-to-End Tests: Disse tester hele applikationen som en helhed, ofte fra en brugers perspektiv, for at sikre, at hele systemet fungerer som forventet.
-
Continuous Integration (CI): CI refererer til praksis med automatisk at integrere kodeændringer fra flere bidragydere i et softwareprojekt. Hovedideen er at sikre, at nye kodeændringer ikke bryder eksisterende funktionalitet. Dette opnås ved automatisk at køre tests hver gang kode tilføjes eller ændres.
Ressourcer
Der er et hav af ressourcer tilgængelige for at hjælpe dig med at lære at programmere. Her er nogle af de mest populære:
- Bøger: Der er mange gode bøger om programmering, der dækker alt fra grundlæggende koncepter til avancerede emner. Nogle af de mest populære er The Pragmatic Programmer, Code Complete og Clean Code.
- Online kurser: Der er mange online kurser, der dækker en bred vifte af programmeringssprog og emner. Nogle af de mest populære er Codecademy, freeCodeCamp, Udemy og Pluralsight.
- YouTube: Der er mange YouTube-kanaler, der tilbyder gratis programmeringsundervisning. Nogle af de mest populære er freeCodeCamp, Traversy Media, The Coding Train og Programming with Mosh.
- Online Communities: Der er mange online programmeringsfællesskaber, hvor du kan stille spørgsmål og få hjælp. Nogle af de mest populære er Stack Overflow, Reddit og Dev.to.
- Blogs: Der er mange gode blogs om programmering, der dækker en bred vifte af emner. Nogle af de mest populære er DEV, Hacker Noon, CSS-Tricks og Smashing Magazine.
- Podcasts: Der er mange gode podcasts om programmering, der dækker en bred vifte af emner. Nogle af de mest populære er Syntax, CodeNewbie, Software Engineering Daily, CodePen Radio og The Changelog.
- Konferencer: Der er mange programmeringskonferencer, der tilbyder undervisning og netværk. Nogle af de mest populære er Microsoft Build, Google I/O, Apple WWDC, GitHub Universe og CodeMash.
- Hackathons: Hackathons er begivenheder, hvor udviklere samles for at arbejde på projekter og konkurrencer. Nogle af de mest populære er Hack the North, HackMIT, HackRU og HackMIT.
Du kan finde flere ressourcer her.
Tip
Kig på https://www.edx.org/cs50 fra Harvard University. Det er en gratis online introduktion til programmering, der dækker mange af de emner, der er nævnt i denne guide.
Klar til C#
Det var en kort introduktion til nogle af de begreber du vil benytte i alle programmeringssprog, så nu er du klar til at kaste dig over C#.
Appendisk: Mulige interessante spillefilm og dokumentarudsendelser
Her er nogle spillefilm om emnet (jeg har markeret nogle af dem som must see)
-
“WarGames” (1983): En ung mand ved et uheld næsten starter en atomkrig, efter at have hacket sig ind i en militær supercomputer. IMDB Link Filmstriben
-
“Tron” (1982): En computerprogrammør bliver transporteret ind i en digital verden inde i en computer. IMDB Link
-
“Hackers” (1995): Fokuserer på en gruppe unge hackere og deres eventyr, der giver et indblik i den tidlige hackerkultur. IMDB Link
-
“Pirates of Silicon Valley” (1999): Skildrer den tidlige historie bag Apple og Microsoft. IMDB Link
-
“The Social Network” (2010): Fortæller historien om Facebooks skabelse og dens grundlægger, Mark Zuckerberg. IMDB Link
-
“Tron: Legacy” (2010): En opfølger til originalen, der igen bringer helten ind i den digitale verden. IMDB Link
-
“The Imitation Game” (2014): Skildrer livet og arbejdet for Alan Turing, der er kendt for sit arbejde med at bryde den tyske Enigma-kode under Anden Verdenskrig. IMDB Link og Filmstriben
-
“Her” (2013): Skildrer en nær fremtid, hvor kunstig intelligens er avanceret nok til at danne dybe, personlige forhold til mennesker. IMDB Link
-
“Ex Machina” (2014): En provokerende film om kunstig intelligens og dens mulige konsekvenser. IMDB Link
-
“Steve Jobs” (2015): Fokuserer på tre bestemte punkter i Jobs’ karriere, herunder lanceringsbegivenhederne for Macintosh i 1984, NeXT Computer i 1988 og iMac i 1998. IMDB Link
-
“Hidden Figures” (2016): Skildrer de afroamerikanske kvinder, der arbejdede som “menneskelige computere” ved NASA i 1960’erne. IMDB Link
- “Silicon Valley” (2014-2019): Selvom det er en tv-serie og ikke en film, skildrer den livet i en moderne tech-startup i Silicon Valley på en humoristisk og indsigtsfuld måde. IMDB Link
Her er lidt dokumentarudsendelser - de kan sikkert findes rundt på nettet (jeg har markeret nogle af dem som must see)
-
“The Code” (2011): Denne BBC-dokumentarserie udforsker, hvordan matematiske mønstre inspirerer og påvirker vores liv og teknologier. IMDB Link
-
“Transistorized!” (1999): Denne PBS-dokumentar detaljeret beskriver opfindelsen af transistoren og dens indflydelse på teknologien. PBS Link
-
“The Secret Rules of Modern Living: Algorithms” (2015): En BBC-dokumentar, der forklarer algoritmer og hvordan de påvirker vores moderne liv. IMDB Link
-
“The Internet’s Own Boy: The Story of Aaron Swartz” (2014): Dokumentaren omhandler livet og arbejdet hos Aaron Swartz, en programmerer og aktivist, der var medvirkende til at skabe RSS og Reddit. IMDB Link
-
“Silicon Cowboys” (2016): Denne dokumentar fortæller historien om Compaq Computer og dens indflydelse på PC-revolutionen i 1980’erne. IMDB Link
-
“Lo and Behold, Reveries of the Connected World” (2016): En dokumentar af Werner Herzog, der udforsker internettets fortid, nutid og fremtid. IMDB Link
-
“Code: Debugging the Gender Gap” (2015): Dokumentaren fremhæver manglen på kvinder og minoriteter i software engineering. IMDB Link
-
“Revolution OS” (2001): Denne dokumentar skildrer historien om open source-software og Linux. IMDB Link
-
“Inside the Mind of Google” (2009): En CNBC-dokumentar, der ser ind i Google, hvordan det fungerer og dets indflydelse på vores liv. IMDB Link
-
“The Virtual Revolution” (2010): Denne BBC-dokumentarserie undersøger, hvordan internettet har ændret vores liv i løbet af de sidste 20 år. IMDB Link
- 1969 Moon Landing: The Code of the Apollo 11 Guidance Computer (AGC) Super gennemgang af teknikken og koden bag Apollo 11 Guiance Module. Se Pluralsight.
Andre forslag imødeses gerne