Feature Flagg med vår

1. Oversikt

I denne artikkelen vil vi kort definere funksjonsflagg og foreslå en meningsfylt og pragmatisk tilnærming for å implementere dem i Spring Boot-applikasjoner. Deretter vil vi grave i mer sofistikerte iterasjoner ved å dra nytte av forskjellige Spring Boot-funksjoner.

Vi vil diskutere ulike scenarier som kan kreve funksjonsflagging og snakke om mulige løsninger. Vi gjør dette ved hjelp av et eksempel på et Bitcoin Miner-program.

2. Feature Flagg

Funksjonsflagg - noen ganger kalt funksjonsbrytere - er en mekanisme som lar oss aktivere eller deaktivere spesifikk funksjonalitet i applikasjonen vår uten å måtte endre kode eller ideelt sett omdisponere appen vår.

Avhengig av dynamikken som kreves av et gitt funksjonsflagg, kan det hende vi trenger å konfigurere dem globalt, per appinstans eller mer detaljert - kanskje per bruker eller forespørsel.

Som med mange situasjoner innen programvareutvikling, er det viktig å prøve å bruke den mest enkle tilnærmingen som takler problemet uten å legge til unødvendig kompleksitet.

Funksjonsflagg er et kraftig verktøy som, når det brukes klokt, kan gi systemet vårt pålitelighet og stabilitet. Men når de blir misbrukt eller underholdt, kan de raskt bli kilder til kompleksitet og hodepine.

Det er mange scenarier der funksjonsflagg kan være til nytte:

Trunkbasert utvikling og ikke-trivielle funksjoner

I bagasjeromsbasert utvikling, spesielt når vi vil fortsette å integrere ofte, kan det hende at vi ikke er klare til å frigjøre en viss funksjonalitet. Funksjonsflagg kan være nyttige for at vi kan fortsette å slippe uten å gjøre endringene tilgjengelige før de er fullført.

Miljøspesifikk konfigurasjon

Vi kan komme til å kreve visse funksjoner for å tilbakestille DB for et E2E-testmiljø.

Alternativt kan det hende vi må bruke en annen sikkerhetskonfigurasjon for miljøer som ikke er produksjonsmiljøer enn de som brukes i produksjonsmiljøet.

Derfor kan vi dra nytte av funksjonsflagg for å veksle riktig oppsett i riktig miljø.

A / B-testing

Å frigjøre flere løsninger for det samme problemet og måle effekten er en overbevisende teknikk som vi kan implementere ved hjelp av funksjonsflagg.

Kanarifrigjøring

Når vi distribuerer nye funksjoner, kan vi bestemme oss for å gjøre det gradvis, og starte med en liten gruppe brukere, og utvide adopsjonen når vi validerer korrekte oppførsel. Funksjonsflagg lar oss oppnå dette.

I de følgende avsnittene vil vi prøve å gi en praktisk tilnærming for å takle de ovennevnte scenariene.

La oss bryte ned forskjellige strategier for å markere funksjoner, og starte med det enkleste scenariet for å gå videre til et mer detaljert og mer komplekst oppsett.

3. Funksjonsflagg på applikasjonsnivå

Hvis vi trenger å takle noen av de to første brukstilfellene, er flagg på applikasjonsnivå en enkel måte å få ting til å fungere.

Et enkelt funksjonsflagg vil vanligvis innebære en eiendom og en eller annen konfigurasjon basert på verdien av den egenskapen.

3.1. Funksjonsflagg ved bruk av vårprofiler

På våren kan vi dra nytte av profiler. Profiler gjør det enkelt for oss å konfigurere bestemte bønner selektivt. Med noen få konstruksjoner rundt oss kan vi raskt lage en enkel og elegant løsning for funksjonsflagg på applikasjonsnivå.

La oss late som om vi bygger et BitCoin-gruvedrift. Programvaren vår er allerede i produksjon, og vi har til oppgave å lage en eksperimentell, forbedret gruvedriftsalgoritme.

I vår JavaConfig vi kunne profilere komponentene våre:

@Configuration public class ProfiledMiningConfig {@Bean @Profile ("! Experimental-miner") offentlig BitcoinMiner defaultMiner () {returner nye DefaultBitcoinMiner (); } @Bean @Profile ("eksperimentell gruvearbeider") offentlig BitcoinMiner experimentalMiner () {returner nye ExperimentalBitcoinMiner (); }}

Deretter, med den forrige konfigurasjonen, trenger vi bare å ta med profilen vår for å melde oss på vår nye funksjonalitet. Det er mange måter å konfigurere appen vår generelt og aktivere profiler spesielt. På samme måte er det testing av verktøy for å gjøre livet vårt enklere.

Så lenge systemet vårt er enkelt nok, Vi kunne da lage en miljøbasert konfigurasjon for å bestemme hvilke funksjoner flaggene skal brukes og hvilke som skal ignoreres.

La oss forestille oss at vi har et nytt brukergrensesnitt basert på kort i stedet for bord, sammen med den forrige eksperimentelle gruvearbeideren.

Vi vil aktivere begge funksjonene i akseptmiljøet vårt (UAT). Vi kan lage en application-uat.yml fil:

vår: profiler: inkluderer: eksperimentell gruvearbeider, ui-kort # Mer konfigurasjon her

Med den forrige filen på plass, trenger vi bare å aktivere UAT-profilen i UAT-miljøet for å få ønsket sett med funksjoner.

Det er også viktig å forstå hvordan du kan dra nytte av det våren.profiler. inkluderer. Sammenlignet med våren.profiler.aktiv, førstnevnte gjør at vi kan inkludere profiler på en additiv måte.

I vårt tilfelle vil vi ha uat profilen også for å inkludere eksperimentelle gruvearbeidere og ui-kort.

3.2. Funksjonsflagg ved bruk av egendefinerte egenskaper

Profiler er en fin og enkel måte å få jobben gjort. Vi kan imidlertid kreve profiler for andre formål. Eller kanskje vi kanskje vil bygge en mer strukturert funksjonsflagginfrastruktur.

For disse scenariene kan egendefinerte egenskaper være et ønskelig alternativ.

La oss omskrive vårt forrige eksempel og dra nytte av @ConditionalOnProperty og vårt navneområde:

@Configuration public class CustomPropsMiningConfig {@Bean @ConditionalOnProperty (name = "features.miner.experimental", matchIfMissing = true) public BitcoinMiner defaultMiner () {return new DefaultBitcoinMiner (); } @Bean @ConditionalOnProperty (name = "features.miner.experimental") offentlig BitcoinMiner experimentalMiner () {returner nye ExperimentalBitcoinMiner (); }}

Det forrige eksemplet bygger på Spring Boots betingede konfigurasjon og konfigurerer en eller annen komponent, avhengig av om eiendommen er satt til ekte eller falsk (eller utelatt helt).

Resultatet er veldig likt det i 3.1, men nå har vi vårt navneområde. Å ha vårt navneområde lar oss lage meningsfulle YAML / egenskapsfiler:

# [...] Noen vårkonfigurasjonsfunksjoner: miner: eksperimentell: true ui: cards: true # [...] Andre funksjonsflagg

Også dette nye oppsettet lar oss prefikse funksjonene våre - i vårt tilfelle ved å bruke funksjoner prefiks.

Det kan virke som en liten detalj, men når applikasjonen vår vokser og kompleksiteten øker, vil denne enkle iterasjonen hjelpe oss med å holde funksjonsflaggene våre under kontroll.

La oss snakke om andre fordeler med denne tilnærmingen.

3.3. Ved hjelp av @ConfigurationProperties

Så snart vi får et prefiks sett med egenskaper, kan vi lage en POJO dekorert med @ConfigurationProperties for å få et programmatisk håndtak i koden vår.

Etter vårt pågående eksempel:

@Component @ConfigurationProperties (prefix = "features") offentlig klasse ConfigProperties {private MinerProperties miner; private UIProperties ui; // standard getters and setters public static class MinerProperties {private boolean experimental; // standard getters and setters} offentlig statisk klasse UIProperties {private boolske kort; // standard getters og setters}}

Ved å sette tilstanden til funksjonene våre i en sammenhengende enhet, åpner vi for nye muligheter, slik at vi enkelt kan eksponere informasjonen for andre deler av systemet vårt, for eksempel brukergrensesnittet, eller for nedstrøms systemer.

3.4. Eksponere funksjonskonfigurasjon

Vårt Bitcoin-gruvesystem fikk en UI-oppgradering som ikke er helt klar ennå. Av den grunn bestemte vi oss for å merke det. Vi kan ha en ensidig app som bruker React, Angular eller Vue.

Uavhengig av teknologien, vi trenger å vite hvilke funksjoner som er aktivert, slik at vi kan gjengi siden vår tilsvarende.

La oss lage et enkelt sluttpunkt for å betjene konfigurasjonen vår, slik at brukergrensesnittet vårt kan spørre backend når det er nødvendig:

@RestController offentlig klasse FeaturesConfigController {private ConfigProperties egenskaper; // constructor @GetMapping ("/ feature-flags") offentlige ConfigProperties getProperties () {return egenskaper; }}

Det kan være mer sofistikerte måter å betjene denne informasjonen på, for eksempel å opprette egendefinerte aktuatorendepunkter. Men av hensyn til denne veiledningen føles et kontrollerendepunkt som en god løsning.

3.5. Holde leiren ren

Selv om det kanskje høres åpenbart ut, er det like viktig å være disiplinert når vi ikke lenger trenger det, når vi har implementert funksjonsflaggene våre omtenksomt.

Funksjonsflagg for første gangs bruk - koffertbasert utvikling og ikke-trivielle funksjoner - er vanligvis kortvarig. Dette betyr at vi trenger å sørge for at vår ConfigProperties, vår Java-konfigurasjon, og vår YAML filer holder seg rene og oppdaterte.

4. Mer granulære funksjonsflagg

Noen ganger befinner vi oss i mer komplekse scenarier. For A / B-testing eller kanarifrigjøringer er vår tidligere tilnærming rett og slett ikke nok.

For å få funksjonsflagg på et mer detaljert nivå, kan det hende vi må lage vår løsning. Dette kan innebære å tilpasse brukerenheten vår til å inkludere funksjonsspesifikk informasjon, eller kanskje utvide nettrammeverket vårt.

Å forurense brukerne våre med funksjonsflagg er kanskje ikke en tiltalende ide for alle, og det er andre løsninger.

Som et alternativ kan vi dra nytte av noen innebygde verktøy som Togglz. Dette verktøyet gir litt kompleksitet, men tilbyr en fin løsning utenom boksen og gir førsteklasses integrasjon med Spring Boot.

Togglz støtter forskjellige aktiveringsstrategier:

  1. Brukernavn: Flagg knyttet til bestemte brukere
  2. Gradvis utrulling: Flagg aktivert for en prosentandel av brukerbasen. Dette er nyttig for Canary-utgivelser, for eksempel når vi vil validere oppførselen til funksjonene våre
  3. Utgivelsesdato: Vi kan planlegge at flagg skal aktiveres på en bestemt dato og et tidspunkt. Dette kan være nyttig for en produktlansering, en koordinert utgivelse eller tilbud og rabatter
  4. Klientens IP: Flaggede funksjoner basert på klienters IP-er. Disse kan være nyttige når du bruker den spesifikke konfigurasjonen på spesifikke kunder, gitt at de har statiske IP-er
  5. Server IP: I dette tilfellet brukes serverens IP til å bestemme om en funksjon skal aktiveres eller ikke. Dette kan også være nyttig for kanarifugler, med en litt annen tilnærming enn den gradvise utrullingen - som når vi ønsker å vurdere ytelseseffekten i våre tilfeller
  6. ScriptEngine: Vi kan aktivere funksjonsflagg basert på vilkårlige skript. Dette er uten tvil det mest fleksible alternativet
  7. System egenskaper: Vi kunne angi visse systemegenskaper for å bestemme tilstanden til et funksjonsflagg. Dette ville være ganske likt det vi oppnådde med vår mest enkle tilnærming

5. Sammendrag

I denne artikkelen hadde vi en sjanse til å snakke om funksjonsflagg. I tillegg diskuterte vi hvordan Spring kan hjelpe oss med å oppnå noe av denne funksjonaliteten uten å legge til nye biblioteker.

Vi startet med å definere hvordan dette mønsteret kan hjelpe oss med noen få vanlige brukssaker.

Deretter bygde vi noen få enkle løsninger ved hjelp av Spring and Spring Boot out-of-the-box verktøy. Med det kom vi opp med en enkel, men kraftig funksjonell flaggkonstruksjon.

Nedenfor sammenlignet vi et par alternativer. Å gå fra den enklere og mindre fleksible løsningen til et mer sofistikert, men mer komplekst mønster.

Til slutt ga vi kort noen retningslinjer for å bygge mer robuste løsninger. Dette er nyttig når vi trenger en høyere grad av granularitet.