Cadec 2025 Göteborg

2025-01-29

Cadec 2025 Göteborg

Konferensen för utvecklare som vill utvecklas

Länk till utvärderingen Cadec Göteborg 2025

Cadec-appen

Ladda ner Cadec-appen, där kan du ställa frågor till talarna under konferensen. Välj någon av länkarna nedan.

Om Cadec 2025

Boka in onsdagen den 29:e januari 2025 – då går Cadec av stapeln i Göteborg. Missa inte chansen att få en rivstart på det nya året med ett inspirerande kunskapslyft. Vi kan utlova ett fullspäckat program med både bredd och djup, och som vanligt handlar föredragen om de senaste trenderna inom arkitektur och utveckling.

Här kan du se det kompletta programmet.

Vi håller till på Filmstaden Bergakungen där vi kan erbjuda en presentationsupplevelse utöver det vanliga. Vi ser fram emot att återigen få träffa alla deltagare personligen.

Det blir naturligtvis också After Cadec på vårt kontor där vi kan varva ner efter konferensen med mat, dryck och mingel. En separat inbjudan till After Cadec kommer vid ett senare tillfälle.

Konferensen är kostnadsfri.

Länk till anmälan Göteborg

Tid: onsdag 29:e januari 2025 kl 13.00 till 17.00

Plats: Filmstaden Bergakungen, Skånegatan 16 B, Göteborg

After Cadec: på Callistas kontor, direkt efter konferensen. Separat inbjudan kommer senare.

Välkommen!

önskar teamet på Callista

Presentationer på YouTube

Alla presentationer från årets Cadec finns i denna spellista (se Callistas YouTube-kanal för presentationer från tidgare år)

Presentationer

Callista medarbetare Patrik Blommaskog

Köra stora språkmodeller lokalt – hur gör man och vad får man?

Patrik Blommaskog

Sedan ChatGPT släpptes till allmänheten för två år sedan så har bruket av stora språkmodeller, LLM:er, blivit vardagsmat för de flesta av oss. Genom olika förpackningar använder vi dem för personligt bruk, som arbetsredskap, och ibland som aktiva delar av produkter och tjänster.

Idag finns det många modeller som går att köra på egna datorer utan att man behöver anförtro sig till leverantörer i molnet. Det är ett snabbt framåtskridande område där man ständigt lyckas klämma in bättre prestanda och mer funktionalitet i hårdvara som fortsätter att bli både billigare och kraftfullare.

Men - man klämmer knappast in ett helt moln i en laptop utan kompromisser. I detta föredrag tittar vi på vad det innebär att köra en språkmodell lokalt. När och varför skulle man vilja välja en lokal modell framför en molnbaserad kommersiell dito? Vi tittar på modellval, anpassningar, egna erfarenheter, och andra saker att ta i beaktande när man väljer och arbetar med sina modeller. Under presentationen kommer vi att använda modellerna både som utvecklingsverktyg och som lösningskomponent..




Frågor och svar

Med immutability kan du köra samma fråga två gånger och alltid förvänta dig samma svar?

Ja, genom att seeda slumpgeneratorn i sin förfrågan mot modellen genom parametern “seed”. Det sägs att man inte kan förlita sig på att man får samma svar, speciellt med högre temperatur, men de gånger jag har provat så har det fungerat fläckfritt. I Ollamas chat kan man sätta parametern såhär:

/set parameter seed 123

Får man använda modellerna i kommersiellt syfte?

Jag är inte juridiskt bevandrad så ta mina ord med en hälsosam nypa försiktighet. Med det sagt så ja, som jag läst dem verkar de stora kända modellerna ha väldigt tillåtande licensvillkor för kommersiellt bruk. Det finns dock lite finstilt att läsa. Llama 3.3 slutar t.ex. vara fritt tillåten om man har över 700 miljoner användare per månad, och även om den är tillåten för kommersiellt bruk så har de en lång lista av användningsområden man inte får använda den inom.

Kan man ge utförligare information hur verktygen kan/får användas i bakgrunsdsprompten?

Javisst! Det är en interaktion mellan modellen, vad man skriver i systemmeddelandet, i promten, och hur man beskriver verktygen. Jag belyste inte det på presentationen, men om man tittar på videon så kan man se ett stycke där jag försöker styra verktygsinteraktionen i systemmeddelandet. Med begränsad framgång får väl erkännas. Min erfarenhet är att interaktionen kan vara bångstyrig att kontrollera, och att det antagligen är en färdighet som faller under det populära uttrycket “prompt engineering”.

Hur funkar det att köra modeller som är större än ett grafikkorts VRAM, dvs dela upp modellen på flera grafikkort och även i RAM? Vad får det för påverkan på prestanda?

Ollama är bra på att dela upp modeller så att det som inte får plats i VRAM hamnar i vanligt RAM och drivs av CPU:n. Det är tekniskt helt transparent för användaren men så fort man passerar en sådan här minnesgräns så flyger prestanda ut genom fönstret. Det finns en aktiv community kring att koppla ihop flera grafikkort. Då får man mer VRAM att stoppa modellen i, men fortfarande ett litet minneshopp som verkar kosta en hel del prestanda. I det här fallet kan man dock utnyttja resurserna genom att parallellisera flera inferens-sessioner. Då kan varje session få en viss hastighet medan den totala genomströmningen blir högre.

Bonus: Stig Vildmarks Hawaiipizza

För den hungrige följer här receptet på Stig Vildmarks Hawaiipizza. Skicka gärna en bild ifall du bakar den.

A pineapple pizza recipe using European measurements

Here’s a recipe for a delicious pineapple pizza using European measurements:

Ingredients:

  • 500g strong white flour
  • 10g salt
  • 15g sugar
  • 20g active dry yeast
  • 350ml lukewarm water
  • 50g extra virgin olive oil
  • 200g tomato sauce (homemade or store-bought)
  • 150g mozzarella cheese, shredded
  • 120g ham or other cured meats (optional)
  • 80g pineapple chunks (fresh or canned in juice)
  • Fresh basil leaves, chopped (optional)

Instructions:

  1. In a large mixing bowl, combine the flour, salt, sugar, and yeast.
  2. Gradually add the lukewarm water to the dry ingredients and mix until a dough forms.
  3. Add the olive oil and continue kneading the dough for 5-10 minutes until it becomes smooth and elastic.
  4. Place the dough in a lightly oiled bowl, cover it with plastic wrap or a damp cloth, and let it rise in a warm place for about 1 hour, or until it has doubled in size.
  5. Preheat your oven to 220°C (425°F) with a baking stone or baking sheet inside.
  6. Punch down the dough and shape it into a circle or rectangle, depending on your preference.
  7. Transfer the dough to a lightly floured surface or a piece of parchment paper.
  8. Spread the tomato sauce over the dough, leaving a 1-2 cm border around the edges.
  9. Sprinkle the mozzarella cheese evenly over the sauce.
  10. Add the ham or other cured meats, if using.
  11. Arrange the pineapple chunks on top of the cheese and meats.
  12. Bake the pizza in the preheated oven for 15-20 minutes, or until the crust is golden brown and the cheese is melted and bubbly.
  13. Remove the pizza from the oven and sprinkle with chopped fresh basil leaves, if desired.
  14. Slice the pizza into wedges and serve hot. Note: European measurements are often more precise than US measurements, so you may need to adjust the quantities of ingredients based on your personal preference for texture and flavor.
Ladda ner presentation
Callista medarbetare Jesper Holmberg

Structured Concurrency för enklare multitrådad programmering

Jesper Holmberg

Structured Concurrency är ett stöd för utvecklare att skriva multitrådad kod som är korrekt och enkel att resonera kring. Exekveringstrådar är resurser som måste hanteras på ett strukturerat sätt, på samma sätt som filer, nätverkskopplingar eller andra potentiellt dyra resurser. Med structured concurrency får utvecklaren hjälp att hantera den komplexitet som en multitrådad lösning innebär, och inte tappa bort skapade resurser.

Structured Concurrency är ett begrepp som började uppmärksammas för 5-6 år sedan och bland annat influerade designen av Kotlins coroutines. Därefter har det använts i populära bibliotek för Python och andra språk, och är sedan några år inlemmat i Swift. I Java finns nu Structured Concurrency som en naturlig överbyggnad på Project Looms virtuella trådar.

I den här presentationen tittar vi på vad Structured Concurreny egentligen innebär, och illustrerar med exempel från några olika programmeringsspråk.




Frågor och svar

Kan Javas implementation av Structured Concurrency också ha executors/thread pools?

Structured Concurrency använder sig av virtuella trådar, så behovet av en trådpool faller bort. Scope-objektet som används i Structured Concurrency ersätter behovet av executors eller andra synkroniseringsmekanismer.

Tror du att Structured Concurrency kommer att ersätta alla andra konstruktioner för concurrency i de språk där det finns?

Jag tror att Structured Concurrency är en så lättarbetad och kraftfull konstruktion att den har goda möjligheter att ersätta äldre modeller; den minskar komplexiteten och erbjuder ett mer lättarbetat verktyg. Dock tenderar äldre lösningar att leva kvar länge, det vet alla som jobbat med utveckling.

I Javas implementation, kan man se hierarkin utifrån om man inspekterar jvm:en?

Ja, existerande verktyg som t.ex. jcmd Thread.dump_to_file eller MXBean-API:et visar nu den hierarkiska relationen mellan trådar som startats med structured concurrency.

Hur kan Structured Concurrency användas för att lösa deadlock-problem som t.ex. “the dining philosophers problem”?

Scoped values gör det enklare att inte oavsiktligt dela på data mellan trådar. Däremot, om en lösning kräver delning av muterbart data, erbjuder Structured Concurrency i sig ingen direkt lösning på den aspekten av multitrådad programmering.

Om man jämför med t.ex. iterations-konstruktioner i alla språk, varför kan vi inte ha en universell standard för att handskas med multitrådad programmering, som t.ex. Async/Await?

Structured Concurrency har nog goda förutsättningar att bli ett standardverktyg i nästan alla moderna språk, även om namnsättning och implementationsdetaljer kommer att skilja sig från språk till språk. Async/await kan hantera samtidighet men saknar automatisk hantering av resurser och fel (exceptions) som Structured Concurrency erbjuder.

Ladda ner presentation
Callista medarbetare Peter Larsson

Säkra modulära applikationer i backend med WebAssembly och WASI

Peter Larsson

WebAssembly System Interface WASI-Preview 2 släpptes i början av 2024 och möjliggör utveckling av säkra, snabba och modulära applikationer på serversidan. Med stöd för Garbage Collection, Exceptions och trådar är det enklare att använda exempelvis JVMbaserade språk. Komponentmodellen möjliggör strukturerade monoliter med isolerade moduler som till stora delar möter arkitektmålen för mikrotjänster, och med ett utbrett stöd för att exekvera i lövtunna (OCI) containers.

Presentationen redovisar varför WASM är en viktig standardiserad teknik att bevaka, hur nuläget ser ut och vad vägen framåt bär med sig. Dessutom demonstreras hur man utvecklar och kör WASM tillämpningar där komponenterna kan vara skrivna i olika språk.




Frågor och svar

Är det relevant med scale to zero för WebAssembly och hur kan det göras?

Absolut, WASM är mycket lättviktigt och blir i princip lika effektivt som Java med CRaC eller en Go-binär etc.

Go och Kotlin har ju GC och går att köra i WASM, varför inte Java?

Språk som Go och Python bäddar in sin egen “runtime” i WASM-binären. Det innebär att GC körs på applikationsnivå och inte i den virtuella maskinen. JVM-språk förlitar sig däremot mer på att VM:en hanterar GC, och för komponentmodellen är detta inte på plats förrän i Preview 3 av WASI. Kotlin har en “GC light” för WASM, men i nuläget stöds enbart Preview 1, vilket innebär att komponentmodellen och WIT inte är inkluderade.

Are WIT files just WASM interfaces that expose the underlying code?

Nja, det är mer än så. WIT är ett språk för att beskriva interface/kontrakt med datatyper. Det handlar om de förmågor en komponent dels erbjuder och dels behöver för att göra sitt jobb. En WASM-komponent har hela sin WIT (värld) inbäddad och kan användas för att generera språkbindningar samt inspektera förmågor (kan den köra främmande kod, koppla upp sig på nätet, läsa/skriva från/till filsystem etc.).

GraalVM borde ganska enkelt kunna kompilera till WASM istället för native, är det något som är på gång?

Ja, det har diskuterats men prioriterats ned, främst på grund av avsaknad av GC. Se även denna diskussion.

Skulle alla de sårbarheter du listade verkligen kunnat undvikas om applikationerna var byggda med WASM?

De flesta hade åtminstone kunnat begränsas väsentligt. Vissa delar av en applikation kan fortfarande upphöra att fungera, men utan de drastiska effekter som kan uppstå när främmande kod tillåts exekveras med administrativa rättigheter.

Felhantering, typ NPE i WASM-körning?

NPE finns inte i WASM på samma sätt som i Java. Man har helt enkelt inga pekare, vare sig till funktioner eller data. Om något refereras utanför tillåtet område resulterar det i en “runtime trap” (error).

Hur kan prestanda vara så bra? Man kör ju på en VM, det borde bli betydligt långsammare än native?

Ja, det är “near-native performance”, det vill säga inte exakt lika snabbt som native men mycket nära.

Does this enable shared libraries over language boundaries? If so, do you think it can serve as a new lib standard instead of C libraries?

Absolut.

Varför skulle man föredra WASI över snabbare native-kodbaserade alternativ?

Lättviktighet, säkerhet och portabilitet är det korta svaret.

Is WebAssembly an official language of the web?

Ja.

Won’t we have the same issues with trusting random people making cool open source packages that we include and use willy-nilly in our WASM projects?

Ja, men skillnaden är att man väldigt enkelt och “automatiserat” kan identifiera den potentiella skada en WASM-modul kan åstadkomma.

Hur är utvecklarupplevelsen för ett sådant här projekt? Compile-Test-Debug etc.?

Ganska undermålig om man inte använder TinyGo eller Rust (kanske finns fler alternativ).

Varför går utvecklingen av detta så långsamt?

Normalt tar det omkring 10 år att utveckla nya features för programmeringsspråk och plattformar. Än så länge är utvecklingstakten förväntad. Se på Java, där man lärt sig av tidigare misstag och numera tar varje ny konstruktion (lambda, pattern matching, virtuella trådar etc.) cirka 10 år innan den är färdigställd.

Vi har redan JVM, varför ska vi använda WASM istället?

JVM fungerar bra för långkörande tillämpningar men är extremt minneskrävande och långsamt att starta upp (olämpligt för scale to zero). Den stora fördelen med WASM är modulära, säkra och polyglota applikationer. På VM-nivå går det inte riktigt att jämföra JVM med WASM – WASM är en VM-plattform med en virtuell CPU, medan JVM snarare är en runtime för Java-bytecode.

Has WASM security model implementations been found to have defects?

Nja, inte i sig själv, men runtime-implementationerna (exempelvis Wasmtime och WasmEdge) kan exponera sårbarheter.

Vad skiljer olika Docker WASM-runtimes åt?

Det är konkurrerande produkter och projekt. Jämför med olika JavaScript- eller Java (JVM)-implementationer.

Ladda ner presentation
Callista medarbetare Björn Beskow

Domänen i fokus, Portar, Adaptrar och Hexagonal Arkitektur

Björn Beskow

Den till synes oundvikliga komplexiteten som plågar de flesta mjukvaruprojekt kommer ofta från beroenden mellan delar av lösningen, beroenden som över tid blir ohanterliga och leder till “legacy” (även känt som “big ball of mud”). Arkitekturarbetets kanske viktigaste uppgift är som bekant att bromsa denna ökande “mjukvaru-entropi” genom att begränsa och kontrollera beroenden med hjälp av abstraktioner, lagerindelning och arkitekturella principer som t.ex SOLID. De allra mest stabila och värdefulla delarna i en mjukvarulösning är de som också är viktigast att skydda mot osunda beroenden: domänen eller kärnverksamhetens regler och beteende.

Ironiskt nog kan en traditionell, “endimensionell” lager-indelning motverka detta syfte, genom att premiera det “understa” lagret. Det är skälet till att man i DDD-lägret allt oftare pratar om en annan, “flerdimensionell” lagerindelnig med domänen i centrum, omgiven av “portar” och “adaptrar” i en lökskalsmodell med det något kryptiska namnet Hexagonal Arkitektur.

I den här presentationen tittar vi närmare på denna arkitekturella stil, och finner ett användbart verktyg i DDD-arkitektens verktygslåda med (i vanlig ordning) ett antal avigsidor.




Frågor och svar

Bör man separera lager i olika projekt i samma lösning eller räcker det med folder struktur och överenskommelser inom team?

Varför inte separera domänlogiken helt som en egen tjänst?

Modularisering kan ju göras på olika sätt, från deploy/runtime-separation (olika processer), buildtime-separation (olika projekt och bygg-artefakter) till de modulariserings-mekanismer som ens programmerings-språk/plattform erbjuder (paket, namespace etc.). Det viktiga är att lager-indelningen/modulariseringen och de principer som styr den upprättas och efterlevs. ArchUnit och liknande verktyg ger bra stöd för att säkerställa att reglerna följs.

Hur ska man göra en avvägning för att undvika att man måste in i mängder med lager när man tex lägger till ett attribut? Jämför tex med hur Ruby on Rails tacklar detta.

Betyder detta att man lätt behöver duplicera dataklasser i varje lager för mappningen?

Abstraktion och strikt lager-indelning har absolut ett pris: “Samma” information kan behöva representeras i flera (och ibland samtliga) lager, och kod behöver skrivas och underhållas för att transformera/mappa mellan dem. Poängen med separationen är ju dock att det som initialt är “samma” över tid kan utvecklas åt olika håll och i olika takt. När så sker, ger abstraktionen/separationen sitt värde, innan dess innebär den bara merarbete. Därmed är denna arkitekturstil inte kostnadseffektiv för alla tillämpningar (som t.ex. enkla CRUD/register-vårds-applikationer eller stödtjänster utanför kärnverksamheten där man kan tänka sig att slänga och bygga/köpa nytt efter hand). För de tillämpningar som utgör kärnverksamheten (som måste kunna förvaltas och vidareutvecklas över lång tid) är abstraktionen/separationen däremot kritisk, och den extra ansträngning som transformation mellan separata representationer väl värd sitt pris. Moderna mappningsverktyg som t.ex. MapStruct eller JMapper kan med fördel användas för att minimera ansträngningen och komplexiteten.

Blir det fler lager med Hexagonal Arkitektur?

Det blir inte fler lager, men ansvarsgränserna mellan lagren blir tydligare i och med att explicita portar och adaptrar separerar dem.

Ladda ner presentation
Callista medarbetare Stephen White

Local-first – välkommen till en värld av responsiva appar som samarbetar sömlöst utan API:er

Stephen White

Föreställ dig för ett ögonblick en värld utan spinners – där appar startar omedelbart, samarbetet med kollegor sker utan avbrott, innehållet delas och synkroniseras sömlöst mellan enheter och där nätverkshastigheten aldrig sätter gränser.

Denna vision kan nu förverkligas. Välkommen till local-first-världen.

I den här presentationen utforskar vi hur local-first blir verklighet – från smarta lagringsstrategier och effektiva synkroniseringsmönster till den snabbt växande mängden bibliotek och ramverk som driver utvecklingen framåt. Vi visar också hur dessa principer kan omsättas i praktiken, med Cadec-appen som ett konkret exempel.




Frågor och svar

Which types of apps are appropriate for local-first?

Productivity applications with real-time collaboration, such as note-taking apps, task managers, and calendars, are prime candidates for a local-first design. These tools need to function seamlessly offline, ensuring users can capture ideas, manage schedules, or update tasks without interruption. For example, Figma and Excalidraw demonstrate how local data storage, combined with Conflict-Free Replicated Data Types (CRDTs), enables real-time collaboration. Users can edit documents simultaneously, even offline, with changes stored locally and synced later—eliminating the “spinners” and delays common in cloud-dependent apps.

Local-first architecture is also well-suited for privacy-sensitive domains like finance and healthcare. Apps can store budgeting sensitive data locally, encrypting it before optionally syncing with the cloud. This ensures users retain full control over their data while still benefiting from cross-device access.

However, local-first is not always the right choice. Applications requiring real-time server validation—such as banking transactions, stock trading, or multiplayer gaming—still rely on centralized systems to ensure atomicity and consistency.

What are good patterns/strategies for handling conflicts when synchronizing local data with the backend?

For local-first applications, Conflict-Free Replicated Data Types (CRDTs) and libraries like PowerSync handle synchronization automatically. It abstracts away the complexity of merging changes across devices, ensuring that: 1) Local changes are always available – No waiting for a server response. 2) Sync happens in the background – Updates propagate once connectivity is restored. 3) Conflicts resolve automatically – Thanks to CRDTs, users don’t have to deal with merge conflicts manually.

How is data migration of the local SQLite handled in regards to App updates?

As mentioned in the presentation, the CADEC App uses Drizzle ORM and PowerSync as key components of the data layer, which help manage schema evolution. However, removing columns is a breaking change. Just like with API evolution, fields should be deprecated first before removal to allow clients time to update.

Will local-first replace the BFF?

Its been proposed that local-first represents the next evolution of fetching and state management, within an app, going from rest to graphql and now to local-first. If we look at graphql, what a developer is most concerned about is the schema, the shape of the data, typing of queries, mutations and finally caching.
If you setup an api with apollo and then sprinkle in GraphQL-codegen from the guild, one can satisfy all of the above.
Although what about synchronisation and to a lesser extent subscriptions/streaming.
The later is solved nicely with apollo but synchronisation is something you’ll have to solve yourself and many projects do this with varying degrees of genius… And then, you have the backend layers, gql schema, resolvers caller services or fetching from a db etc etc … So, if you could work with a strongly defined typed schema, with common querying/mutation hooks, get the whole synchronisation aspect worked out (by experts), skip having to maintain an api, then really why not?

An essential thing to grasp is that the shape of data, synchronised to your local dbs is the schema. In the power synch example I preseneted in my talk, the synch rules expose Materialised Views of your data which in effect is your schema. The cool thing, is that it gets synched, you skip spinners and you own that data!

I really think that this will take a big dent in the BFF space if not start replacing it, the kids want 60fps!!

Could you use local-first to manage all your data?

With the huge optimisations of sqlite with for instance op-sqlite the gap between fetching data from a db vs from memory is beginning to close. There is obviously still a need for useState within components to handle local state, but for API data I really don’t see why not? If we look at Redux and redux-persist, which uses AsyncStorage under the hood, theres no real reason you couldn’t just replace that with sqlite. Also I stumble across alot of projects, despite using Graph QL still use something like Redux for global state. Personally I’d cut out the middle man and try and simplify the way I fetch and store data. Having said that something like LegendState bridges the gap between local-first and traditional state management, maybe theres a middle ground? See https://supabase.com/blog/local-first-expo-legend-state

Ladda ner presentation
Callista medarbetare Magnus Larsson

Snabbare uppstart av Java-applikationer med CRaC

Magnus Larsson

Med en ökad användning av mikrotjänster och molnbaserade arkitekturer har snabba uppstartstider för applikationer blivit allt viktigare för effektiv skalning och minskad nertid. För Java-applikationer kan dock krav på korta uppstartstider vara svåra att uppfylla.

I denna presentation introducerar vi CRaC (Coordinated Restore at Checkpoint), en teknik som kan minska uppstartstiden avsevärt för Java-applikationer. Vi går igenom hur man går tillväga för att använda CRaC och demonstrerar hur det fungerar för applikationer utvecklade med Spring Boot.

Presentationen jämför också CRaC med andra tekniker för att minska uppstartstider såsom GraalVM native compile, AppCDS och project Layden.




Frågor och svar

Vilken typ av service kan man använda Scale to Zero-strategi på?
Ju mindre service desto bättre skulle jag vilja säga. Typfallet är väl FaaS, Function as a Service. Men baserat på de tester jag gjort så här långt ser jag ingen teoretisk övre gräns för hur stor en Spring Boot-applikation kan vara, givet att man använder CRaC. Ju större applikation desto större minnesutnyttjande, och därmed kommer en checkpoint ta allt större plats på disk, vilket borde kunna bli ett praktiskt problem.

Finns det risk för svårupptäckta fel genom att den CRaC:ade applikationen på något sätt skiljer sig från originalet?
Förutom de områden som togs upp under presentationen, har jag inte sett några andra specifika problemområden. Självklart kan det finnas buggar i CRaC i sig som kan ge upphov till fel. En återstartad CRaC-applikation körs som en vanlig applikation i en Java-VM, till skillnad från t.ex. en applikation som är native-kompilerad med Graal VM och som därmed kör maskinkod direkt istället för att vara baserad på Java bytecode.

Finns det en stor community som hjälper till med CRaC-implementering?
Ja, det är ett OpenJDK-projekt. För mer info se OpenJDK CRaC.

Does the checkpoint contain heap data that could be sensitive?
Ja, det är därför viktigt att uppvärmningen före checkpoint körs mot en tillfällig träningsmiljö. Då blir den känsliga informationen som skrivs ner på disk vid checkpoint utan värde.

Kan man inte förenkla byggprocessen genom att göra warmup och checkpoint direkt i byggservern, givet att den kör Linux? Då skulle man ju slippa bygga den första jar-baserade Docker-imagen.
Nej, det tror jag är väldigt svårt, i alla fall baserat på de tester jag gjort. För att CRaC:s restore ska fungera krävs det att samma operativsystem och Java-installation används som vid CRaC:s checkpoint. Jag har löst problemet genom att använda samma bas-Docker-image (för OS och Java) för checkpoint och restore.

Har du provat att använda Testcontainers istället för Docker Compose för att starta ett träningslandskap?
Ja, men eftersom checkpointen måste köras i en container, i den lösning jag jobbat med (se frågan ovan), så kommer Testcontainers-ramverket behöva starta syskon-containrar, dvs anropa Dockers API. Det ska gå rent tekniskt att få till, men jag tycker alltid att det är knöligt och väldigt störkänsligt. Så jag undviker det. De som vill prova kan läsa mer på Testcontainers Docker-in-Docker.

What about connection with a database, will it establish again?
Se bild med rubriken “State and Connections” i min presentation. 3PP-biblioteket som används för databaser måste implementera CRaC:s Resource-interface för att hantera detta.

Olika JVM-versioner vid bygge och restart?
Ingen bra idé, enligt mina erfarenheter. För att CRaC:s restore ska fungera krävs det att samma operativsystem och Java-installation används som vid CRaC:s checkpoint. Om man beaktar att restore i princip handlar om att läsa tillbaka minnet i en process från disk så inser man att det är bra om det underliggande operativsystemet och Java-miljön är identiska med hur de såg ut vid checkpoint-tillfället. Jag har löst problemet genom att använda samma bas-Docker-image (för OS och Java) för checkpoint och restore.

Är CRaC lämpligt för större applikationer eller har det negativ påverkan på CRaC?
Jag kan tänka mig att en större applikation har större minnesutnyttjande, och därmed kommer en checkpoint ta allt större plats på disk, vilket borde kunna bli ett praktiskt problem.

How can I use CRaC to keep my boss happy about my development approaches? It is clear that CRaC can keep management happy about our development work.
Om bossen är bekymrad över (dvs. ni har ett affärsrelaterat problem med) långa startup-tider för en eller flera av era Java-applikationer (t.ex. i ett scale-to-zero-sammanhang), så kan absolut CRaC vara en väg framåt för att göra bossen och er verksamhet nöjd.

När du väl har flödet på plats är det ju super men verkar vara massor med jobb. Hur skulle det funka att bara köra i ‘live’ - dvs första deploy är från jar och sedan när live är varmkörd ta en snapshot och fortsättningsvis köra från den? Secrets är såklart ett problem men config behöver inte trixas med.
Ja, håller med. Hoppas min nästa bloggpost kan ge er en flygande start för att automatisera skapandet av CRaC-baserade Docker-images :-) Att bara köra checkpoint/restore live är väl i princip hur AWS SnapStart-stödet för Java-baserade Lambda-funktioner fungerar. Så, det får man väl säga fungerar :-). Jag har själv dock inte testat eller funderat på den ansatsen.

Can a checkpoint be made at any point in the program? Benefits, challenges (e.g. connections to external services)?
Tekniskt sett ja, men för att hålla nere uppstartstiden efter en restore så är det viktigt att applikationen är “tillräckligt” uppvärmd innan checkpointen tas. Detta kommer i de flesta fall leda till att man måste återetablera connections till databaser, köhanterare mm efter restore. En stor del av presentationen handlade om detta, så kika gärna igenom presentationen igen när den blivit publicerad.

Vilka begränsningar eller utmaningar finns med CRaC?
Tror det finns rätt matnyttiga svar ovan på den frågan.

Could CRaC be used not just at build and deploy time but even at runtime for event sourced applications to save regular checkpoints so it doesn’t have to replay all the events at every startup?
Det var ju en intressant idé! Jag har inte själv funderat i banor av att persistera (event) data mha CRaC. Med tanke på att data ändras mycket fortare än applikationen så blir det kanske rätt ineffektivt att checkpointa applikationen varje gång man vill checkpointa sin event-data.

Finns det någon nackdel med CRaC eller ska man automatisera det och alltid ha den approachen?
Som med all ny teknik så skall man införa det med viss måtta tycker jag. Börja med att prova ut det där det finns en tydlig vinst, t.ex. i ett scale-to-zero-scenario. Utvärdera och besluta därefter hur ni vill gå vidare. Men att automatisera ser jag som ett grundkrav innan man använder det i produktion.

Vad händer när appen kraschar? Vill man använda checkpoint då?
Oftast, ja, skulle jag vilja säga. Enda fallet jag kan tänka mig teoretiskt är om kraschen skulle bero på hur man värmde upp applikationen innan man tog checkpointen. Då måste man ju hitta och rätta felet i applikationen och sedan ta en ny checkpoint av den nya versionen. Som workaround, i väntan på den nya versionen, borde man kunna ändra i warmup-proceduren för att undvika att trigga felet i applikationen innan checkpoint.

Kan man kombinera CRaC med native compile / Graal?
Det avråder jag bestämt från! Blanda tekniker på det sättet är att be om problem. Dessutom ser jag spontant inte nyttan, native-kompileringen kommer ju i slutändan skapa maskinkod, så nyttan av CRaC uteblir vad jag kan förstå.

Hur ser du på ROI av CRaC:ade tjänster? Är det värt insatsen?
Ja, givet att man har ett behov av snabbare startuptider. Ju mer verksamheten vinner på en snabbare uppstart desto fortare ger investeringen vinst. Om t.ex. användare slipper vänta 5 sek vid uppstart av en Java-applikation i ett scale-to-zero-scenario, så kan man säkert snabbt räkna hem investeringen. Dvs i form av att man inte behöver ha sin applikation igång när den inte används.

Rensas minnesdumpen från disk när applikationen startats upp igen och i vilket läge återskapas den i så fall? Eller återanvänds den första checkpointen om och om igen och ligger kvar på disk?
Så som jag visade i min presentation så läggs minnesdumpen in i en Docker-image, och rensas därmed inte utan återanvänds varje gång en container skall startas från den versionen av Docker-imagen.

Bör man skriva andra tester för att få CRaC att fungera bra jämfört med de man vanligen har av kvalitetsskäl?
Om man tänker på tester som skall användas under uppvärmningen före man tar en checkpoint så är min tanke att man till stor del skall kunna återanvända befintliga tester som används för att säkra kvaliteten. Men det borde ju kunna uppstå, rent teoretiskt, behov av tester för att säkerställa en tillräckligt bra uppvärmning och som befintliga kvalitetstester inte täcker in. Men börja med ansatsen att återanvända befintliga tester och se om ett behov dyker upp för specialtester för uppvärmning.

Do you have to be careful having the application ”idle” (no external operations in progress) when creating the checkpoint?
Den ansatsen jag har utgått från är att checkpoint tas i byggsteget och där har man full kontroll på applikationen. Där tar man checkpointen efter uppvärmningen är klar och applikationen är “idle”. Då CRaC kräver att externa connections är stängda vid en checkpoint, så låter det svårt att ta en checkpoint “i farten”.

Bör man tänka på GC innan snapshot?
Det låter som en intressant tanke, jag har själv inte laborerat med det.

What happens to the stack and any open file descriptors when a process is CRaCed?
Se bild med rubriken “State and Connections” i min presentation, filer och andra externa connections måste stängas före en checkpoint och återetableras efter en restore. CRaC-interfacet Resource kan användas av en applikation för att få reda på när en checkpoint skall ske och när en restore har utförts.

Finns det alternativ på ‘Docker-nivån’? Där minne av pausad container sparas till disk?
Inget jag har kikat på. Handlar det om en kortare paus så kanske det kan fungera utan att applikationen blandas in. Annars får man väl samma problem att handskas med externa connections och konfiguration som inte längre är relevant vid en återstart.

Ladda ner presentation