Demystificeret med en jargonfri udforskning.
Ofte hører, lærer og bruger vi endda udtryk eller sætninger, som vi ikke helt forstår. Jeg synes, at dette er ret almindeligt inden for softwareudviklingsmiljøet, uanset om det er RESTful Web API’er, agil metodologi, maskinlæring eller et andet begreb. Det er ikke nødvendigvis en dårlig ting, men det er vigtigt at forstå, hvornår man virkelig kender noget, og hvornår man bare kender navnet på det.
For mig er systemprogrammering et sådant begreb. Jeg vil gerne forsøge at forklare, ved hjælp af et simpelt sprog, hvad det betyder.
Hvor vi kan forstå, hvad systemprogrammering indebærer, skal vi først forstå, hvad et system er. Software har en tendens til at falde i en af to lejre, nemlig systemsoftware og applikationssoftware.
Systemsoftware er computersoftware, der er designet til at danne en platform for anden software. Eksempler på systemsoftware omfatter operativsystemer, datalogisk software, spilmotorer, industriel automatisering og software as a service-applikationer.
… En sådan software betragtes ikke som systemsoftware, når den normalt kan afinstalleres uden at påvirke funktionen af anden software.
– wikipedia.orgSystemsoftware er en platform, der består af operativsystemets (OS) programmer og tjenester, herunder indstillinger og præferencer, filbiblioteker og funktioner, der anvendes til systemapplikationer. Systemsoftware omfatter også enhedsdrivere, der kører grundlæggende computerhardware og periferiudstyr. – techopedia.com
Systemsoftware henviser til de filer og programmer, der udgør computerens operativsystem. Systemfiler omfatter biblioteker med funktioner, systemtjenester, drivere til printere og andet hardware, systempræferencer og andre konfigurationsfiler. De programmer, der er en del af systemsoftwaren, omfatter assemblere, kompilatorer, filhåndteringsværktøjer, systemværktøjer og debuggere.
– techterms.com
Wikipedia-definitionen er meget vag med hensyn til, hvad der betragtes som systemsoftware, så længe det leverer tjenester til andre programmer. De to andre definitioner fokuserer imidlertid udelukkende på styresystemet – drivere, kerner, biblioteker og funktioner (tænk på kernel/libc-headerfiler og delte objekter). Dette indebærer et tæt forhold til hardware. Hvis vi ser på en anden Wikipedia-artikel om systemprogrammering, ser vi:
Systemprogrammering kræver en stor grad af hardwarebevidsthed.
Artiklen fortsætter med at antyde, at en central del af systemprogrammering er behovet for, at tingene skal være meget hurtige. Det giver mening, hvorfor vi har brug for at vide en masse om hardwaren. Det giver også mening, at hastighed (ydeevne) ville være en central del af systemprogrammering, hvis det er en platform til anden software.
Hvis den mest centrale del af din applikation (systemsoftware-“platformen”) er langsom, så er hele applikationen langsom. For mange applikationer, især i stor skala, vil dette være en deal-breaker.
Systemsoftware i en nøddeskal
Overstående citater og andre ressourcer har ført mig til følgende kriterier til at definere systemsoftware:
- Giver en platform for anden software, der kan bygges på.
- Er direkte eller tæt forbundet med computerhardware for at opnå den nødvendige ydeevne og eksponere abstraktioner (som en del af platformen).
Hvad er og hvad der ikke er systemsoftware
Eksempler på, hvad der er systemsoftware:
- OS Kernels
- Drivere
- Bare Metal Hypervisors (f.eks.g. Hyper-V og VM Ware ESXi)
- Compilere (der producerer native binære filer) og debuggere
Eksempler på, hvad der ikke er systemsoftware:
- GUI Chatprogram (Slack, Discord osv.)
- Webbaseret JavaScript-program
- Webtjeneste-API
Du vil bemærke, at webtjeneste-API’er leverer en tjeneste til anden software, men at de (typisk) ikke interagerer med hardware for at udsætte abstraktioner over den. Der er dog applikationer, der falder inden for en mellemliggende gråzone. De, der falder mig ind, er high performance computing-applikationer og indlejret software.
High performance computing (HPC)-applikationer, som f.eks. realtidshandel på børser, eksponerer typisk ikke en platform, men det er almindeligt, at de skriver kode, der har direkte grænseflader til hardware. Et eksempel herpå er at omgå den netværksstack, der tilbydes af kernen, og implementere deres egen netværksstack, der taler direkte til NIC’en eller NIC’erne. På denne måde kan vi se, hvordan HPC-software har mange ligheder med systemsoftware, idet den interagerer direkte med hardware for at give de nødvendige ydelsesforbedringer.
Embedded softwareudvikling har også mange ligheder med systemsoftware, idet der skrives kode, der har direkte grænseflade med hardware. Eventuelle abstraktioner, der leveres, forbruges dog typisk af den samme software og kan ikke betragtes som en platform.
Det er vigtigt at bemærke applikationer, der deler ligheder med vores definition af systemsoftware, da du sandsynligvis vil se disse applikationer/jobs beskrevet i disse termer (systemsoftware, systemingeniører osv.)
Systemprogrammering (+ sprog)
Når vi har defineret systemer, kan vi nu definere systemprogrammering som den handling, der består i at opbygge systemsoftware ved hjælp af systemprogrammeringssprog. Simpelt nok, ikke sandt?
Der er dog en ting, vi sprang over, nemlig sprog. Folk taler ofte om systemprogrammeringssprog på en måde som “X er fantastisk, det er hurtigt, kompileret og et systemprogrammeringssprog”. Men er alle enige om, hvad et systemprogrammeringssprog er?
Givet vores definitioner af systemer vil jeg definere kriterierne for et systemprogrammeringssprog til at være:
- Kompileret til native binary
- Kan bygges uden afhængighed af anden software (herunder en kerne)
- Præstationsegenskaber svarende til andre systemprogrammeringssprog
Disclaimer: Dette er min definition. Da der ikke findes nogen faste kriterier, udleder jeg en definition fra det, der giver mening for mig i den sammenhæng, hvori jeg har defineret systemsoftware.
Kompilér til native binær
Hvis et sprog ikke kan kompilere til en eksekverbar fil, der kan fortolkes direkte af CPU’en, så kører det pr. definition på en platform (f.eks. JVM, Ruby VM, Python VM osv.). Der kan være nogle argumenter her, men for enkelhedens skyld mener jeg, at dette er et passende kriterium.
Ingen afhængigheder
Argumentet svarer til at kompilere til en native binary. Hvis sproget altid kræver, at der er noget andet software til stede for at kunne afvikles, så kører det på en platform. Et eksempel på dette er Go og dets medfølgende standardbibliotek. Det kræver støtte fra operativsystemet for at udføre grundlæggende handlinger som f.eks. allokering af hukommelse, spawning af tråde (for goroutiner til at køre på), for dets indbyggede netværksafspørger og andre handlinger. Selv om det er muligt at genimplementere disse kernefunktioner, skaber det en barriere for brugen i denne sammenhæng, og det er let at forestille sig, hvorfor ikke alle sprog, selv dem, der kompileres til statiske binære filer, er beregnet som systemprogrammeringssprog.
Sammenlignende præstationskarakteristika
Dette er lidt af en undskyldning. Den går dog ud på at sige, at inden for det system af sprog, der typisk klassificeres som systemprogrammeringssprog, bør der ikke være store (størrelsesorden) forskelle i præstationsegenskaber. Med egenskaber henviser jeg udtrykkeligt til udførelseshastighed og hukommelseseffektivitet.
Den gyldne standard for sammenligning er C og/eller C++, som ofte er repræsenteret i sammenlignende benchmarks, der måler udførelseshastighed i hvor mange størrelsesordener langsommere sprog er end C/C++.
Nævn et par stykker
De sprog, der umiddelbart falder mig ind, givet ovenstående definition, er C og C++. Men der er også nyere sprog som Rust og Nim, som også udfylder denne niche. Faktisk findes der allerede et operativsystem, der er skrevet udelukkende i Rust (RedoxOS) og en kerne i Nim (nimkernel).
Lad os tale om Go
Tidligere antydede jeg, at Go måske ikke falder inden for familien af “systemprogrammeringssprog”. Men ligesom ikke alle applikationer passer fint ind i applikationssoftware og systemsoftware, gør sprog det heller ikke.
Ofte vil folk kalde Go for et systemprogrammeringssprog, og selv golang.org er citeret som:
Go er et alment sprog designet med systemprogrammering for øje.
Men selv dette er ikke en direkte påstand om, at Go er et systemprogrammeringssprog, blot at det er designet med det for øje. Jeg synes, at det snarere ligger midt imellem.
Selv om Go kompilerer til native binære filer, indeholder nyttige koncepter på lavt niveau (rå/usikre pointere, native typer som bytes og int32 og inline assembly-understøttelse), og det er forholdsvis performent, har det stadig nogle udfordringer, som det skal overvinde. Go leveres med en runtime og en garbage collector.
En runtime betyder, at bootstrapping/overriding af runtime vil være nødvendig for at køre i miljøer uden kerner. Dette kommer mere ind på den interne implementering af sproget, som kan ændre sig i fremtidige udgivelser. Ændringer kræver yderligere bootstrapping-arbejde, efterhånden som sproget udvikler sig.
En garbage collector (GC) betyder enten, at Go er begrænset i hvilke applikationsdomæner det kan bruges, eller at GC’en skal deaktiveres og erstattes med manuel hukommelsesstyring. I det tilfælde, at GC ikke kan erstattes, vil realtidsdomænet (defineret af operationer, der skal afsluttes inden for givne tidsgrænser og/eller ydelsen måles i nanosekunder) ikke kunne risikere ikke-deterministiske pausetider for en GC.
Software til distribuerede systemer
Med den stigende snak om distribuerede systemer, og applikationer som Kubernetes, der bliver meget populære, får vi en masse nyt ordforråd at høre, som (hvis vi skal være ærlige) de fleste af os ikke helt forstår.
Hertil har jeg set udtrykkene systemprogrammering og systemingeniører blive brugt i sammenhænge, hvor det, de i virkeligheden betød, var distribueret systemprogrammering og distribuerede systemingeniører.
Vi har defineret systemsoftware, systemsprog og systemprogrammering i dette indlæg. Men når vi taler om distribuerede systemer, ændrer betydningen af system sig. Og selv om jeg ikke vil dykke ned i de specifikke forskelle her (primært fordi jeg stadig selv har brug for at forstå dem bedre), er det vigtigt, at vi foretager disse mentale sondringer og bruger mere præcis tale, når vi kan, for at undgå forvirring hos dem, der stadig er ved at lære området at kende.