(source: pexels.com)

Ofta hör, lär och använder vi termer eller fraser som vi inte helt förstår. Jag tycker att detta är ganska vanligt inom mjukvaruutvecklingsbranschen, oavsett om det handlar om RESTful Web APIs, agil metodik, maskininlärning eller någon annan term. Detta är inte nödvändigtvis något dåligt, men det är viktigt att förstå när man verkligen kan något och när man bara kan namnet på det.

För mig är systemprogrammering en sådan term. Jag vill försöka förklara, med hjälp av ett enkelt språk, vad detta innebär.

För att förstå vad systemprogrammering innebär måste vi först förstå vad ett system är. Programvara tenderar att falla in i ett av två läger, systemprogramvara och tillämpningsprogramvara.

Systemprogramvara är datorprogramvara som är utformad för att tillhandahålla en plattform för annan programvara. Exempel på systemprogramvara är operativsystem, programvara för datavetenskap, spelmotorer, industriell automatisering och programvaror som tjänstetillämpningar.
… Sådan programvara betraktas inte som systemprogramvara när den vanligtvis kan avinstalleras utan att påverka andra programvarors funktion.
– wikipedia.org

Systemprogramvara är en plattform som består av operativsystemets (OS) program och tjänster, inklusive inställningar och preferenser, filbibliotek och funktioner som används för systemtillämpningar. Systemprogramvara omfattar även enhetsdrivrutiner som kör grundläggande datorhårdvara och kringutrustning.
– techopedia.com

Systemprogramvara avser de filer och program som utgör datorns operativsystem. Systemfiler omfattar funktionsbibliotek, systemtjänster, drivrutiner för skrivare och annan maskinvara, systeminställningar och andra konfigurationsfiler. Programmen som ingår i systemprogramvaran är bland annat assemblers, kompilatorer, filhanteringsverktyg, systemverktyg och felsökare.
– techterms.com

Wikipedias definition är mycket vag när det gäller vad som betraktas som systemprogramvara så länge den tillhandahåller tjänster till andra program. De andra två definitionerna fokuserar dock enbart på operativsystemet – drivrutiner, kärnor, bibliotek och funktioner (tänk på kernel/libc-huvudfiler och delade objekt). Detta innebär ett nära förhållande till hårdvara. Om vi tittar på en annan Wikipedia-artikel om systemprogrammering ser vi:

Systemprogrammering kräver en stor grad av medvetenhet om hårdvara.

Artikeln fortsätter med att antyda att en central del av systemprogrammering är behovet av att saker och ting ska vara mycket snabba. Detta är logiskt varför vi skulle behöva veta mycket om hårdvaran. Det är också logiskt att snabbhet (prestanda) skulle vara en central del av systemprogrammering om det är en plattform för annan programvara.

Om den mest centrala delen av din tillämpning (systemprogramvarans ”plattform”) är långsam, så är hela tillämpningen långsam. För många tillämpningar, särskilt i stor skala, skulle detta vara en dealbreaker.

Systemprogramvara i ett nötskal

Citaten ovan och andra resurser har lett mig till följande kriterier för att definiera systemprogramvara:

  • Gör det möjligt för andra programvaror att bygga på en plattform.
  • Gör direkt eller nära gränssnitt mot datorhårdvara för att få nödvändig prestanda och exponera abstraktioner (som en del av plattformen).

Vad är och vad som inte är systemmjukvara

Exempel på vad som är systemmjukvara:

  • OS-kärnor
  • Drivrutiner
  • Bare Metal Hypervisors (e.g. Hyper-V och VM Ware ESXi)
  • Compilatorer (som producerar binärer) och felsökare

Exempel på vad som inte är systemprogramvara:

  • GUI Chattprogram (Slack, Discord, etc)
  • Webbaserat JavaScript-program
  • Webtjänst-API

Du kommer att märka att även om webbtjänst-API:er tillhandahåller en tjänst till andra programvaror, så interagerar de (vanligtvis) inte med hårdvara för att exponera abstraktioner över den. Det finns dock tillämpningar som faller inom en gråzon. De som jag kommer att tänka på är högpresterande datortillämpningar och inbyggd programvara.

Högpresterande datortillämpningar (HPC), t.ex. handel i realtid på börser, exponerar vanligtvis inte en plattform, men det är vanligt att de skriver kod som har ett direkt gränssnitt mot hårdvara. Ett exempel skulle vara att kringgå den nätverksstack som erbjuds av kärnan och implementera sin egen nätverksstack som talar direkt till NIC(s). På detta sätt kan vi se hur HPC-programvara har många likheter med systemmjukvara, genom att den interagerar direkt med maskinvaran för att ge de nödvändiga prestandaförbättringarna.

Embedded software development har också många likheter med systemmjukvara i och med att koden skrivs för att direkt interagera med maskinvaran. Alla abstraktioner som tillhandahålls konsumeras dock vanligtvis av samma programvara och kan inte betraktas som en plattform.

Det är viktigt att notera tillämpningar som har likheter med vår definition av systemmjukvara eftersom du sannolikt kommer att se dessa tillämpningar/jobb beskrivna i dessa termer (systemmjukvara, systemingenjörer, osv.)

Systemprogrammering (+ språk)

(Foto av Roman Spiridonov på Unsplash)

När vi har definierat system kan vi nu definiera systemprogrammering som den handling som består i att bygga upp systemprogramvara med hjälp av systemprogrammeringsspråk. Enkelt nog, eller hur?

Det finns en sak som vi hoppade över, språk. Folk talar ofta om systemprogrammeringsspråk på ett sätt som ”X är bra, det är snabbt, kompilerat och ett systemprogrammeringsspråk”. Men är alla överens om vad ett systemprogrammeringsspråk är?

Med tanke på våra definitioner av system skulle jag definiera kriterierna för ett systemprogrammeringsspråk som följande:

  • Kompilerat till binärfil
  • Kan byggas utan beroende av annan programvara (inklusive en kärna)
  • Prestationsegenskaper som liknar andra systemprogrammeringsspråk

Disclaimer: Detta är min definition. Eftersom det inte finns några fastställda kriterier, härleder jag en definition från vad som är meningsfullt för mig med tanke på det sammanhang i vilket jag har definierat systemprogramvara.

Kompilera till native binär

Om ett språk inte kan kompilera till en körbar fil som är direkt tolkningsbar av CPU:n körs det per definition på en plattform (t.ex. JVM, Ruby VM, Python VM, etc.). Det kan finnas en del argument att ta upp här, men för enkelhetens skull anser jag att detta är ett lämpligt kriterium.

Inga beroenden

Argumentet liknar det att kompilera till en inhemsk binärfil. Om språket alltid kräver att någon annan programvara är närvarande för att kunna köras, så körs det på en plattform. Ett exempel på detta är Go och dess inkluderade standardbibliotek. Det kräver stöd från operativsystemet för att utföra grundläggande åtgärder, t.ex. allokering av minne, skapande av trådar (för goroutiner att köra på), för dess inbyggda nätverkspollare och andra åtgärder. Även om det är möjligt att återimplementera dessa kärnfunktioner skapar det ett hinder för användning i detta sammanhang och det är lätt att föreställa sig varför inte alla språk, även de som kompileras till statiska binärer, är avsedda som systemprogrammeringsspråk.

Samma prestandakaraktäristika

Detta är lite av en undanflykt. Det handlar dock om att säga att inom det system av språk som vanligtvis klassificeras som systemprogrammeringsspråk bör det inte finnas stora (storleksordning) skillnader i prestanda. Med egenskaper syftar jag uttryckligen på exekveringshastighet och minneseffektivitet.

Den gyllene standarden för jämförelser är C och/eller C++, som ofta representeras i jämförande benchmarks, som mäter exekveringshastigheten i hur många storleksordningar långsammare språken är än C/C++.

Namn på några få

De språk som omedelbart kommer att komma i åtanke, med tanke på ovanstående definition, är C och C++. Men det finns också nyare språk som Rust och Nim som också fyller denna nisch. Faktum är att det redan finns ett operativsystem som är skrivet helt och hållet i Rust (RedoxOS) och en kärna i Nim (nimkernel).

Låt oss prata om Go

Tidigare antydde jag att Go kanske inte faller inom familjen ”systemprogrammeringsspråk”. Men precis som att alla applikationer inte passar fint in i applikationsprogramvara och systemprogramvara så gör inte heller språk det.

Ofta kallar folk Go för ett systemprogrammeringsspråk och till och med golang.org citeras som:

Go är ett allmängiltigt språk som är utformat med systemprogrammering i åtanke.

Men inte ens detta är ett direkt påstående om att Go är ett systemprogrammeringsspråk, utan bara att det är utformat med det i åtanke. Jag tycker att det snarare ligger mitt emellan.

Och även om Go kompileras till inhemsk binärfil, innehåller användbara koncept på låg nivå (råa/osäkra pekare, inhemsk typ som bytes och int32, stöd för inline-assemblering) och är relativt kraftfullt, så har det fortfarande en del utmaningar att övervinna. Go levereras med en körtid och en skräpplockare.

En körtid innebär att bootstrapping/overriding av körtiden kommer att krävas för att kunna köras i miljöer utan kärnor. Detta berör mer den interna implementeringen av språket, vilket kan förändras i framtida versioner. Förändringar kräver ytterligare arbete med bootstrapping när språket utvecklas.

En garbage collector (GC) innebär antingen att Go är begränsat i vilka tillämpningsdomäner det kan användas eller att GC måste inaktiveras och ersättas med manuell minneshantering. I det fall GC inte kan ersättas skulle realtidsdomänen (definierad av operationer som måste slutföras inom givna tidsgränser och/eller prestanda mäts i nanosekunder) inte kunna riskera icke-deterministiska paustider för en GC.

Mjukvara för distribuerade system

Med det ökande talet om distribuerade system, och tillämpningar som Kubernetes som blir mycket populära, får vi höra en mängd nya ord som (om vi ska vara ärliga) de flesta av oss inte förstår helt och hållet.

Jag har hittills sett termerna systemprogrammering och systemingenjörer användas i sammanhang där de egentligen menade distribuerad systemprogrammering och distribuerade systemingenjörer.

Vi har definierat systemmjukvara, systemspråk och systemprogrammering i det här inlägget. Men när vi talar om distribuerade system ändras innebörden av system. Och även om jag inte tänker dyka ner i de specifika skillnaderna här (främst för att jag fortfarande behöver förstå dem bättre själv), är det viktigt att vi gör dessa mentala distinktioner och använder ett mer exakt språk när vi kan för att undvika förvirring hos dem som fortfarande lär sig utrymmet.

Articles

Lämna ett svar

Din e-postadress kommer inte publiceras.