Jeg vil framsnakke et gammelt prinsipp og to modne verktøy som fungerer spesielt godt når alt er i bevegelse samtidig. Denne kombinasjonen var nyttig for oss da lagene våre ristet i takt og utakt med prosjekter som var utenfor vår kontroll.

Frontendproblemet

En kunde har en avtale om finansielle tjenester hos en bedrift. Denne avtalen kan endre tilstand som følge av et jobbskifte. Av historiske årsaker håndterer bedriften de ulike tilstandene i ulike fagsystem. Som følge av dette må brukeren forholde seg til ulike brukeropplevelser for å utføre de samme oppgavene.

Tre ulike applikasjoner som mer eller mindre inneholdt samme type funksjonalitet.

Det tekniske oppsettet virket ganske standard. Arkitektene tegner det slik:

Ett forholdsvis standard teknisk oppsett.

Ved nærmere ettersyn viste det seg at api-ene som ble eksponert via BFF-en i stor grad bare proxiet strukturene som fantes i fagsystemet som eide avtalen. BFF-en var proppfull av «ifs-and-buts», men det fantes ikke noe harmonisert grensesnitt som forenklet utviklingen av brukeroplevelser. På sikt førte dette til tre applikasjoner som levde sine egne liv.

Strukturer i fra fagsystemene proxies helt ut til brukergrensesnittene med liten mulighet for harmonisering på tvers av avtaletyper.

Forretningen trykket hardt på for at brukerne ikke skulle påvirkes av at det var ulike fagsystem som håndterte de ulike avtaletypene. Det måtte bli en omforent brukeropplevelse for alle fasene.

Vi trenger ett omforent brukergrensesnitt som håndterer alle typer avtaler.

Backend for Frontend utfordringen

Av ulike årsaker skulle BFF-en erstattes for å passe inn i et større plattformløft utenfor vår kontroll. Nytt kjøretidsmiljø, nytt programmeringsspråk, nye sikkerhetsmekanismer osv. Vi måtte etablere en helt ny BFF som betjente de eksisterende applikasjonene med nødvendige api.

Ny BFF må etableres på grunn av platformløft og nye krav til sikkerhet.

Fagsystem i endring

Fagsystemene der bak levde også sine egne liv. Et sentralt system skulle erstattes – selvfølgelig også utenfor vår kontroll.

Sentralt fagsytem byttes ut.

Hele “platformen” var i bevegelse. Tidsplanen var stram og vi måtte finne en strategi for å levere stabile grensesnitt samtidig som vi håndterer masse endringer på en trygg måte.

Noen faste rammer

Vår strategi var enkelt og greit å innføre ende-til-ende testing der vi simulerte alle fagsystem ved hjelp av WireMock og verifiserte alle nye api opp mot det vi fikk fra de gamle ved hjelp av ApprovalTests.

Utfordringen lå i å få kontroll på alle variasjonene innenfor hver avtaletype. Vi startet med ca 25 ulike scenarioer som måtte verifiseres. For alle disse variantene hentet vi ut responsens fra api i den gamle BFFen og tilhørende respons fra de ulike fagsytemene. Det var ca 30 ulike api involvert i henholdsvis BFF og fagssytem.

Datasettene som ble hentet ut var produksjonsnære i den forstand at de kom fra de samme systemene som ble benyttet i produksjon, men det var selvfølgelig ingen faktiske kundedata i disse. Der det var behov for å representere kundeinformasjon, ble dette hentet fra Tenor datasettet til Skatteetaten.

Med scenarioene på plass og nødvendig uttrekk av data, var det ganske raskt å sette opp simuleringen og testingen.

BFFen vi etablerte skulle i første omgang bare erstatte den gamle gjennom reetablering av de samme grensesnittene. Over tid har vi restrukturert disse grensesnittene - slik at frontend enklere kan håndtere ulike avtaletyper ved hjelp av felleskomponenter og nye api.

Uttrekk av scenariedata fra fagsystemene og tilsvarende respons i eksisterende api.

I alle ende-til-ende testene våre startes BFFen og WireMock opp som egne servicer. Apiene blir testet ut med de ulike scenariene.

Responsen i fra eksisterende api benyttes i ApprovalTests for å fange opp eventuelle avvik i nye api.

Simuleringen av fagsystemene i WireMock konfigureres slik at den gjenspeiler de faktiske grensesnittene vi jobber mot.

Uttrekk av scenariedata fra fagsystemene benyttes av WireMock for å simulere disse systemene under testing. Katalogstrukturen gjenspeiler stien til grensesnittet i fagsystemene.
Wiremock konfigures til å gjenspeile api som BFF benytter for å hente scenariedata. Også her representerer katalogstrukturen stien til grensesnittene i fagsystemene.

Når vi kjører testene våre, verifiserer vi ende-til-ende med kall mot BFF-ens api og dens interaksjon mot fagsystemene. Hvis det er avvik mellom det den nye BFF-en produserer og fasiten fra den gamle BFF-en, vil testen feile.

ApprovalTests der det er funnet avvik i respons i ett api knyttet til ett scenarie.

Avvik vises i en egen diff mellom det som er «approved» og det som er «received».

ApprovalTestes viser differansen mellom det som er forventet resultat og faktisk resultat.

Tydelig ansvarsdeling - Api, Ports and Adapters

I den nye BFF-en innførte vi et tydelig skille mellom:

  • api ut mot brukergrensesnitt
  • Adaptere som snakker med api-ene til de ulike fagsystemene

Prinsippene er hentet fra Hexagonal arkitektur, også kalt Ports and Adapters. Dette gir oss løse koblinger mellom datakilde og brukergrensesnitt. Løse koblinger gjør det enklere å la dem leve ulike liv – så lenge kontrakten, portene, ivaretas.

Portene definerer grensesnitt, uttrykt ved hjelp av den interne domenemodellen. api-ene har sine egne modeller som gjenspeiler kontrakten med brukergrensesnittene. På samme måte har adaptere sine modeller som gjenspeiler kontrakten med fagsystemene.

Når alle testene for nye api var feilfrie, kunne vi gradvis migrere over eksisterende applikasjoner.

Ved etablering av ny BFF innførte vi en api side med veldig løse koblinger mot Fagsystemsiden (Via Adaptere). Eksisternede brukergrensesnitt ble etterhvert rutet til ny BFF for sine api kall.

Services ble etablert for å orkestrere samspill mellom ulike adaptere ut mot api-ene. Her er den originale beskrivelsen av Hexagonal arkitektur. Det er mange måter å implementere dette på. Det viktigste er at du finner din form – og er tro mot den.

Prinsippene for å få til løse koblinger mellom api-siden og Adapter-siden.
api med sine modeller som definerer kontrakten mot brukergrensesnittene.
Domenemodell, porter og servicer
Adaptere med sine modeller som definerer kontrakten mot fagsystemene sine api.

Når et fagsystem ble byttet ut, etablerte vi en ny adapter som håndterte nye strukturer og tilkoblingspunkter. Vi samlet inn nye scenariedata fra det nye systemet og verifiserte resultatet med de samme testene.

Utskifting av fagsystem håndteres ved hjelp av ny Adapter. De eksisterende testene benyttes for å verifisere nye adaptere.

Ved etablering av nye api ut mot det nye harmoniserte brukergrensesnittet, etablerte vi nye tester mot de samme scenariefilene. Gradvis fikk vi faset ut «bastardene» og innført en harmonisert frontend.

Søtte for harmonisert brukergrensesnitt håndteres ved hjelp av nye api. Her må vi lage nye tester, men vi gjenbruker datauttrekk i fra fagsystemene.

Vi måtte lage noen nye tester, men vi hadde kontroll på:

  • hvilke scenario vi ønsket å teste
  • tilhørende testdata for de ulike fagsystemene
Etterhvert kom vi i mål med utskifingene i alle lag.

Vi er veldig godt fornøyd med oppsettet vårt. Vi har klart å håndtere store endringer i alle lag på en trygg måte. Antall ulike testscenario har gradvis vokst til over 100 og dekker langt flere use case enn den opprinnelige avtalehåndteringen. WireMock benyttes for å simulere ca 50 bakenforliggende api.

Bonus 1

En fin bonus har vært rollen vår nye BFF har hatt for vår frontendutvikling. Ved å kjøre BFFen lokalt har vi hatt tilgang til alle scenariene med produksjonsnære data samtidig som vi utvikler nye brukergrensesnitt. Det har sikret godt samspill mellom BFFen som tilgjengeligjør api og de som faktisk skal benytte seg av disse.

Bonus 2

Kombinasjonen http4k og WireMock gjør det ganske enkelt å automatisere dokumentasjon av integrasjonene relatert til de ulike scenariene. Automatisk oppdatering av dokumentasjon er en fin bonus når mye er i endring.

Automatisk generert UML dokumentasjon i forbindelse med testing av scenarioene.