Cvičení 08 · Co je slib klientovi a co přepočet

Výpočet V1 → V2 a determinismus

  • verze algoritmu
  • determinismus
  • replay

Princip

Výpočet splátky se vyvíjí: V1 zaokrouhluje sazbu a ořezává, V2 počítá přesně a přidává pojištění. Klient dostal slib podle V1.

Když replay přepočítá starý výpočet novým kódem, minulost se tiše změní. Událost proto nese výsledek a verzi algoritmu (fakt), ne jen vstupy.

Replay musí být deterministický: `apply` nesmí používat náhodu ani aktuální čas. Dvakrát přehraný stream dává stejný kontrolní součet.

Co sledovat

  • Slíbená vs. přehraná splátka po přepnutí na V2.
  • Kontrolní součty dvou přehrání se u nedeterministického apply liší.

Bez řešení / S řešením

Bez řešení

Spustit: nasazení V2 bez verzování

Dokončíme výpočet ve V1, pak nasadíme V2. Replay přepočítá starý výpočet a apply generuje referenční číslo náhodně.

Spustit v simulátoru bez řešení

S řešením

Spustit s verzovaným výsledkem a deterministickým apply

Událost CalculationCompleted nese výsledek i algoritmus V1, replay vrací původní slib. Nové výpočty jedou ve V2.

Spustit v simulátoru s řešením

Co udělat: Klikni na „Spustit: nasazení V2 bez verzování“. Na co se dívat: Splátka po přehrání je jiná než ta, kterou jsme klientovi slíbili. Simulátor potřebuje JavaScript a běží jako samostatná aplikace.

Zkus to ve svém projektu

Zkopíruj prompt do svého coding agenta (Claude Code, Copilot, Codex…) a spusť ho v repozitáři svého projektu.

Zavést verzi výpočetního algoritmu tak, aby replay historie vracel původní výsledky a byl deterministický.

Jazyk
Varianta
# Úkol pro coding agenta: Výpočet V1 → V2 a determinismus

Stack: Java. Režim: s vedením.
Cíl: Zavést verzi výpočetního algoritmu tak, aby replay historie vracel původní výsledky a byl deterministický.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (Java backend (typicky Java 21, Spring Boot, JPA nebo JDBC). Použij build nástroj a styl, který projekt už má (Maven/Gradle, JUnit 5).).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).
Předpoklad: projekt má event store s `CalculationCompleted` a upcastem. Pokud ne, nejdřív je založ minimálně.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde se počítá splátka a jak se výsledek ukládá.
- Všechna místa v `apply`/replay, která používají čas, náhodu, UUID nebo externí volání, a čtení, která výsledek přepočítávají (API, čtecí modely, e-maily).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Replay, který výpočet slíbený podle V1 přepočítá kódem V2, tiše změní minulost; událost proto nese výsledek a verzi algoritmu a replay je deterministický. Příklad: příjem 40 600 Kč, cena 4 950 000 Kč, akontace 20 %, sazba 3,72 %, 30 let: poměr splátky V1 0,4500 (limit 45 % projde), V2 0,4501 (odmítne).

## Konkrétní úkol

Technická specifika (Java): `BigDecimal` s explicitním `RoundingMode`; algoritmy za rozhraním `PaymentCalculator` a mapou verzí.

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: uveď, který údaj je fakt (uložit do události) a který odvozený (přepočítat). Výsledek dokončení je fakt rozhodnutí.
2. Přidej do CalculationCompleted `algorithmVersion` a vypočtený výsledek. Nová verze schématu: upcast dá staré události `algorithmVersion: 1`, při změně tvaru stavu zvyš verzi snapshotů.
3. Zachovej V1 jako samostatnou implementaci; V2 jako novou (výpočet v haléřích, zaokrouhlení jen na konci). Výběr podle verze v události.
4. Přesuň generování ID/čas z `apply` do příkazu, pokud tam jsou (hodnota vstoupí do události).
5. Test determinismu: dvě přehrání stejného streamu (jiný čas, jiné úložiště, od snapshotu) mají shodný hash stavu.
6. Golden test: výpočet z fixture ve V1 dává pořád stejné číslo i po nasazení V2. Fixture má vstup, kde se V1 a V2 liší (příklad výše).

Na co si dát pozor:
- Zaokrouhlování měny (Decimal místo double).
- Změna pravidla není oprava chyby: historii zachovej, opravu zapiš novou událostí.

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Golden testy pro V1 a V2 (aspoň jeden vstup se liší).
- Replay výpočtu z V1 vrací výsledek V1 i v API a čtecích modelech.
- Hash stavu dvou replayů je shodný.
- V `apply` není čas, náhoda ani I/O.
- JUnit 5 testy ve stávající struktuře `src/test/java` projdou build nástrojem projektu.
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.
# Úkol pro coding agenta: Výpočet V1 → V2 a determinismus

Stack: Java. Režim: challenge.
Cíl: Zavést verzi výpočetního algoritmu tak, aby replay historie vracel původní výsledky a byl deterministický.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (Java backend (typicky Java 21, Spring Boot, JPA nebo JDBC). Použij build nástroj a styl, který projekt už má (Maven/Gradle, JUnit 5).).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).
Předpoklad: projekt má event store s `CalculationCompleted` a upcastem. Pokud ne, nejdřív je založ minimálně.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde se počítá splátka a jak se výsledek ukládá.
- Všechna místa v `apply`/replay, která používají čas, náhodu, UUID nebo externí volání, a čtení, která výsledek přepočítávají (API, čtecí modely, e-maily).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Replay, který výpočet slíbený podle V1 přepočítá kódem V2, tiše změní minulost; událost proto nese výsledek a verzi algoritmu a replay je deterministický. Příklad: příjem 40 600 Kč, cena 4 950 000 Kč, akontace 20 %, sazba 3,72 %, 30 let: poměr splátky V1 0,4500 (limit 45 % projde), V2 0,4501 (odmítne).

## Zadání (Challenge)

Nasaď V2 výpočtu splátky tak, aby historické kalkulace vracely beze změny svůj původní výsledek a replay byl deterministický.

Technická specifika (Java): `BigDecimal` s explicitním `RoundingMode`; algoritmy za rozhraním `PaymentCalculator` a mapou verzí.

Postup si zvol sám. Pasti v tomto tématu nejsou vypsané: najdi je (souběh, opakované doručení, pořadí, selhání uprostřed) a ke každé napiš test, který by ji odhalil. Na konci vypiš, jaké pasti jsi našel a které jsi vědomě nechal otevřené.

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Golden testy pro V1 a V2 (aspoň jeden vstup se liší).
- Replay výpočtu z V1 vrací výsledek V1 i v API a čtecích modelech.
- Hash stavu dvou replayů je shodný.
- V `apply` není čas, náhoda ani I/O.
- JUnit 5 testy ve stávající struktuře `src/test/java` projdou build nástrojem projektu.
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.
# Úkol pro coding agenta: Výpočet V1 → V2 a determinismus

Stack: C#. Režim: s vedením.
Cíl: Zavést verzi výpočetního algoritmu tak, aby replay historie vracel původní výsledky a byl deterministický.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (C# backend (.NET, ASP.NET Core, EF Core nebo Dapper). Použij solution, styl a DI konvence, které projekt už má (xUnit/NUnit).).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).
Předpoklad: projekt má event store s `CalculationCompleted` a upcastem. Pokud ne, nejdřív je založ minimálně.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde se počítá splátka a jak se výsledek ukládá.
- Všechna místa v `apply`/replay, která používají čas, náhodu, UUID nebo externí volání, a čtení, která výsledek přepočítávají (API, čtecí modely, e-maily).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Replay, který výpočet slíbený podle V1 přepočítá kódem V2, tiše změní minulost; událost proto nese výsledek a verzi algoritmu a replay je deterministický. Příklad: příjem 40 600 Kč, cena 4 950 000 Kč, akontace 20 %, sazba 3,72 %, 30 let: poměr splátky V1 0,4500 (limit 45 % projde), V2 0,4501 (odmítne).

## Konkrétní úkol

Technická specifika (C#): `decimal` s `MidpointRounding`; algoritmy za rozhraním `IPaymentCalculator` registrovanými podle verze.

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: uveď, který údaj je fakt (uložit do události) a který odvozený (přepočítat). Výsledek dokončení je fakt rozhodnutí.
2. Přidej do CalculationCompleted `algorithmVersion` a vypočtený výsledek. Nová verze schématu: upcast dá staré události `algorithmVersion: 1`, při změně tvaru stavu zvyš verzi snapshotů.
3. Zachovej V1 jako samostatnou implementaci; V2 jako novou (výpočet v haléřích, zaokrouhlení jen na konci). Výběr podle verze v události.
4. Přesuň generování ID/čas z `apply` do příkazu, pokud tam jsou (hodnota vstoupí do události).
5. Test determinismu: dvě přehrání stejného streamu (jiný čas, jiné úložiště, od snapshotu) mají shodný hash stavu.
6. Golden test: výpočet z fixture ve V1 dává pořád stejné číslo i po nasazení V2. Fixture má vstup, kde se V1 a V2 liší (příklad výše).

Na co si dát pozor:
- Zaokrouhlování měny (Decimal místo double).
- Změna pravidla není oprava chyby: historii zachovej, opravu zapiš novou událostí.

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Golden testy pro V1 a V2 (aspoň jeden vstup se liší).
- Replay výpočtu z V1 vrací výsledek V1 i v API a čtecích modelech.
- Hash stavu dvou replayů je shodný.
- V `apply` není čas, náhoda ani I/O.
- Testy ve stávajícím testovacím projektu projdou (`dotnet test`).
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.
# Úkol pro coding agenta: Výpočet V1 → V2 a determinismus

Stack: C#. Režim: challenge.
Cíl: Zavést verzi výpočetního algoritmu tak, aby replay historie vracel původní výsledky a byl deterministický.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (C# backend (.NET, ASP.NET Core, EF Core nebo Dapper). Použij solution, styl a DI konvence, které projekt už má (xUnit/NUnit).).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).
Předpoklad: projekt má event store s `CalculationCompleted` a upcastem. Pokud ne, nejdřív je založ minimálně.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde se počítá splátka a jak se výsledek ukládá.
- Všechna místa v `apply`/replay, která používají čas, náhodu, UUID nebo externí volání, a čtení, která výsledek přepočítávají (API, čtecí modely, e-maily).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Replay, který výpočet slíbený podle V1 přepočítá kódem V2, tiše změní minulost; událost proto nese výsledek a verzi algoritmu a replay je deterministický. Příklad: příjem 40 600 Kč, cena 4 950 000 Kč, akontace 20 %, sazba 3,72 %, 30 let: poměr splátky V1 0,4500 (limit 45 % projde), V2 0,4501 (odmítne).

## Zadání (Challenge)

Nasaď V2 výpočtu splátky tak, aby historické kalkulace vracely beze změny svůj původní výsledek a replay byl deterministický.

Technická specifika (C#): `decimal` s `MidpointRounding`; algoritmy za rozhraním `IPaymentCalculator` registrovanými podle verze.

Postup si zvol sám. Pasti v tomto tématu nejsou vypsané: najdi je (souběh, opakované doručení, pořadí, selhání uprostřed) a ke každé napiš test, který by ji odhalil. Na konci vypiš, jaké pasti jsi našel a které jsi vědomě nechal otevřené.

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Golden testy pro V1 a V2 (aspoň jeden vstup se liší).
- Replay výpočtu z V1 vrací výsledek V1 i v API a čtecích modelech.
- Hash stavu dvou replayů je shodný.
- V `apply` není čas, náhoda ani I/O.
- Testy ve stávajícím testovacím projektu projdou (`dotnet test`).
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.
# Úkol pro coding agenta: Výpočet V1 → V2 a determinismus

Stack: Web (HTML/JS nebo stack aplikace). Režim: s vedením.
Cíl: Zavést verzi výpočetního algoritmu tak, aby replay historie vracel původní výsledky a byl deterministický.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (webová aplikace: frontend v prohlížeči, případně s vlastním backendem. Když má projekt backend, patří event store, broker a služby na backend a body o endpointech a tabulkách se týkají jeho. Když backend nemá, použij IndexedDB v prohlížeči a v testech `fake-indexeddb`. Framework a test runner projektu zachovej; nové závislosti přidávej jen s odůvodněním.).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).
Předpoklad: projekt má event store s `CalculationCompleted` a upcastem. Pokud ne, nejdřív je založ minimálně.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde se počítá splátka a jak se výsledek ukládá.
- Všechna místa v `apply`/replay, která používají čas, náhodu, UUID nebo externí volání, a čtení, která výsledek přepočítávají (API, čtecí modely, e-maily).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Replay, který výpočet slíbený podle V1 přepočítá kódem V2, tiše změní minulost; událost proto nese výsledek a verzi algoritmu a replay je deterministický. Příklad: příjem 40 600 Kč, cena 4 950 000 Kč, akontace 20 %, sazba 3,72 %, 30 let: poměr splátky V1 0,4500 (limit 45 % projde), V2 0,4501 (odmítne).

## Konkrétní úkol

Technická specifika (Web (HTML/JS nebo stack aplikace)): Pro peníze použij celá čísla (haléře) nebo knihovnu pro decimal; verze algoritmu jako klíč v mapě funkcí.

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: uveď, který údaj je fakt (uložit do události) a který odvozený (přepočítat). Výsledek dokončení je fakt rozhodnutí.
2. Přidej do CalculationCompleted `algorithmVersion` a vypočtený výsledek. Nová verze schématu: upcast dá staré události `algorithmVersion: 1`, při změně tvaru stavu zvyš verzi snapshotů.
3. Zachovej V1 jako samostatnou implementaci; V2 jako novou (výpočet v haléřích, zaokrouhlení jen na konci). Výběr podle verze v události.
4. Přesuň generování ID/čas z `apply` do příkazu, pokud tam jsou (hodnota vstoupí do události).
5. Test determinismu: dvě přehrání stejného streamu (jiný čas, jiné úložiště, od snapshotu) mají shodný hash stavu.
6. Golden test: výpočet z fixture ve V1 dává pořád stejné číslo i po nasazení V2. Fixture má vstup, kde se V1 a V2 liší (příklad výše).

Na co si dát pozor:
- Zaokrouhlování měny (Decimal místo double).
- Změna pravidla není oprava chyby: historii zachovej, opravu zapiš novou událostí.

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Golden testy pro V1 a V2 (aspoň jeden vstup se liší).
- Replay výpočtu z V1 vrací výsledek V1 i v API a čtecích modelech.
- Hash stavu dvou replayů je shodný.
- V `apply` není čas, náhoda ani I/O.
- Testy projdou stávajícím test runnerem; lint a build projdou, pokud je projekt má.
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.
# Úkol pro coding agenta: Výpočet V1 → V2 a determinismus

Stack: Web (HTML/JS nebo stack aplikace). Režim: challenge.
Cíl: Zavést verzi výpočetního algoritmu tak, aby replay historie vracel původní výsledky a byl deterministický.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (webová aplikace: frontend v prohlížeči, případně s vlastním backendem. Když má projekt backend, patří event store, broker a služby na backend a body o endpointech a tabulkách se týkají jeho. Když backend nemá, použij IndexedDB v prohlížeči a v testech `fake-indexeddb`. Framework a test runner projektu zachovej; nové závislosti přidávej jen s odůvodněním.).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).
Předpoklad: projekt má event store s `CalculationCompleted` a upcastem. Pokud ne, nejdřív je založ minimálně.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde se počítá splátka a jak se výsledek ukládá.
- Všechna místa v `apply`/replay, která používají čas, náhodu, UUID nebo externí volání, a čtení, která výsledek přepočítávají (API, čtecí modely, e-maily).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Replay, který výpočet slíbený podle V1 přepočítá kódem V2, tiše změní minulost; událost proto nese výsledek a verzi algoritmu a replay je deterministický. Příklad: příjem 40 600 Kč, cena 4 950 000 Kč, akontace 20 %, sazba 3,72 %, 30 let: poměr splátky V1 0,4500 (limit 45 % projde), V2 0,4501 (odmítne).

## Zadání (Challenge)

Nasaď V2 výpočtu splátky tak, aby historické kalkulace vracely beze změny svůj původní výsledek a replay byl deterministický.

Technická specifika (Web (HTML/JS nebo stack aplikace)): Pro peníze použij celá čísla (haléře) nebo knihovnu pro decimal; verze algoritmu jako klíč v mapě funkcí.

Postup si zvol sám. Pasti v tomto tématu nejsou vypsané: najdi je (souběh, opakované doručení, pořadí, selhání uprostřed) a ke každé napiš test, který by ji odhalil. Na konci vypiš, jaké pasti jsi našel a které jsi vědomě nechal otevřené.

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Golden testy pro V1 a V2 (aspoň jeden vstup se liší).
- Replay výpočtu z V1 vrací výsledek V1 i v API a čtecích modelech.
- Hash stavu dvou replayů je shodný.
- V `apply` není čas, náhoda ani I/O.
- Testy projdou stávajícím test runnerem; lint a build projdou, pokud je projekt má.
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.

Školení pro váš tým

Chcete školení pro svůj tým?

Školení vedeme na vašem kódu a vašem doménovém problému. Domluvíme rozsah, termín a formu.

Probrat školení