Introduktion till arkitektur

Boken som refereras nedan (Larman) är Larman: Applying UML and Patterns (Prentice-Hall 2002) ISBN: 0-13-092569-1

Introduktion

Arkitekturen är systemets "skelett", hur det ser ut i stora drag. Arkitekturen talar om vilka problem som löses och var de löses men inte hur (det hör till design). Jämför arkitektens roll vid ett husbygge: Antag att det behövs en hiss, arkitekten ritar då ett hisschakt, designern ritar en hiss och en hissmotor och konstruktören monterar in hissen. Ytterligare ett annat sätt att förklara begreppet arkitektur är att se det som en vy av systemet från 1000 meters höjd, bara de stora dragen syns. Arkitekturen ska garantera att de ickefunktionella kraven kan lösas.

Liksom analys och design består även arkitekturen både av en statisk och en dynamisk modell. I designen är den statiska modellen klassdiagram över mjukvaruklasser, i arkitekturen är det diagram över subsystem och andra viktiga delar. Den dynamiska modellen i designen är interaktionsdiagram som visar hur mjukvaruklasserna samarbetar, i arkitekturen visar de hur subsystem samarbetar.

Arkiekturen består också av en motivering av varför en viss lösning är vald.

Arbetet med arkitekturen

Arbetet med arkitekturen inkluderar dels att hitta kraven på den, främst ickefunktionella men även funktionella krav (architectural investigation) dels att ta fram hård- och mjukvara som löser dem (architectural design).

Ickefunktionella krav

Alla krav på ett program som inte har att göra med vad programmet ska göra utan hur det ska fungera. Typiska exempel på ickefunktionella krav är krav på prestanda, tillgänglighet, tillförlitlighet, säkerhet, hur lättunderhållet programmet ska vara, hur lättanvänt det ska vara, hur lätt det ska gå att administrera osv. Det är mycket viktigt att beakta de ickefunktionella kraven innan programmet börjar utvecklas. Det är också viktigt att uttrycka de ickefunktionella kraven så att det går att verifera om de uppfylls.

Arkitekturen måste garantera att de ickefunktionella kraven kan lösas. Därför är det nödvändigt att klargöra vilka ickefunktionella krav som ställs på systemet. Det finns många olika definitioner av ickefunktionella krav men de vanligaste kraven att beakta är dessa:

Tillgänglighet (availability) och pålitlighet (reliability)

Tillgänlighet används för att försäkra sig om att tillräckligt många användare kommer åt systemet tillräckligt ofta. Det kan till exempel anges som "igång 98% av tiden" eller "otillgängligt max 4 minuter under en vecka". Pålitlighet är ett mått på i vilken utsträckning en användare kan förvänta sig att systemet ska ge ett korrekt resultat. Det kan till exempel vara "max en av 1000 sessioner misslyckas". Observera att det handlar om misslyckanden på grund av att systemet är (blir) otillgängligt, inte på grund av att detger fel resultat.

Lättunderhållet (manageability)

Anger hur komplext systemadministratörens arbete får vara. Ett exempel är "högst 2 arbetstimmar per månad för att installera uppgraderingar".

Konfigurerbart (configurability, flexibility)

Utökningar och förändringar som inte rör de funktionella kraven, tex att byta språk i användargränssnittet eller att lägga till en ny typ av klient. Det finns inget tydligt sätt att mäta detta, det bästa är att försöka uppskatta arbetstid, kostnad och sannolikhet för förändringar.

Lättutökat (adaptability, extensibility)

Utökningar och förändringar som rör de funktionella kraven, tex att lägga till nya typer av rabatter i NextGen POS. Se konfigurerbarhet för möjligheter att mäta detta. För övrigt handlar i stort sett hela kursen om att möta krav på detta område.

Prestanda

Till exempel "första synliga tecken på svar inom 3 sekunder i 95% av fallen mätt från yttre brandväggen". Det som framför allt tar tid är anrop till andra processer, speciellt att koppla upp sådana förbindelser.

Kapacitet

Ett mått på hur mycket som kan utförs samtidigt (concurrent), alltså inte parallellt. Ett krav kan vara "100 samtidiga transaktioner".

Skalbart (scalability)

Egenskapen att systemet kan uppfylla samma ickefunktionella krav när lasten ökar om ytterligare hårdvara tillförs. Vertikal skalning är att tillföra ytterligare hårdvara (tex processorer och minne) till befintliga datorer. Horisontell skalning är att tillföra fler burkar. Om skalbarheten ska mätas måste vi definera vilka ickefunktionella krav som ska skala och i vilken omfattning, till exempel "bibehållen prestanda vid 90% lastökning om antalet servrar dubbleras".

Användbarhet (usability)

Till exempel "skärmbilden ska synas på en meters håll".

Säkerhet

Säkerhet är ett stort och viktigt område som absolut måste övervägas noga på ett tidigt skede. Att försöka lägga till säkerhetshantering i ett befintligt program är en mycket otrevlig uppgift. Ett mätbart krav på säkerheten kan vara "det ska ta minst 30 minuter med bäst kända teknik för attacker att förändra en användares saldo" eller "tre misslyckade inloggningsförsök i följd ska loggas". Exempel på olika säkerhetsaspekter är:

Styrka identiteten, autentisering (authentication)

Hur ska användarens identitet styrkas? Med någon form av certifkat? Med inloggning? Var finns i så fall lösenord sparade?

Rättigheter (authorization)

Har olika användare olika rättigheter? Hur hanteras det?

Non-repudiation

Egenskapen att det inte går att förneka något som gjorts, till exempel att ett visst meddelande skickats. Deta åstadkoms till exempel genom att använda någon form av digital signatur.

Integritet (integrity)

Data kan inte modifieras på något otillåtet sätt. Till exempel kanske vi måste vara säkra på att data som skickas över ett nätverk kommer fram opåverkat.

Loggning (auditability)

Vad ska loggas och vart? Hur ska det förhindras att loggen påverkas av en inkräktare?

Paketering

Hur produkten ska levereras.

Standarder

Krav på standarder som måste följas.

Krav på att använda viss hård- och mjukvara

Dess krav kan komma sig till exempel av att systemet ska integreras med något befintligt eller av kostnadsskäl (exempelvis "endast open source-produkter får användas").

Architectural investigation

Architectural investigation är en del av arbetet med att ta fram kravspecen och ingår alltså inte i kursen.

Kom ihåg att inte skriva en orealistisk önskelista, det är ingen idé att ställa onödigt stora ickefunktionella krav på produkten. Kom också ihåg att det måste gå att verifera att kraven uppfylls.  Vidare kan det vara lämpligt att gradera kraven efter hur viktigt det är att de uppfylls och hur svårt det är att uppfylla dem. Figur 32.2 på sid 492 i Larman visar ett exempel på hur ickefunktionella krav kan formaliseras.

Architectural design

Allt vi hittils gått igenom i kursen om objektorienterad design har varit tämligen plattformsoberoende. Vi gör på samma sätt oavsett vilket språk vi använder och vilket operativsystem programmet körs på. Arbetet med att utforma en arkitektur som tillgodoser de ickefunktionella kraven är tvärtom i högsta grad plattformsberoende. Det beror på att det är arkitekturen som sätter ramarna för designarbetet. Om det till exempel finns ett krav på loggning väljer vi förmodligen att använda ett färdigt loggnings-API, vi kommer då säkert att välja ett annat API om vi använder C# än om vi använder Java.

Det kan vara lämpligt att spara information om arkitekturella beslut, alternativ till dem och vilka faktorer som styrde beslutet. Det finns annars en risk att andra inte förstår beslutet eller att arkitekten glömmer varför beslutet togs och måste göra om arbetet. På sid 494, 495 och 497 i Larman finns exempel på hur sådana anteckningar kan se ut.

Vad är resultatet av arbetet med arkitekturen?

Arkitekturen täcker flera olika områden. En komplett beskrivning av den måste innehålla:
Dessutom kan det vid behov finnas ytterligare vyer:

Varning för vattenfallsprocesser!

Det kan låta som om den här redogörelsen förespråkar någon sorts vattenfallsprocess, först listas kraven på arkitekturen, sedan tar vi fram en arkitektur som löser dem och därefter gör vi en design inom den framtagna arkitekturen. Så är det absolut inte. Arbetet måste tvärtom vara iterativt. Först tar vi fram ett grovt utkast till kravspec och sedan implementerar vi någon funktionalitet som tvingar oss att fundera över arkitekturen. Den implementationen ska gå hela vägen till kod av produktionskvalité. I varje följande iteration förfinar vi kravspecen lite, genomför eventuella förändringar i den befintliga arkitekturen (och i koden) och utvecklar ny funktionalitet som tvingar oss att fundera vidare på arkitekturen. En viktig milstolpe oavsett process är när vi utvcklat så mycket kod att arkitekturen är klar.

Hur utforma en arkitektur?

Riktlinjer och metoder för att ta fram en arkitektur ligger utanför den här kursen. För att åstadkomma en bra arkitektur krävs god kännedom om aktuella teknologier och gärna även om alternativa teknologier. Vi ska bara ta en kort titt på några viktiga principer.

Arkitekturella mönster

Nu ska vi titta lite närmare på två arkitekturella mönster som är mycket bra hjälpmedel för att uppnå de egenskaper som presenterades under punkten design goals ovan. De är Lager och MVC och behandlas i kapitel 30 i Larman. Dessa är (eftersom de har förtjänat benämningen mönster) plattformsoberoende.

Lager

Problem
Lösning
Det finns många olika mallar för hur ett system kan delas upp i lager. Figur 30.1 på sid 451 i Larman är ett förslag.
Exempel
Figur 30.2 på sid 452 visar hur NextGen POS kan delas upp enligt förslaget i figur 30.1. Notera att detta är en arkitekturell vy som alltså inte visar alla klasser och komponenter utan bara de som behövs för att ge en förståelse för strukturen. Som påpekats ovan är utvecklingen av arkitekturen iterativ. Figur 30.2 är en skiss i en relativ tidig iteration, Larman misstänker till exempel att det kommer till ett application layer i en senare iteration.

Det är viktigt att göra klart för sig vilken koppling det finns mellan olika paket och lager, detta visas i figur 30.3 på sid 454 i Larman. Notera att det både går att visa mellan exakt vilka typer ett beroende finns (tex mellan Register och ServicesFactory) och bara att det finns ett beroende mellan paket (tex Domain till DBFacade). Det senare kan användas om det inte är intressant mellan vilka typer beroendet finns eller om många typer i ett paket är beroende (så är fallet med beroendet från Domain till DBFacade).

Det är lämpligt att rita interaktionsdiagram för att illustrera beteendet i den den logiska vyn av arkitekturen. Dessa ska då visa arkitekturellt viktiga scenarion, alltså sådana som illustrerar samarbete mellan olika lager och paket. Ett exempel finns i figur 30.5 på sid 456 i Larman. Notera hur sambandet mellan paket och typer illustreras i UML, <PaketNamn>::<TypNamn>. Notera också hur stereotyper (<<singleton>> och <<subsystem>>) används för att förtydliga diagrammet.
Samarbeten
Samarbeten mellan olika lager kan implementeras med hjälp av designmönstren Facade, Controller och Observer.

Facade används lämpligtvis för att kapsla in subsystem och därigenom åstadkomma Proteced Variations. Ett exempel på det finns i figur 30.6 på sid 458 i Larman. Detta gäller vid kommunikation från högre till lägre lager eller mellan olika paket/subsystem inom samma lager.

Controller används som Facade vid anrop från Presentation till Domain. Om det är få systemanrop används lämpligtvis en facade controller (se sidan med mönstret Controller) varvid lagret Application utelämnas, se figur 30.7 på sid 459 i Larman. När systemet växer och allt fler systemoperationer implementeras kommer vi till slut till en punkt där facade controllern blir otympligt stor. Då är det dags att dela upp den i use case controllers och placera dessa i lagret Application som då införs, se figur 30.8 och 30.9 på sid 460 i Larman. Notera att varje systemoperation motsvaras av ett anrop från Presentation till Domain (eventuellt via Application). Controller används endast vid kommunikation från Presentation till lägre lager.

Ovan hävdades att det inte skulle förekomma några beroenden från lägre till högre lager. Det är tyvärr nödvändigt att göra ett undantag från den regeln. Det beror på att en systemoperation kan medföra att stora delar av domänen (lagret domain) byter tillstånd. Om någon av de typer som ändrar tillstånd finns representerade på skärmen (alltså i Presentation) måste skärmbilden uppdateras så att den visar rätt tillstånd (det uppdaterade). Detta gör att Domain blir beroende av Presentation. Det här problemet är mycket välkänt och det finns många olika lösningar på det även om ingen av dem helt eliminerar beroendet. En bra och vanlig lösning som gör kopplingen mycket lös är att använda mönstret Observer. De objekt i Presentation som är intresserade av tillståndförändringar i Domain impementerar då interfacet Observer (se sidan med mönstret Observer). Det betyder att det i Domain bara finns beroenden av det interfacet, inte av klasser som symboliserar fönster på skärmen (vilket vore vansinne). Detta är ett praktexempel på hur tjusigt det är att använda interface för att skapa en typ för en egenskap som beskrivs i avsnittet om Observer och i avsnittet Använd interface för egenskaper skilda från en klass egentliga betydelse på sidan Några tankar om interface.
Diskussion
Fördelar
Nackdelar
Besläktade mönster

MVC (Model Viev Controller)

Problem
Hanteringen i koden av användargränssnittet får inte vara blandad med affärslogiken eftersom det ger extremt dålig sammanhållning och hög koppling.
Lösning
Dela upp systemet i de tre olika delarna model, view och controller. Dessa svara mot lagren Domain, Presentation och Application som definieras i mönstret lager ovan. MVC är egentligen "bara" principer för hur dessa tre lager ska kommunicera med varandra.

Fördelar
Besläktade mönster

Sammanfattning

Vi har nu tittat relativt noga på arbetet med den logiska vyn av arkitekturen, dvs hur vi kan nå eftersträvansvärda design goals (se ovan), detta ingår också i laborationskursen. Anledningen till att vi fokuserat på det är att det i mångt och mycket är "designliknande" och plattformsoberoende kunskaper. Däremot har vi inte tagit upp något om deployment-vyn, dvs hur vi väljer och kombinerar operativsystem, applikationsservrar, hårdvara eller någon annan teknologi eftersom detta egentligen är ett helt annat område än vad den här kursen täcker.

Uppgift

  1. Fundera på indelning i lager för att banksystem.
  2. Skissa på kod för de olika sätten att implementera kommunikationen mellan modellen och vyn i MVC. Upptäcker du några speciella klurigheter? Verkar det vara någon strategi som är speciellt lätt eller svår?