Separasjon av bekymringer i flutter applikasjoner
Aloïs Deniel.
Flutter utvikler
Nylig måtte jeg implementere ombord på walkthroughs for UDN Task Manager Nykommere! Dette var en veldig viktig oppgave fordi mange nye brukere skulle oppdage plattformen medUtrolig morsom annonse vi premiere på Super Bowl! ✨.
Via.UDN Task Manager
The Walkthrough tillater våre mange nye brukere, som kanskje ikke vetUDN Task Managerennå, for raskt å forstå hvordan du bruker flere funksjoner fra applikasjonen. Det er en pågående innsats, akkurat som den nye UDN Task ManageruniversitetRessurs vi forfølger! 🚀.
Heldigvis, programvarearkitekturen bakUDN Task ManagerFlutter Mobile Application tillot meg å implementere denne funksjonaliteten ganske raskt, selv ved å gjenbruke de virkelige widgets fra søknaden! Dette betyr at gjennomgangen er dynamisk, responsiv, og nøyaktig samsvarer med de virkelige applikasjonsskjermene til appen - og vil fortsette å, selv når widgets vil utvikle seg.
Jeg kunne også implementere funksjonaliteten på grunn av den rette separasjonen av bekymringer.
La oss se hva jeg mener her. 🤔.
Adskillelse av bekymringer
Å designe en programvarearkitektur er et av de mest komplekse temaene for ingeniørlag. Blant alle ansvarsområder er det alltid vanskelig å forutse fremtidige programvareutviklinger. Det er derfor å skape en godt lagret og avkoblet arkitektur kan hjelpe deg og dine lagkamerater med mange ting!
Hovedfordelen ved å skape små avkoblede systemer er utvilsomtTestbarhet! Og dette er det som hjalp meg med å lage et demo alternativ til eksisterende skjermer fra appen!
En trinnvis guide
Nå, hvordan kunne vi bruke disse prinsippene til en flamplikasjonsapplikasjon?
Vi vil dele noen teknikker vi bruker til å byggeUDN Task Managermed et enkelt walkthrough eksempel.
Eksemplet er så enkelt at det ikke kan opplyse alle fordelene bak det, men tro meg, det vil hjelpe deg med å skape mye mer vedlikeholdsførbare flutter applikasjoner med komplekse kodebaser. 💡.
Søknaden
Som et eksempel vil vi opprette et program som viser befolkningen i USA for hvert år.
Via.UDN Task Manager
Vi har to skjermer her:
Vi vil fokusere på Implementering siden det er det mest interessante med sin asynkrone samtale.
Trinn 1. Naiv tilnærming
Den mest åpenbare implementeringen for vår app, er ved å bruke en enkelt for hele logikken.
For å få tilgang til det anmodede året, leser vi fra arvet widget.
Dette eksemplet påkaller funksjon fra den pakke for å få dataene fradatausa.io API., parser den resulterende JSON med metode fra den bibliotek, og hold som en del av staten med en eiendom som heter .
For å lage widgettreet, bruker vi en , som gjenoppbygger seg selv om den nåværende tilstanden til vår asynkron samtale.
Ok, implementeringen er kort og bruker bare innebygde widgets, men tenk nå på vår første intensjon: Bygg demo alternativer (eller tester) for denne skjermen. Det er svært vanskelig å kontrollere resultatet av HTTP-anropet for å tvinge programmet til å gjengi i en bestemt stat.
Det er der begrepetinversjon av kontrollenvil hjelpe oss. 🧐.
Trinn 2. Inversjon av kontroll
Dette prinsippet kan være vanskelig å forstå for nye utviklere (og også vanskelig å forklare), men den generelle ideen er åtrekk ut bekymringene utenfor komponentene våre-Så at de ikke er ansvarlige for å velge oppførselen - og delegere den i stedet.
I en mer vanlig situasjon består det bare av å skape abstraksjoner og injisere implementeringer i våre komponenter, slik at implementeringen kan endres senere om nødvendig.
Men ikke bekymre deg, det vil gjøre mer fornuftig etter vårt neste eksempel! 👀.
For å kontrollere HTTP-anropet til API-en, har vi isolert gjennomføringen vår til en dedikert klasse. Vi har også opprettet en klasse for å gjøre dataene enklere å manipulere og vedlikeholde.
For vårt eksempel bruker vi den velkjenteforsørgerpakke for å injisere a forekomst ved roten til vårt tre.
Leverandøren tillater enhver descendent widget ( som vår ) å lese nærmeste øvre i treet. Vi kan da bruke sin metode for å starte vår , i stedet for den faktiske HTTP-implementeringen.
Nå kan vi dra nytte av dette!
I tilfelle du ikke visste: noen klasserI Dart definerer også implisitt et tilknyttet grensesnitt. Dette gjør at vi kan gi en alternativ implementering av som alltid returnerer det samme forekomsten fra sin Metodeanrop.
Denne metoden
Vi har nå alle nøklene til å vise en demo-forekomst av !
Vi overstyrer bare den for tiden som er oppgitt forekomst ved å pakke inn vår i en leverandør som skaper en forekomst i stedet!
Og det er det - vår Les denne demo-forekomsten i stedet, og bruker vår data i stedet for et HTTP-anrop.
Dette er et godt eksempel påInversjon av kontroll.Vår Widget er ikke ansvarlig for logikken for å få dataene lenger, men delegerer det i stedet for et dedikert klientobjekt. Og vi kan nå lage demo forekomster på skjermen, eller å implementere widgetester for skjermen vår! Rått! 👏.
Men vi kan gjøre enda bedre!
Siden vi ikke er i stand til å simulere en lastestatus, har vi for eksempel ikke full kontroll over en hvilken som helst statsendring på widgetnivået.
Trinn 3. Statlig ledelse
Dette er et varmt emne i flutter!
Jeg er sikker på at du allerede har lest lange tråder av folk som prøver å velgeden beste statsforvaltningenløsning for flammel. Og for å være klar, det er ikke det vi skal gjøre i denne artikkelen. Etter vår mening, så lenge du skiller din bedriftslogikk fra din visuelle logikk, har du det bra! Å skape disse lagene er veldig viktig for vedlikeholdbarhet. Vårt eksempel er enkelt, men i ekte applikasjoner kan logikken raskt bli komplisert, og en slik separasjon gjør det mye enklere å finne dine rene logiske algoritmer. Dette emnet er ofte oppsummert somStatsledelse .
I dette eksemplet bruker vi en grunnleggende sammen med A. . Men vi kunne også ha bruktflutter_bloc.ellerRiverpod. (eller en annen løsning), og det ville ha jobbet bra også. Prinsippene forblir det samme, og så lenge du adskilt dine stater og din logikk, er det enda mulig å portere kodebasen fra en av de andre løsningene.
Denne separasjonen hjelper oss også med å kontrollere noen tilstand av våre widgets, slik at vi kan spotte det på alle mulige måter!
I stedet for å stole på Fra rammen representerer vi nå vår skjermtilstand som en gjenstand.
Det er også viktig å implementere og metoder for å gjøre vårt objekt sammenlignbare etter verdi. Dette gjør at vi kan oppdage om to tilfeller bør betraktes som forskjellige.
💡 The.er erklærbarellerfrysetPakker er gode alternativer for å hjelpe deg med å implementere og Metoder!
Vår stat er alltid forbundet med en , men vi har også fire forskjellige mulige stater om hva vi vil vise til brukeren:
Disse tilstandene er tydeligere enn en , siden det virkelig representerer våre bruksområder. Og igjen, dette gjør vår kode mer vedlikeholdbar!
💡 Vi anbefaler på det sterkesteUnion Typer fra den frysepakkenå representere dine logikkstater! Det legger til mange verktøy som eller metoder.
Nå som vi har en representasjon av vår stat, må vi lagre en forekomst av det et sted - det er formålet med . Det vil holde strømmen forekomst i sin eiendom og vil gi metoder for å oppdatere staten.
Vi gir A. innledende tilstand og a Metode for å laste data fra og oppdater gjeldende .
For å instantiate og observere staten på skjermen vår, stole vi også på leverandøren og dens . Denne typen leverandør ser automatisk etter noen opprettet og vil utløse en gjenoppbygging fra Hver gang det blir varslet om en endring(når vår notifiseringsverdi er forskjellig fra den forrige).
Flott! Vår applikasjonsarkitektur begynner å se ganske bra ut. Alt er adskilt i veldefinerte lag, med spesifikke bekymringer! 🤗.
En ting mangler fortsatt for testabilitet skjønt, vi vil definere dagens å kontrollere tilstanden til vår tilknyttede .
Trinn 4. Visuell dedikert layout widget
I det siste trinnet ga vi litt for mye ansvar for vår Widget: Det var ansvarlig for å instantiating . Og som det vi har sett tidligere, prøver vi å unngå logikkansvar på visningslaget!
Vi kan enkelt løse dette ved å lage et annet lag for vår skjerm-widget: vi vil dele vår widget i to:
Ved å kombinere de to, vil vi kunne bare lage Demo / test forekomster, men å ha for ekte brukssaken i vår søknad.
For å oppnå en bedre adskillelse av bekymringer, flyttet vi alt under widget til en dedikert widget. Denne nye widgeten bruker bare data og er ikke ansvarlig for enhver endeliging. Det konverterer bare lesestaten til et bestemt widgettre.
De Ring og Instans forblir i , og denne widgeten returnerer bare med et forhåndskonfigurert avhengighetstreet!
Denne mindre forbedringen er spesifikk for bruksbruk, men du vil legge merke til at vi også har lagt til en slik at enhver etterkommer-widget direkte kan forbruke en . Dette vil gjøre det lettere å mocke data.
Ikke nøl med å trekke ut et widgetre i en dedikert klasse! Det vil forbedre ytelsen, og gjøre koden mer vedlikeholdbar.
I vårt eksempel opprettet vi en visuell layout-widget for hver av de tilknyttede statstyper:
Nå har vi full kontroll over hva vi kan mocke og vise på skjermen vår!
Vi må bare pakke en med en å simulere tilstanden til layoutet.
Konklusjon
Å skape en vedlikeholdsbar programvarearkitektur er definitivt ikke lett! Forutse fremtidige scenarier kan kreve mye arbeid, men jeg håper de få tipsene jeg delte, vil hjelpe deg i fremtiden!
Eksemplene kan se enkle - det kan til og med virke som om vi er over-engineering - men da appens kompleksitet vokser, vil de standarder hjelpe deg mye! 💪.
Ha det gøy med flutter, og følg bloggen for å få flere tekniske artikler som denne! Følg med!