Design- och arkitekturövning: design av ickefunktionella krav i
NextGen POS
Litteratur
kapitel 33 i Larman
Innehåll
Design av några krav på NextGen POS. En viktig slutsats av detta
kapitel är att det i mångt och mycket är de ickefunktionella
kraven som formar arkitekturen.
Någon tjänst (till exempel produktdatabasen) är ej tillgänglig
Det är inte acceptabelt att en klient hänger om den inte lyckas
få kontakt med tex produktdatabasen (se technical memo på
sid 508 i Larman). Lösningen är att skapa en lokal cache med de
vanligaste produkterna. Hur stor den ska vara avgörs av den lokala hårddiskens
storlek.
Vi har tidigare designat en lösning för åtkomst av
tjänster med hjälp av mönstret adapter som illustreras av figur
23.1 på sid 343 i Larman. Nu utökar vi designen för åtkomst
av produktdatabasen med en adapter till en lokal cache enligt figur 33.1
på sid 509 i Larman. Några kommentarer om lösningen:
- Den lokala adaptern (LocalProducts i figur 33.1 på
sid 509 i Larman) är egentligen inte en adapter utan det objekt som
faktiskt hanterar den lokala cachen. Det hindrar inte att den implementerar
IProductsAdapter.
- Notera att det finns två nivåer av lokal cache. ProductCatalog
har en cache i minnet av de allra vanligaste produkterna vars storlek avgörs
av primärminnets storlek. Dessutom hanterar LocalProducts en
fil med produkter vars storlek avgörs av den lokala hårdiskens
storlek.
- Figur 33.2 på sid 510 i Larman visar hur de olika objekten kopplas
ihop vid uppstart. Notera att ServicesFactory (som vi tidigare designat
enligt bla figur 23.5 och 23.6 på sid 349 och 351 i Larman) alltid returnerar
den lokala adaptern. Notera vidare att den lokala adaptern har en referens
till en adapter för den egentliga produktdatabasen så att frågan
vid behov (ingen träff i cachen) kan skickas vidare dit.
- Figur 33.3 och 33.4 på sid 510 och 511 i Larman visar hur de
olika produktdatabaserna samarbetar. Först letar ProductCatalog
i sin egen primärminnescashe, finns inte produkten där vidarebefodras
frågan till LocalProducts som letar i sin filcache. Finns datat
inte där heller skickar den frågan vidare till produktdatabasen.
Cache-hantering
Att hantera en cache medför en del problem. En fråga är
hur cachen ska fyllas. I designen ovan fylls cachen succesivt genom att ett
nytt element läggs till om det inte hittas i cachen och den dessutom
inte är full. Ett alternativ är att fylla cachen direkt vid uppstart.
Det gör uppstarten långsammare men vi har större möjlighet
att påverka vilka produkter som hamnar i cachen (de vanligaste, vilket
är bättre än de först accessade). Den långa uppstartstiden
med den senare lösningen kan undvikas om cachen fylls av en separat tråd.
Oavsett hur cachen fylls kan vi fundera på om det ska finnas någon
funktionalitet för att ta bort element som inte använts på
en viss tid.
Hur vet vi om data i cachen är aktuellt? Det kanske är uppdaterat
i produktdatabasen. Om det är OK att det tar en tid innan förändringar
i databasen når klienterna kan vi lösa det genom att låta
varje klient ha en tråd som med ett visst intervall frågar produktdatabasen
efter förändringar och uppdaterar den lokala cachen. En sådan
tråd visas i figur 33.7 och 33.8 på sid 513 i Larman. Notera att
denna design ger ett problem med kritiska sektioner som vi måste lösa.
Vad händer om produktdatabasen är nere och det sökta datat
inte finns i cachen?
Se sidan Undantag för en genomgång
av strategier för undantagshantering och sidan Undantag i klass- och sekvensdiagram för
UML-notation för undantag.
Figur 33.10 och 33.11 på sid 517 och 520 i Larman visar hur undantag
hanteras om den sökta produkten inte finns i cachen och databasen inte
fungerar.
Uppgift
Fundera på vilka punkter på sidan om
undantag som tillämpats i ovanstående design av undantagshantering.
Failover när den lokala cachen inte ska frågas först
Ett exempel är när försäljningar rapporteras till ekonomisystemet.
De ska in så fort som möjligt och ska därföras inte
mellanlagras lokalt om det går att undvika. Om ekonomisystemet av någon
anledning inte är tillgängligt måste de däremot lagras
lokalt och rapporteras vid ett senare tillfälle. Detta kan lösas
med hjälp av mönstret proxy enligt figur 33.13 på sid 522
i Larman. Den typ av proxy som används här är redirection
proxy (se sidan Flera designmönster).
Hantering av olika typer av betalningar (kort, check och kontant)
Dessa tre olika typer av betalningar har helt olika kriterier för att
godkännas. Kreditkortsbetalningar ska godkännas (och registreras)
av något kreditinstitut, checkbetalningar ska (kanske) godkännas
av en bank och kontantbetalningar eventuellt med någon mekanism för
att kolla om sedlar är förfalskade. Dessa olika beteenden hanteras
lämpligtvis polymorfiskt enligt figur 33.17 på sid 530 i Larman.
Om en viss typ av betalning (tex kontant) inte ska godkännas alls (dvs
alltid godkänns) hanteras även detta polymorfiskt.
Figur 33.18 och 33.19 på sid 530 och 531 i Larman visar förloppet
från det att kunden betalar fram till det polymorfiska anropet av authorize()
för kreditkorts- respektive checkbetalning.
Figur 33.20-33.22 på sid 533-534 i Larman visar hur metoden authorize()
erhåller ett godkännande och rapporterar detta. Vi har tidigare
designat en lösning för hur olika kreditinstitut accessas med hjälp
av adaptrar och ett concrete factory (ServicesFactory).
Lösningen framgår av bla figur 23.1 och 23.5 på sid 343
och 349 i Larman och ingår som en del av figur 33.20-33.22.