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:
  1. 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.

  2. 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.

  3. 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.

  4. 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.