image for Hva betyr grønn teknologi, og hva kan vi som utviklere bidra med?

Hva betyr grønn teknologi, og hva kan vi som utviklere bidra med?

Når man tenker på miljø og teknologi, så er det ofte mulighetene teknologi kan bidra med for å redde miljøet som er i fokus. Men teknologi er faktisk også et problem i miljøsammenheng. Teknologi står for mer utslipp enn hele flyindustrien gjør i dag – og mer utslipp enn enkeltland som Storbritannia. Det er estimert at utslippet fra teknologi kommer til å øke fra rundt 4% av det totalet utslippet i dag til 14% innen 2040!

Innenfor teknologi og miljø er det ofte to begreper som brukes, «Greening by IT» og «Greening of IT». Førstnevnte går på hvordan man kan bruke teknologi til å bidra til bedre løsninger i andre industrier for å minke deres utslipp. Sistnevnte ser på hvordan IT innad kan bli mer energieffektiv. Det er dette denne artikkelen skal fokusere på, og spesielt se på hvordan vi som utviklere kan ta konkrete valg i hverdagen for å bidra til mer miljøvennlig teknologi.

Valg av programmeringsspråk

Det har blitt undersøkt hvor energieffektive programmeringsspråk er mot hverandre, og ikke overraskende så er generelt kompilerte språk både mye raskere og energieffektive enn tolket (interpreted) språk – i snitt mer enn dobbelt så effektive. Eksempelvis er C, Rust og C++ helt i toppen med Java hakk i hel, mens Python og Perl ligger i bunn av listen. Kompilerte språk er generelt raskere fordi de konverteres direkte til maskinspråk. I tillegg har flere av de andre språkene funksjonalitet som gjør de tregere under kjøring som C mangler. Eksempler er dynamisk typing, deteksjon av minnelekkasjer og garbarge collection. Det er også verdt å nevne at Python er et såkalt interface språk mot kompilerte språk som C, altså at mange Python pakker er skrevet i kompilerte språk. Som vil si at i praksis vil bruk av disse pakkene totalt bidra til at Python er noe mer effektiv enn det som fremstilles av tabellen.

Se bildet under for fullstendig liste over programmeringsspråkene som ble testet, og hvordan de skårer relativt hverandre. Både energibruk, tid og minne ble analysert, og hvert språk er annotert med c (compiled language), v (virtual language) eller i (interpreted language).

Bildet er hentet fra artikkelen "Energy Efficiency across Programming Languages" av Pereira og co som kan finnes her: https://greenlab.di.uminho.pt/wp-content/uploads/2017/10/sleFinal.pdf

Liten disclaimer: Artikkelen er fra 2017, og endringer kan ha skjedd siden dette. Eksempelvis har det kommet mange oppdateringer med Python som har utviklet effektiviteten, med en forbedring på rundt 15% fra Python 3.6 til 3.12. Men det er likevel en stor forskjell opp til C og de kompilerte språkene. Generelt er det er naturlig å anta at kompilerte språk fremdeles er mer effektive enn virtuelle og interpreted språk - selv om rekkefølgen innad i grupperingene kan varierere noe fra 2017 til i dag.

Hvor grønn er Java "best practices"?

Personlig har jeg jobbet mest med Java de siste fem årene, så jeg har dermed gått litt i dybden på hvordan man kan skrive god og energieffektiv Java-kode. Dette har naturlig nok ført meg til å utforske ulike "best practices" innen Java, som har blitt utviklet nettopp for å øke effeketiviteten i tillegg til å sikre god og standardisert kode. Så hvor mye mer energieffektivt er disse praksisene sammenlignet med alternativer? Dette har faktisk blitt undersøkt i artikkelen "How Green Are Java Best Coding Practices?» av Rocheteau og co. Her skal jeg komme med noen eksempler fra artikkelen.

Int vs Float loop counter

En etablert praksis er å bruke int som loop counter. Siden float er desimaltall kan looping med float føre til avrundingsfeil og uforutsigbare kjøringer. IDE-er som IntelliJ foreslår automatisk looping med int når man starter å skrive "for". Og heldigvis viser det seg at å bruke int gir en relativ energigevinst på 16.32% sammenlignet med float.

// Good
for (int i = 0; i < 5; i++) {
System.out.println("Hello world!");
}
// Bad
for (float i = 0f; i < 5f; i += 1f) {
System.out.println("Hello world!");
}

Vanligste loop betingelse først

Betingelser inni en loop bør sorteres etter hvor vanlig betingelsene er, med mest vanlige betingelse først. Ifølge artikkelen gir dette en energigevinst på 3%.

for (int i = 0; i < 5; i++) {
if (mostCommonCondition(i)){
// Do something
} else if (leastCommonCondition(i)){
// Do something else
} else {
// Do something default
}
}

Artikkelen tar ikke for seg alternative praksiser som for eksempel "Guard Clauses" der målet er å gi exceptions og corner cases tidlig utganger i looper. Dette kan gi mindre nøstet logikk og dermed gjøre koden med lesbar og enklere å vedlikeholde. I og med at energigevinsten er såpass liten ved å bruke vanligste betingelse først er det viktig å vurdere om lesbarhet og vedlikeholdbarhet veier tyngre enn energigevinsten.

Literal initialization

Literal initialization sammenlignet med intialisering av objekter kan gi en ganske høy energigevinst. For de fleste typer som strings, integer og boolean gir dette en gevinst på rundt 90%! Mens for double og float er det minimalt med gevinst, og det argumenteres i artikkelen at det kan være på grunn av JVM optimalisering i bakgrunnen.

// God
String initializeStringLiterally = "abcdfg";
Integer initializeIntegerLiterally = 123;
Double initializeDoubleLiterally = 123.45;
// Bad
String initializeStringByConstructor = new String("abcdfg");
Integer initializeIntegerByConstructor = new Integer(123);
Double initializeDoubleByConstructor = new Double(123.45);

Bruk av primitive sammenlignet med wrappers

Bruk av int og float sammenlignet med deres wrappers gir en energigevinst på 69%. Men her er det være verdt å nevne at Java autoboxer primitive til wrappers i collections, som tar mer energi enn å bruke wrappers i collections i utgangspunktet.

int intValue = 34; // Good
Integer integerValue = 12; // Bad
List<Integer> integerList = List.of(integerValue);
List<Integer> autoboxingIntList = List.of(intValue); // Even worse!

Andre eksempler fra systemutvikling

Det er andre miljøvennlige valg man kan gjøre som utvikler som ikke er Java spesifikt. Eksempler er lazy loading, caching og effektivisering av datastrukturer.

Lazy loading går ut på å laste data når det trengs – i motsetning til eager loading som laster hele ressursen på en gang. Lazy loading kan bidra til bedre ytelse og dermed lavere energibruk i systemet som helhet.

Caching av data som brukes ofte eller som er uendret over lang tid kan både gjøre opplevelsen bedre for brukeren av systemet, i tillegg til å redusere energibruken.

Unødvendig kompliserte datastrukturer tar mye ressurser og dermed energibruk. Lagrer applikasjonen din unødvendig data, eller på unødvendig presist format? Data som ikke gir mening med mer enn to desimaler trenger ikke 16 desimaler – selv om det kan være fristende å lagre «mer enn nok».

For å konkludere er det altså noe vi kan gjøre som utviklere for å ta miljøbevisste valg. Valg av energieffektive programmeringsspråk, effektiv minnehåndtering og ressursbruk er med å redusere den totale energikostnaden. I tillegg viser det seg at "best practices" i Java er mer energieffektive enn alternative implementasjoner. Dette gir Java-utviklere enda et konkret insentiv til å følge beste praksiser – et valg som forbedrer både koden og kloden.

Kilder og forslag til videre lesning: