You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
<strong>Carletti</strong> A/S <strong>2012</strong><br />
Lavet af<br />
Mads Pedersen<br />
Robert Kristian Nogal<br />
Frederik Emil Pontoppidan Thygesen<br />
Side 1 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
______________________________________________<br />
Mads Pedersen<br />
______________________________________________<br />
Robert Kristian Nogal<br />
______________________________________________<br />
Frederik Emil Pontoppidan Thygesen<br />
Side 2 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Indhold<br />
Informations Teknologi i Organisationer ............................................................................................. 5<br />
<strong>Carletti</strong> A/S (Robert & Frederik) ..................................................................................................... 5<br />
SWOT (Fælles) ................................................................................................................................ 6<br />
Organisations form (Frederik) ......................................................................................................... 6<br />
Produktionssystem (Mads) ............................................................................................................... 7<br />
Produktions-filosofi ................................................................................................................................... 7<br />
Produktions-layout .................................................................................................................................... 8<br />
Produktionsstyring..................................................................................................................................... 9<br />
Produktionsformer .................................................................................................................................... 9<br />
Business Case (Fælles)................................................................................................................... 10<br />
Formål ...................................................................................................................................................... 10<br />
Forretningsmæssigt omfang .................................................................................................................... 10<br />
IT omfang & krav ..................................................................................................................................... 11<br />
Interessenter ........................................................................................................................................... 11<br />
Alternativ løsning ..................................................................................................................................... 11<br />
Risici ......................................................................................................................................................... 11<br />
Implementeringsstrategi ......................................................................................................................... 11<br />
Organisation ............................................................................................................................................ 12<br />
Key Performance Indicators (KPI) ............................................................................................................ 12<br />
Konsekvens af løsningen ......................................................................................................................... 12<br />
Logistisk effektivitet – hvordan opnås det? (Robert) ..................................................................... 12<br />
Leveringsservice ...................................................................................................................................... 13<br />
Logistikomkostninger .............................................................................................................................. 14<br />
Vurdering af logistiksystemet .................................................................................................................. 15<br />
Software Design ................................................................................................................................. 16<br />
Vision (Fælles) ............................................................................................................................... 16<br />
Krav (Mads & Frederik) ................................................................................................................ 16<br />
Use-cases (Fælles).......................................................................................................................... 16<br />
Use-case oversigt ..................................................................................................................................... 17<br />
Aktør beskrivelse ..................................................................................................................................... 17<br />
Use-case beskrivelser .............................................................................................................................. 17<br />
Sporbarhedsmatrix (Frederik) ................................................................................................................. 19<br />
System sekvens diagram (SSD) (Frederik) .................................................................................... 19<br />
Side 3 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Design sekvens diagram (DSD) (Fælles) ....................................................................................... 21<br />
Analyse Klasse Diagram (Fælles) .................................................................................................. 24<br />
Tilstandsdiagrammer (Mads) ......................................................................................................... 25<br />
Design Klasse Diagram (Fælles).................................................................................................... 26<br />
Arkitektur (Mads) .......................................................................................................................... 29<br />
Testrapport (Mads) ......................................................................................................................... 29<br />
Modultest af Proces-klasse ...................................................................................................................... 29<br />
Use-case test af Opret Opskrift ............................................................................................................... 33<br />
Status (Mads) ................................................................................................................................. 34<br />
Resume af forløbet (Robert) .......................................................................................................... 35<br />
Refleksioner (Robert) ..................................................................................................................... 36<br />
Ordbog ........................................................................................................................................... 37<br />
Software konstruktion ........................................................................................................................ 38<br />
Klassemodel (Fælles) ..................................................................................................................... 38<br />
Implementering af design-modellen ....................................................................................................... 38<br />
Sammenhæng mellem klasserne ............................................................................................................. 38<br />
Polymorfi ................................................................................................................................................. 40<br />
JavaDoc .................................................................................................................................................... 40<br />
Design Mønstre ....................................................................................................................................... 42<br />
Implementering af arkitektur (Robert) ........................................................................................... 45<br />
Fejl håndtering (Frederik) .............................................................................................................. 46<br />
JUnit test (Mads) ............................................................................................................................ 47<br />
Specielt interessant kode (Fælles) .................................................................................................. 49<br />
TimeThread & SystemDato klasserne ..................................................................................................... 49<br />
checkVareStatus & beregnStatus metoderne ......................................................................................... 51<br />
ColorRender-klassen ................................................................................................................................ 53<br />
Guided Tour (Fælles) ..................................................................................................................... 54<br />
Konklusion ......................................................................................................................................... 58<br />
Bilag ................................................................................................................................................... 60<br />
Klassebeskrivelser .......................................................................................................................... 60<br />
Design Klasse Diagram .................................................................................................................. 74<br />
<strong>Carletti</strong> Tidslinje ............................................................................................................................ 75<br />
Side 4 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Informations Teknologi i Organisationer<br />
<strong>Carletti</strong> A/S (Robert & Frederik)<br />
<strong>Carletti</strong> A/S er en dansk chokolade- og slikfabrik, der har eksisteret siden 1918. Siden da er virksomheden<br />
vokset og er i dag en virksomhed, der i 2011, havde en omsætning på 644 mio. kr. 1 . <strong>Carletti</strong> A/S producerer<br />
og sælger et bredt sortiment af chokolade og konfektureprodukter, som findes hovedsagligt i Danmark og<br />
Nordeuropa.<br />
Koncernen er vokset stødt siden da hvor de har in<strong>dk</strong>øbt mange maskiner, fabrikker m.m. For den fulde<br />
tidsoversigt henviser vi til bilaget med tidslinjen over udviklingen. I dag består virksomheden af et<br />
moderselvskab, <strong>Carletti</strong> A/S, samt datterselskaberne, ASM Foods AB i Sverige, samt <strong>Carletti</strong> Polska i Polen<br />
hvor de ejer størstedelen af selskaberne. Derudover har de en stor andel af Oy NIS – Nordic Industrial Sales,<br />
dog uden at have størstedelen.<br />
Hele koncernen har ikke skiftet ejerskab under forløbet og bliver den dag i dag stadig ejet af Givesco A/S i<br />
Give.<br />
Virksomheden består af en forholdsvis dyb funktionsbaseret struktur, med en vertikal arbejdsdeling, der er<br />
baseret på et linje- og stabsprincip. 2 . Dette betyder at centraliseringen dannes i form af et hierarki. I toppen<br />
af dette hierarki finder vi administrerende direktør Niels Petersen, med et kontrolspænd på 7<br />
underafdelinger.<br />
Stabsfunktionen findes i form af in<strong>dk</strong>øbsdirektør Børge Hejlesen, der kan være med til at aflaste linjeledere<br />
og underafdelinger på tværs af organisationsdiagrammet.<br />
Denne type virksomhedsstruktur, der er baseret på funktionsprincippet, er meget typisk for en<br />
stordriftsfungerende produktionsvirksomhed som <strong>Carletti</strong> A/S. Idet der er mulighed for udvikling af<br />
kernekompetencer i nogle standardiserede opgaveudførelser som fx i produktionen.<br />
1 www.carletti.com/default.aspx?ID=471<br />
2 baseret på bilag 1 ”Organisationsdiagram”.<br />
Side 5 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
SWOT (Fælles)<br />
INTERNE SITUATION<br />
Stærke sider (strengths) Svage sider (weakness)<br />
Stor erfaring<br />
Solidt produkt<br />
Malkekos produkter<br />
Produktudvikling<br />
Faste storkunder (indtægter)<br />
Høj indgangsbarriere<br />
Leveringsservice<br />
Stor målgruppe<br />
Stort sortiment<br />
Dedikeret arbejdskraft<br />
Mellemlager problem<br />
Spild i produktion<br />
Sårbare overfor politiske tiltag (fx sukkerafgift)<br />
Finanskrise (en varer der let kan tilsidesættes)<br />
Dragémaskiner kører langsomt<br />
EKSTERNE SITUATION<br />
Muligheder (opportunities) Trusler (threats)<br />
Robotstyret lager og produktion<br />
Større produktudvikling<br />
Opkøbe<br />
Udvide markedet<br />
Flytte produktion til udlandet<br />
Forbedringer i produktionslinjen<br />
(dragéprodukter)<br />
Markedsføring (fx tv)<br />
Finanskrise<br />
Sukkerafgift<br />
Sundhedstrend<br />
Maskinstop<br />
SWOT-analysen er med i denne del af rapporten for at danne grundlag for de øvrige afsnit. For at tage et<br />
eksempel kan vi afsløre at senere i rapporten vil vi have fokus på bl.a. at komme med et forslag til en<br />
løsning der ville kunne løse problemstillingen i form af deres mellemlager-problem. Dette kan ses i SWOTanalysen<br />
som værende en af virksomhedens svage sider. Grunden til SWOT-analysen er med er for at få et<br />
overblik over de ting som virksomheden gør godt, samt virksomhedens svage sider som kan optimeres for<br />
bedre produktion.<br />
Organisations form (Frederik)<br />
<strong>Carletti</strong> A/S kan karakteriseres til at være en blanding af den mekaniske og organiske organisations struktur.<br />
<strong>Carletti</strong>s produktion styres efter ordrebestilling, sæson udsving og i støre mængder til lager bliver<br />
produceret efter tidligere års tendenser.<br />
En produktionsvirksomhed hvor der arbejdes i stabile omgivelser og med gentagne ensformige opgaver, er<br />
det mest effektivt, at designe organisationen efter mekanistiske principper, såsom: stabil arbejdsdeling og<br />
fast produktions rutine, præcise foreskrevne pligter, position i hierarkiet og faste kommunikations kanaler.<br />
Hvorimod virksomheder der skal have en hurtig reaktionsevne til at ændre arbejdsrutinerne, så de passer til<br />
de komplekse opgaver de får ind, er mere effektive ved at anvende de organiske principper – opdeling af<br />
arbejdet varierer efter viden og erfaring, ansvaret bliver mere generelt fordelt og hvor den personlige<br />
erfaring tæller mere end ens position hierarkiet.<br />
Side 6 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Den mekaniske forms stabile og funktionsbaserede arbejdsdeling er mest hensigtsmæssig ved<br />
produktionen af de større faste mængder slik til lageret. Hvor den organiske producerer efter<br />
ordrebestillinger og tidligere års tendenser.<br />
Udgangspunktet for Mintzberg´s model er stabilitet, intern såvel som ekstern og hvordan man kan indstille<br />
strukturen i forhold til stabiliteten.<br />
Produktionssystem (Mads)<br />
For at kunne beskrive det egentlige produktionssystem som danner grund for den storproducerende<br />
<strong>Carletti</strong> Koncern skal man se på de fire dele som udgør dette. I den følgende tekst kan man læse omkring<br />
gruppens analyse af opbygningen af <strong>Carletti</strong>s produktionssystem. De fire dele er: produktions-filosofi,<br />
layout, styring samt form. Dette afsnit er lavet på baggrund af teksten omkring produktion samt logistik.<br />
Produktions-filosofi<br />
Da <strong>Carletti</strong> er en masseproducerende virksomhed inden for konfekture og chokolade ville dette gøre dem<br />
til en perfekt virksomhed til at benytte sig af Ford ismens principper. Når man snakker om Ford ismen<br />
inkludere det automatisk et vist fokus på området omkring høj produktivitet. Dette betyder at man opnår<br />
et så højt output af de specifikke vare hvor der er blevet brugt en så lille ressourceindsats som muligt. For<br />
at optimere denne produktivitet kræver det at man opdeler procesforløbet i forskellige underprocesser<br />
hvor der nemmere kan benyttes forskellige maskiner til at fuldføre denne. Samtidig gør det<br />
arbejdsopgaverne nemmere for de forskellige ansatte da de så kun skal tage sig af en lille, simplere, del af<br />
produktionsprocessen. Dette gør også at det er nemmere at oplærer nye ansatte i virksomhedens<br />
produktion da dette ikke kræver nær så lang tid, grundet den simplificerede proces.<br />
For at tage udgangspunkt i <strong>Carletti</strong> produktionsbeskrivelsen ved produktionen af dragé-produkter kan man<br />
ane brugen af Ford ismen. Denne proces er ideel til at benytte denne da der automatisk er så mange<br />
underprocesser. For at nævne nogle af underprocesserne hvor der indgår forskellige maskiner i kan man<br />
tage fat i:<br />
Støbning af kernen hvor der benyttes kedler<br />
Blanding af basisdrageringen<br />
Tørring af mellem- og færdigprodukter<br />
Påføring af ydre dragering.<br />
Ved hver af disse processer opholder produktet sig et bestemt sted i produktionen hvor lige præcis denne<br />
opgave bliver udført. Når man så står og mangler en medarbejder skal denne medarbejder ikke forstå<br />
hvordan hele produktionen af et dragé-produkt forløber men blot forstå og lære hvordan lige præcis hans<br />
station skal køres. Ulempen kan så være at hvis han skal forflyttes til en anden station i produktionen skal<br />
han på ny oplæres i denne funktion.<br />
Når man så tager fat i den anden kendte produktions-filosofi som kaldes Lean, er der både for og<br />
modargumenter for brugen af denne filosofi i en virksomhed som <strong>Carletti</strong>. En af hovedpointerne i denne<br />
filosofi er at man skal undgå at producere til et færdigvare-lager da dette gør at produktet bliver dyrere for<br />
kunden eftersom et lager medfører ekstra omkostninger. Dog kan det være svært for en virksomhed som<br />
<strong>Carletti</strong> at være så dynamiske at de hele tiden kan skifte deres produktions-opsætning til fordel for de<br />
forskellige kunders behov. Her er det relevant at finde en mellemvej hvor der stadig bliver benyttet et lager<br />
så kunderne altid kan få deres vare efter deres eget behov. Det at indføre en ren Lean filosofi som værende<br />
den eneste er ikke optimalt for virksomheder der producere i så stor kvantitet som en virksomhed af<br />
<strong>Carletti</strong>s størrelse.<br />
Dette kan forstås i forhold til et eksempel hvor en stor kunde laver en uforudset bestilling som en Lean<br />
tilgang ellers ikke ville kunne producere. Hvis denne storkunde ikke får sine vare til tiden kan <strong>Carletti</strong><br />
risikere at miste kunden fordi de ikke havde varerne til tiden pga. Produktionssystemets filosofi. Derfor er<br />
Side 7 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
det vigtigt for en producent som dem at have et relativt stort lager så det ikke er grundet overskredne<br />
deadlines at kunder evt. forsvinder.<br />
Lean-tilgangen bliver derfor oftest benyttet på producenter der har forholdsvist små ordrestørrelser og<br />
derfor kan omstille sig meget hurtigt til de forskellige kundebehov der er i forhold til ordrene.<br />
Det en Lean-manager dog kan gøre i en virksomhed som <strong>Carletti</strong> er at se på de processer som allerede<br />
eksistere og gå ind og optimere på disse. Som et eksempel kan det være at Lean-manageren skal<br />
omrangere produktions-layoutet for at optimere det vare-flow der er, sørge for at spild på mellem-vare<br />
lageret bliver minimeret og andre lignende optimeringer. Her er det også aktuelt for at snakke om selve<br />
opgaveformuleringens problem stilling. Det at et mellem-vare lager er en flaskehals vil også være et af de<br />
områder som ville kunne løses af en Lean-manager.<br />
Produktions-layout<br />
Det er meget begrænset hvad vi igennem den udleverede beskrivelse har fået at vide omkring det fysiske<br />
layout af mellem-lager rummet samt produktionen i hele taget. Derfor holdes der fokus på det som der<br />
rent faktisk er viden om, nemlig mellemlageret hvor de forskellige bakker bliver lagret til tørring i perioder<br />
med forskellig tidslængde.<br />
Det der sker når en produktion har færdiggjort en proces som kræver en tørretid er at køre den ind og<br />
sætte den på mellem-lageret hvor den så, ved hjælp af ruller, bliver transporteret ned i den anden ende<br />
hvor den bliver plukket til dragering.<br />
Her kan man måske overveje om de forskellige procesforløb ikke skal have hver deres række eller endda<br />
deres helt eget niveau så man hele tiden kan holde styr på hvilken proces de skal til næste gang de bliver<br />
plukket. Men mere om det senere.<br />
Når man skal sammenholde det med den udleverede teori kan man begynde at argumentere for og imod<br />
forskellige typer af layouts. Som et eksempel kan man godt argumentere for at <strong>Carletti</strong> benytter et<br />
funktionslayout eftersom man kunne antage at der ikke var en lakridsstøbe kedel for hver type slik som<br />
benytter en eller anden lakrids komponent i den. Her vil man nok have et centralt lakridsstøbe kedel rum<br />
hvor al lakrids i virksomheden ville blive produceret hvor det efterfølgende vil blive transporteret videre til<br />
de processer som tager udgang i grundproduktet lakrids.<br />
Samtidig med at de måske benytter sig af et funktionslayout kan man også kigge på andre typer, så som<br />
linjelayoutet, flow produktionen. Som nævnt før er <strong>Carletti</strong> en virksomhed som producere en stor kvantitet<br />
af standardiserede vare, både ud fra ordre men også til lagering. Her vil et linjelayout være ideelt da der<br />
bliver produceret store mængder af det samme produkt på en kontinuerlig linje uden sideløbende<br />
produktioner af andre produkter (der ses her bort fra at de sandsynligvis har en fælles lakridsstøbe<br />
produktion til mange produktprocesser). Dette layout bliver benyttet til de produkter i et firma som firmaet<br />
ved, pr. statistik og erfaring, er rentable og de er sikre på at kunne få afsat. Dette kan i <strong>Carletti</strong>s tilfælde<br />
være skumbananer og P-tærter som de har stor succes med at sælge.<br />
Ser man det fra en medarbejders synspunkt kan denne type layout blive meget umotiverende og<br />
ensformigt hvilket i værste tilfælde vil resultere i utilfredse medarbejdere. Her er det en god ting at <strong>Carletti</strong><br />
har multifunktionelle medarbejdere som hele tiden kan finde nye produktionsforløb at indgå i hvis de<br />
finder den nuværende monotom. På den måde får man en mere fleksibel arbejdsstyrke som gør at man<br />
ikke ligger inde med produktionsforløb der er afhængig af specialiserede medarbejdere som ikke ville<br />
kunne erstattes af andre. Dette problem har de dog med de medarbejdere der ligger inde med nogle af de<br />
få truckcertifikater. Dette er et typisk specialiseringsproblem hvor firmaet kan risikere store<br />
flaskehalsproblemer hvis disse medarbejdere er syge.<br />
Ud fra alt dette kan man komme med begrundelser for at disse to typer layout kombineret giver et gruppelayout<br />
som passer på <strong>Carletti</strong>s produktion som blev klassificeret som en jobshopproduktion. Dette giver<br />
nemlig et miks mellem linje og funktionslayout som gør at de kan kører små serier med svingende<br />
afsætning i selvstyrende teams.<br />
Side 8 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Produktionsstyring<br />
Da teksten på dette område har været meget sparsom omkring viden på produktionsstyrings området kan<br />
vi dog kun komme ind på principperne og drage paralleller til den sparsommelige viden fra teksten.<br />
Produktionsstyringen består som basis af to dele, nemlig en planlægningsdel samt en overvågningsdel.<br />
Planlægningsdelen er typisk en funktion som bliver håndteret på mellemleder niveau, bl.a. fordi det er for<br />
administrativt for folket på gulvet og det ve<strong>dk</strong>ommer bl.a. heller ikke virksomhedens øverste direktør. På<br />
<strong>Carletti</strong> ville denne opgave typisk gå til produktionsplanlæggerne Peter og Leif. De vil få de forskellige<br />
ordrer passet ind så leveringstidspunktet samt kvantiteten bliver overholdt så det resultere i kunder der<br />
kommer igen. Når man så kigger på overvågningssystemet af produktionsstyringen bliver man nød til at<br />
lave nogle antagelser når det kommer til den konkrete virksomhed, i dette tilfælde <strong>Carletti</strong>. I denne<br />
virksomhed vil det typisk være en teamleder som rapportere til produktionsplanlæggerne om de<br />
overholder tidsplanen eller om planerne skal omlægges så de kommer til at passe.<br />
Produktionsformer<br />
Når man ser på de forskellige produktionsformer som bliver nævnt i den udleverede tekst er der to former<br />
giver mere mening at benytte i virksomheden <strong>Carletti</strong>. Den ene er typen jopshop produktionsformen. Det<br />
er her virksomhedens forskellige vare er standardiseret i forskellige udgaver som bliver produceret i små<br />
serier flere gange om året. Dog kan man debattere hvornår noget er i små serier, men ikke desto mindre<br />
kan man argumentere ud fra oplægget.<br />
Det der sker for <strong>Carletti</strong> nogle gange om året er at de enten får en stor ordre som kræver at hele fabrikken<br />
bliver omstillet på at producere lige præcis den kundes ordre, eller hvis det f.eks. bliver jul hvor der<br />
igennem prognoser for salg har vist sig at kræve ekstra arbejde for at holde trit med udbud og<br />
efterspørgsel. Dette kan argumentere for at <strong>Carletti</strong> benytter jobshop formen.<br />
Når det kommer til et argument for at <strong>Carletti</strong> benytter sig af flowproduktions formen kan man gå ind og se<br />
på hvor ofte deres produktion bliver omstillet for at tilgodese et specifikt produkt eller ordre. Hvis der dog<br />
forekommer relativt få omstillinger om året kan man godt argumentere for at virksomheden benytter<br />
flowproduction. Mens hvis der sker en omskiftning f.eks. to gange om måneden er virksomheden nok<br />
tættere på at benytte en jobshop form.<br />
Det der argumentere for en flowproductions form lige meget omstillings hyppigheden er det flow som<br />
produkterne gennemgår. Dette flow minder meget om en standard samlebånds princip som er en fast del<br />
af flow-produktions virksomheders opbygning.<br />
Side 9 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Business Case (Fælles)<br />
Formål<br />
At få en bedre styring af mellemvarelageret, så tørretiderne bliver overholdt bedre og spildet formindskes.<br />
Forretningsmæssigt omfang<br />
En opdeling af mellemvarelageret, tilsvarende de 3 tørretidskategorier: min, perfekt og maks. Det skal<br />
fortsat fungere efter FIFO-princippet for at få en bedre styring af pluknings-rækkefølgen og sørge for at<br />
produkterne får den rette tørreperiode. Hvis der er en dominerende størrelse indenfor en bestemt<br />
kategori, så skal dette område kunne overtage den ubrugte plads fra de andre kategoriers lagerdel.<br />
For at holde styr på bakkernes indhold og vedrørende informationer implementeres hver bakke med en<br />
RFID-chip. Denne chip bruges også til at lokalisere bakkens placering og resterende tørretid. For at denne<br />
løsning kan anses for at værende succesrig, skal det systemet kunne måle den maksimale spildprocent på 2<br />
% - alt over ville vise løsningen værende ineffektiv.<br />
En problemstilling ved denne løsning ville være at brugeren i mellemvarelageret ikke får lagt den rette<br />
information ind i bakkens chip, hvilket vil resultere i at bakkens indhold ikke vil være brugbart. Dette vil<br />
resultere i et yderligere spild i stedet for det ønskede resultat.<br />
De berørte brugere er de ansatte der styrer mellemvarelageret, der skal efteruddannes i brugen af det<br />
implementerede system. Dette inkluderer både indtastningen af information til chippen, samt placeringen<br />
af pallen på dens rette placering. Derudover skal brugerne også kunne aflæse bakkens information korrekt<br />
og derved få plukket korrekt.<br />
Side 10 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
IT omfang & krav<br />
Først og fremmest skal chippen fungere og implementeres i bakkerne. Når bakkerne kommer ind på<br />
mellemvarelageret skal de forbi et check-in ved indgangen, hvor informationen bliver skrevet til chippen,<br />
som blandt andet inkluderer dead-line for endt tørretid. Dette bliver gjort igennem computer. Det skal<br />
være muligt at aflæse bakkens information på et givent tidspunkt med en håndholdt scanner. Efter endt<br />
tørretid vil en alarm gøre medarbejderen opmærksom på at bakken/pallen skal sendes videre til<br />
forarbejdning. Bakkens placering kan ses på en skærm i lageret placeret og evt. på en skærm på trucken.<br />
På denne måde sikres det at den rette bakke bliver taget på det rette tidspunkt. Når bakken forlader<br />
mellemvarelageret skal det checkes ud. Systemet er delt op i 2 under systemer, overvågningsdelen og<br />
registrerings delen.<br />
Så hele systemet kommer til at bestå af RFID-chips i bakkerne, skærme til at aflæse bakkernes placering,<br />
samt scannere til aflæsning og indlæsning af data. Alt i alt bliver der brugt eksisterende og velfungerende<br />
teknologier, hvilket gør at der ikke skal investeres i yderligere udvikling.<br />
ID Beskrivelse Type Prioritet<br />
1 Systemet skal have en alarm funktion ved endt tørretid Funktionelt M<br />
2 Skal kunne vise en placering på et display Funktionelt M<br />
3 Chippen i bakkerne skal kunne læses og ændres efter behov Funktionelt M<br />
4 Systemet skal være brugervenligt og overskueligt Ikke<br />
funktionelt<br />
S<br />
5 Oppetid på minimum 98 %. Stabilt og driftssikker, samt hurtigt. Ikke<br />
funktionelt<br />
M<br />
6 Nemt at brugerdefinere til andre lagere Funktionelt C<br />
7 Hver bakke skal kunne læses på et givent tidspunkt af en Funktionelt<br />
skanner.<br />
S<br />
8 Muligt at printe en liste med alle bakker og deres informationer Funktionelt S<br />
Interessenter<br />
Interessenterne i dette system er hovedsagligt personalet der er tilknyttet mellemvarelageret, som direkte<br />
kommer til at bruge det. Derudover kan der argumenteres for at mellemledelse samt topledelsen har<br />
interesse i systemet eftersom det vil formindske spildet og forøge overskuddet.<br />
Alternativ løsning<br />
Nulløsningen ville være at fortsætte med det nuværende system og dermed acceptere spildet på min. 2 % -<br />
hvilket er et tabt pr. måned på minimum 270 000 kr. (30 000 kg*15 kr.*30 dage *0,02). Denne løsning løser<br />
intet!<br />
Risici<br />
En risiko kunne være at implementerings fasen bliver meget lang og brugerne har svært ved at vende sig til<br />
det nye system, dermed vil produktionsstyrken blive nedsat og der kan så opstå længere leveringstider.<br />
Eftersom dette system skal udvikles fra bunden vil der også være behov for opgradering når fejl findes.<br />
Dette kan også medføre stillestående produktion i visse tilfælde.<br />
Implementeringsstrategi<br />
Alt hardware installation foregår imens den daglige produktion foregår mere eller mindre uforstyrret. Dette<br />
gøres ved at nogle teknikkere bliver sendt ud på fabrikken for at sætte skærme og scannere til og chippen i<br />
bakkerne bliver implementeret når de løbende bliver ”ledige”.<br />
Når alt udstyret er sat til og funktionstestet skal de forskellige teams fra fabrikken undervises i brugen af<br />
det nye system. Dette inkluderer brug af scannere, samt benyttelse af skærmene til plukning af bakker.<br />
Side 11 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Dette kunne evt. foregå over en weekend i fabrikkens konference lokaler, hvor de ansatte også kommer ud<br />
og kan afprøve systemet grundigt igennem med en tekniker/underviser.<br />
Organisation<br />
Gruppen vil være repræsenteret som projektejere og har dermed ansvaret for evt. opdatering af business<br />
case. Gruppen er blevet nøje sammensat efter individuelle spidskompetencer og er derfor velkvalificeret til<br />
at løse <strong>Carletti</strong> A/S problemstilling.<br />
Key Performance Indicators (KPI)<br />
Det gennemgående nøgletal i denne case er spildprocenten på maks. 2 %. Problemstilling vil vise sig<br />
værende løst eller ej når spildprocenten ligger stabilt under 2 %.<br />
Konsekvens af løsningen<br />
Omkostninger til systemudvikling, hvilket inkluderer hardware så vel som software udvikling, vil blive dens<br />
største post i forløbet med implementering af systemet. Disse omkostninger kan forsvares, hvis man<br />
sammenligner dem med hvad virksomheden taber på nuværende tidpunkt pr. måned. Hvis vi antager at<br />
prisen for det færdige fungerende produkt ender på 1 million kroner og at de i øjeblikket har en spild<br />
procent på 4, vil det efter 4 måneder begynde at give overskud – eftersom systemet garanterer en<br />
maksimal spildprocent på 2. Hvis virksomheden er villig til at investere dette beløb vil resultatet hurtigt<br />
kunne måles.<br />
Logistisk effektivitet – hvordan opnås det? (Robert)<br />
Logistik stammer fra det græske ord logistikos og blev oprindeligt brugt i militære sammenhænge omkring<br />
håndteringen af forsyning i kamp. Lidt på samme måde bruger vi logistik i erhvervsmæssige<br />
sammenhænge, som færdigheden i håndtering og styring af blandt andet varer og informationer. Helt<br />
præcist inkluderer det strategisk håndtering af in<strong>dk</strong>øb, transport, lagring, varer samt de dertil hørende<br />
knyttede procedurer.<br />
Side 12 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Vi vil derfor lægge vægt på, hvad det betyder at være logistisk effektiv, ved at tage udgangspunkt i noten<br />
om logistik, der betegner effektiviteten som værende indeholdende to modsatrettede mål, nemlig<br />
leveringsservice samt logistikomkostninger. Hvert af disse mål indeholder nogle deleelementer, som vi vil<br />
gennemgå og diskutere hvordan kommer til udtryk hos <strong>Carletti</strong> A/S.<br />
Logistisk effektivitet<br />
Leveringsservice Logistikomkostninger<br />
Leveringstid<br />
Lagerservicegrad<br />
Leveringsoverholdelse<br />
Leveringsfleksibilitet<br />
Leveringsinformation<br />
Lageromkostninger<br />
Transportomkostninger<br />
Emballage- og<br />
håndteringsomkostninger<br />
Administrative omkostninger<br />
Mangelomkostninger<br />
Kort om de to mål kan der siges, at leveringsservice er en del af virksomhedens forhold til kunder i form af<br />
kundeservice (fx kort leveringstid som forøger salgsvolumen), mens logistikomkostninger indbefatter de<br />
omkostninger der skal til hos virksomheden, for at overholde den leveringsservice man stræber om at opnå<br />
til kunderne(fx lagerføre varer så man kan opnå kort leveringstid).<br />
Logistisk effektivitet er altså et samspil mellem disse to mål og kan for eksempel vurderes på at levere en<br />
god service og et godt produkt for at beholde og tiltrække potentielle kunder på en så omkostningseffektiv<br />
levering af in<strong>dk</strong>omne ordre som muligt.<br />
Vi vil nu komme ind på nogle af de forskellige delemner<br />
Leveringsservice<br />
Leveringstiden går ud på, hvor hurtigt en kunde får sin vare, fra ordren er givet til kunden har modtaget<br />
varen. Denne proces kaldes også den logistiske leveringstid og indeholder fem delelementer.<br />
Afhængigt af, hvilken ordre der er givet behøves alle delelementer ikke indgå i en ordre. Da <strong>Carletti</strong> A/S<br />
arbejder både i jobshop-produktionsform og flow-produktionsform, betyder det at de har mange varer på<br />
lager, men at de samtidigt kan omstille sig til specialordre.<br />
At <strong>Carletti</strong> A/S har mange varer på lager, kan vi se ud fra et billede taget på <strong>Carletti</strong> A/S 3 (reference), som<br />
viser at de har en lagerservicegrad i gennemsnit på cirka 98 %. Lagerservicegrad regnes som en procentvis<br />
størrelse og er altså et tal der viser hvor mange ordrer der leveres direkte fra et lager.<br />
Antager vi, at der gives en ordre udelukkende indeholdende en meget populær vare som fx skumbananer,<br />
kunne man forestille sig, at denne ordre leveres direkte fra et lager. I sådan en situation, vil leveringstiden<br />
være kort, da ordren kun bliver berørt af en administrativ afdeling der tager imod ordren og betaling, og<br />
derefter distributionsafdelingen der sender varen.<br />
Antager vi, at det er en ordre der kræver at <strong>Carletti</strong> A/S skal lave produktet fra bunden af, går ordren<br />
igennem alle fem punkter. Teknisk ordrebehandling der laver beregninger for hele ordren (det kan fx være<br />
udregning af estimeret leveringstid, pris osv.), en administrativ afdeling, in<strong>dk</strong>øbets leveringstid der står for<br />
in<strong>dk</strong>øb af råvarer til produktion, produktionen samt distributionen.<br />
3 Udleveret materiale ”<strong>Carletti</strong> billeder til ITO”<br />
Side 13 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
For at levere en god kundeservice, skal man også kunne overholde leveringstiden, for blandt andet skabe<br />
tillid til kunderne og skabe et godt ry.<br />
I dette projekt har vi en problemstilling, der består af nogle problemer på et mellemvarelager og ifølge en<br />
dansk undersøgelse fra 2002 4 , er det også i produktionen at de fleste forsinkelser opstår. Her kan der altså<br />
opstå leveringsoverholdelsesproblemer. <strong>Carletti</strong> har som sikkerhed til kunderne, hvis <strong>Carletti</strong> skulle gå hen<br />
og være forsinket i leveringen, en aftale med kunder på forhånd, om en bøde til <strong>Carletti</strong> A/S.<br />
Fleksibiliteten kan måles i mange forskellige aspekter. Produktfleksibilitet vedrører evnen til at levere nye<br />
produkter. Her er <strong>Carletti</strong> A/S meget fleksible, ifølge årsrapporten lægges der stor vægt på udvikling af nye<br />
produkter 5 og ganske vist er der på deres hjemmeside også information om tre typer nyt slags slik 6 .<br />
Funktionsfleksibilitet vedrører evnen til at levere forskellige varianter af samme varetype. <strong>Carletti</strong> A/S har<br />
en gang i en haste sag taget imod en ordre der skulle lave en type slik om til kosher-slik. Dette må siges at<br />
være utrolig fleksibelt, men samtidig blev de også betalt godt for dette 7 . <strong>Carletti</strong> A/S ligger desuden inde<br />
med over 100 opskrifter chokolade 8 , og man kunne godt forestille sig, at de kunne ændre<br />
chokoladeopskriften i en bestemt type vare, hvis ønsket.<br />
Leveringsinformationen er et svært punkt at komme ind på, da vi ikke rigtig ved hvordan <strong>Carletti</strong> A/S<br />
samarbejder helt præcist med sine kunder, udover de føromtalte sanktioner til dem selv.<br />
Logistikomkostninger<br />
Logistikomkostninger er som nævnt tidligere, en slags styring mod, hvordan man vil opnå den ønskede grad<br />
af leveringsservice.<br />
<strong>Carletti</strong> A/S har en relativ høj lagerservicegrad, hvilket betyder at de har bundet meget kapital i form af<br />
varer i store lagre, hvilket er en del af lageromkostninger. Ifølge årsrapporten 9 ligger de inde med<br />
varebeholdning for cirka 31 mio. kr., som også er en lageromkostning. Disse lagre kræver også de<br />
omkostninger de indbefatter(husleje, varme osv.).<br />
Da <strong>Carletti</strong> A/S både er masseproducerende, men samtidig også kan tage imod specialordre, må de også<br />
have maskiner til at kunne omstille sig efter ordre og behov. Dette må kræve avancerede maskiner, som<br />
også er en del af lageromkostninger.<br />
Valget om transportform har stor betydning for den logistiske effektivitet. Selve omkostningerne hos<br />
<strong>Carletti</strong> A/S er svære at vurdere, dog ses en gæld hos leverandører på cirka 16 mio. kr. 10 .<br />
<strong>Carletti</strong> A/S’s marked strækker sig over Danmark og Nordeuropa. Det er derfor måske sandsynligt, at der<br />
ikke er behov for dyre transportmidler som fx fly, men derimod noget billigere som fx tog.<br />
<strong>Carletti</strong> A/S har ikke de største omkostninger mht. emballage. Meget af <strong>Carletti</strong> A/S slik er pakket i standard<br />
plastikposter og med relative simple design. Pakningen af deres produkter sker fuldautomatisk på<br />
fabrikken, og nogle varer bliver endda ikke rørt af menneskehænder fra råvarerne bliver sendt fra fx Afrika,<br />
til kunden har slikket i hånden 11 . Disse maskiner skal selvfølgelig købes, men pengene bliver nok tjent hjem<br />
igen, i forhold til at have personer til at pakke.<br />
4 Note fra Fronter ”Logistikmål og logistikstrategier”<br />
5 Udleveret materiale ”Årsrapport del 1 – side 9”<br />
6 www.carletti.com/Default.aspx?ID=467<br />
7 Undervisning + www.hebrewear.com– her ses en pose slik af ”Kosher Balls” til 20 pund pr pose. (produktet findes<br />
ved at søge på ”Balls” i søgefeltet)<br />
8 Bilag 2 i udleveret ITO projekt-materiale<br />
9 Udleveret materiale ”Årsrapport del 1 – side 21”<br />
10 Udleveret materiale ”Årsrapport del 1 – side 22”<br />
11 Bilag 2 i udleveret ITO projekt-materiale<br />
Side 14 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Vurdering af logistiksystemet<br />
Grundet de mange kvalitative metoder logistisk effektivitet er baseret på, samt den begrænsede<br />
information tilgængelig, er det svært at give en helhedsvurdering af logistisk effektivitet hos <strong>Carletti</strong>. Vi har<br />
dog valgt at sammenligne nogle tal, fra nok den største danske slikproducent Toms med <strong>Carletti</strong> A/S, for<br />
derefter at give en vurdering.<br />
Vi kunne godt have tænkt os at vide mere om selve produktionen af fx dragéprodukterne. Ifølge<br />
procesbeskrivelsen af dragéprodukter 12 , tager denne produktion 1-2 uger. Vi har dog ingen information<br />
om hvor lang hver proces er, udover to gange tørring som tager ”nogle dage”. Antager vi, at ”nogle dage”<br />
er to dage, kunne det godt ligne at vi har nogle logistikproblemer i forhold til hele processens længde på<br />
hele to uger, da også markedet ikke strækker sig længere end Nordeuropa.<br />
Her kan der måske være problemer med leverandører der er for langsomme. Desuden opstår der<br />
flaskehalsproblemer på mellemlageret, da selve dragéringsprocessen ikke kan følge med selve<br />
produktionen, hvilket også er et logistisk problem.<br />
Ser vi bort fra dette og sammenligner med Toms 13 , kunne det måske alligevel tyde på, at <strong>Carletti</strong> A/S’s<br />
logistiksystem er ret velfungerende, dog har det sin pris.<br />
12 Udleveret ITO projekt-materiale side 12<br />
13 De følgende udregninger er lavet ud fra bilag 3<br />
Side 15 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Software Design<br />
Vision (Fælles)<br />
It-systemets formål er at understøtte en rationalisering af arbejdsgangene i forbindelse med<br />
mellemvarelageret hos <strong>Carletti</strong> samt at minimere spildet i forbindelse med dragering og tørring.<br />
Krav (Mads & Frederik)<br />
ID Beskrivelse Type Prioritet<br />
K1 Enkeltbrugersystem Funktionelt M<br />
K2 Afvikles på en almindelig computer Ikke Funktionelt M<br />
K3 Skal kunne finde næste portion der skal plukkes Funktionelt M<br />
K4 Det skal være hurtigt og nemt at finde placeringen på den<br />
ønskede portion.<br />
Ikke Funktionelt M<br />
K5 Systemet skal kunne vise de portion som er klar til plukning Funktionelt M<br />
K6 Systemet skal kunne registrere en portion & en opskrift og<br />
dens behandlingsforløb.<br />
K7 På en behandling skal det være muligt at registrere<br />
minimums, ideal og maksimum tørretid.<br />
K8 Det skal være muligt at kunne oprette en portion i systemet<br />
og registrere påbegyndt tørretid (timestamp).<br />
K9 Man skal med systemet kunne kalde en oversigt frem over<br />
portioner der står til tørring, der har overskredet maksimal<br />
tørretid.<br />
K10 Systemet skal kunne beregne den gennemsnitlige tid en<br />
portion befinder sig på lageret.<br />
K11 Skal kunne holde styr på hvor mange portioner der når at<br />
blive forældet.<br />
K12 Systemet skal kunne beregne den optimale placering af en<br />
portion ud fra FIFO-princippet<br />
Funktionelt M<br />
Funktionelt M<br />
Funktionelt M<br />
Funktionelt S<br />
Funktionelt S<br />
Funktionelt S<br />
Funktionelt S<br />
K13 Informationerne skal gemmes i en relationel database Funktionelt M<br />
Use-cases (Fælles)<br />
Følgende afsnit beskriver de use-cases vi er kommet frem til. Disse bliver uddybet igennem brug af vores<br />
use-case skabelon.<br />
Side 16 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Use-case oversigt<br />
ID Navn<br />
U1 Find vare<br />
U2 Pluk vare<br />
U3 Beregn gennemsnitlig tid på lager<br />
U4 Beregn antallet af forældede mellemvarer<br />
U5 Print oversigt<br />
U6 Opret opskrift<br />
U7 Opret portion<br />
U8 Registrer behandling<br />
U9 Tilknyt behandling<br />
Aktør beskrivelse<br />
Brugerne af dette system vil være almene lagerarbejdere og en lagerchef, hvor vi antager at deres IT<br />
kunnen er begrænset. Systemet vil blive brugt i den daglige drift.<br />
Use-case beskrivelser<br />
Use Case Name: U6 - Opret opskrift<br />
Scenario: Lagerchef opretter en opskrift<br />
Trigger Event: Der skal oprettes en opskrift<br />
Brief Description: Der oprettes en opskrift til brug i systemet<br />
Actors: Lagerchefen<br />
Related use cases: Opret eller tilføj behandling<br />
Postcondition: Opskrift oprettet<br />
Flow of events: Actor<br />
1. Lagerchefen taster navn ind i<br />
systemet<br />
Exceptional<br />
Flows:<br />
2. Lagerchefen opretter opskrift eller<br />
tilknytter behandling.<br />
System<br />
1. Systemet gemmer opskrift<br />
med navn.<br />
Side 17 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Use Case Name: U2 - Pluk vare<br />
Scenario: Lagermedarbejder skal plukke en vare<br />
Trigger Event: Varen er færdig med at tørre eller tørret for lang tid.<br />
Brief Description: Når en vare er færdig med at tørre eller tørretiden er for længe – skal den<br />
flyttes videre til behandling eller til spild.<br />
Actors: Lagermedarbejder<br />
Related use cases: Frigør lokation<br />
Stakeholders <strong>Carletti</strong> A/S<br />
Precondition: Der er en vare på lager<br />
Postcondition: Varen er flyttet til viderebehandling<br />
Flow of events: Aktør<br />
1. Lagermedarbejder finder varen<br />
i systemet<br />
2. Varen sendes til<br />
viderebehandling<br />
Exceptional<br />
Flows:<br />
Use Case Name: U7 - Opret portion<br />
System<br />
1. Placering vises<br />
2. Placering bliver frigjort<br />
Scenario: Produkt/portion kommer fra produktionen og skal behandles i form af tørring<br />
og/eller dragering.<br />
Trigger Event: Portion skal behandles<br />
Brief Description: Portionen får et varenummer, en start tid og bliver tilknyttet en behandling<br />
Actors: Lagerchefen<br />
Related use cases: Tilknyt behandling<br />
Stakeholders <strong>Carletti</strong> A/S<br />
Precondition: Der kommer et produkt/portion til<br />
mellemlager<br />
Postcondition: Portion oprettet med tilknyttet behandling<br />
Flow of events: Aktør<br />
Exceptional Flows:<br />
1. Lagerchefen opretter<br />
portion<br />
System<br />
1. Portion oprettes med<br />
navn, id og start tid<br />
1.1 Der tilknyttes<br />
behandling(tørring<br />
og/eller dragering)<br />
Side 18 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Sporbarhedsmatrix (Frederik)<br />
Tabellen viser sammenholdet imellem vores use cases og de liste krav fra kravspecifikationen,<br />
ID K1 K2 K3 K4 K5 K6 K7 K8 K9 K10 K11 K12 K13<br />
U1 X X X X<br />
U2 X X X X X<br />
U3 X X X<br />
U4 X X X<br />
U5 X X X X<br />
U6 X X X X<br />
U7 X X X X<br />
U8 X X X<br />
U9 X X X<br />
System sekvens diagram (SSD) (Frederik)<br />
System sekvens diagrammer har vi brugt til at illustrerer hvordan en use-case interagerer imellem aktøren<br />
og systemet. Dette skaber en forståelse for hvordan systemet fungerer, ved at bruge en beskrivelsesform<br />
der ligger sig tæt til programmeringsformen.<br />
Opret opskrift – U6:<br />
Aktøren i denne use case er lagerchefen som interagerer med systemet.<br />
Lagerchefen opretter en opskrift ved at indtaste navnet på opskriften og tilknytte behandlinger. Den<br />
oprettede opskrift kan nu ses på listen.<br />
Side 19 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Opret portion – U7:<br />
Aktøren i denne use case er lagerchefen som interagerer med systemet.<br />
Lagerchefen opretter en portion ud fra den valgte opskrift, som indeholder behandlinger og<br />
behandlingsindeks. Her tildeles portionen et id og en starttid per automatik. Efter oprettelse bliver<br />
portionen flyttet til lageret og behandlingen går i gang.<br />
Pluk vare – U2:<br />
Aktøren i denne use case er lager medarbejderen som interagerer med systemet.<br />
Systemet viser at en portion er færdig med den igangværende behandling, og dermed at den er klar til<br />
plukning dvs. at portionen enten skal sendes videre til den nye behandling eller til pakning. Når portionen<br />
sendes til pakning bliver den placering frigjort.<br />
Side 20 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Design sekvens diagram (DSD) (Fælles)<br />
Design sekvens diagram er en udvidelse af SSD. Her udvides beskrivelsen så den ligger nærmere<br />
programmeringssproget, hvilket der er det centrale i DSD. Dette design giver et tilnærmelsesvis billede af,<br />
hvordan den specifikke use case en gang skal kodes.<br />
Opret opskrift:<br />
Der bliver oprettet en ny opskrift igennem service klassen, som kalder contructeren i Opskrift. Det nye<br />
objekt bliver returneret og tilføjet til listen i Dao. Ud fra en liste af behandlinger tilføjes disse til opskriften<br />
og der tildeles behandlingsindekser til behandlingerne. Processen i at tilføje behandlinger foregår i et loop<br />
da der kan være 1 til mange behandlinger.<br />
Side 21 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Opret portion:<br />
Når der oprettes en portion, går vi igennem den pågældende Opskrift og tilføjer den en portion. Da vi i<br />
oprettelsen af opskriften har tilknyttet dens behandlinger, kan vi igennem portionen oprette processer,<br />
hvor der tilknyttes netop opskriftens behandlinger, behandlingsindeks samt starttider og behandlingen kan<br />
gå i gang.<br />
Side 22 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Pluk vare:<br />
I denne use case forestiller vi os eksemplet hvor varen er blevet for gammel og derfor tilføjes til spild. Når<br />
portionen bliver markeret i listen over processer, har vi fat i en portions aktuelle proces hvor netop denne<br />
proces’ status bliver beregnet. Får vi som i eksemplet returneret statustypen ”old”, fjernes portionen fra<br />
lageret og portionen tilføjes til spildlisten.<br />
Side 23 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Analyse Klasse Diagram (Fælles)<br />
Dette diagram er som titlen indikerer meget generelt, derfor bliver klasserne forklaret i forhold til de<br />
koncepter og begrebsområder titlerne dækker over. Hvis større detalje ønskes, henledes<br />
opmærksomheden til Klassebeskrivelserne.<br />
Som en start kan man tage udgangspunkt i det man kan kalde systemets centrale klasse, nemlig Opskriftsklassen.<br />
Ud fra denne klasse bliver hele produktionsforløbet oprettet igennem. Det vil sige at det er denne<br />
klasse der kommer til at stå for oprettelsen af Portioner samt holde styr på den rækkefølge en Portion skal<br />
gennemgå for at kunne blive erklæret færdig. Dernæst kan man se på de forskellige behandlinger som en<br />
Portion skal igennem.<br />
De konkrete klasser er alle sammen en udvidelse af en fælles superklasse så det er muligt at have en<br />
generel liste i de forskellige klasser der finder dette nødvendigt. Disse Behandlings sub-klasser kan oprettes<br />
udenom fx Opskrift-klassen. Dette er fordi det skal være muligt for mange forskellige opskrifter at benytte<br />
sig af en fælles behandling fx Tørring, som har de samme minimum, ideel og maksimum værdier for<br />
tørretider. Der ville ikke være nogen grund til at tvinge oprettelsen af behandlinger til at skulle gå gennem<br />
en anden klasse. Dette bevirker også en hvis grad af re-use.<br />
Ligeledes har vi Placerings-klassen som også kan oprettes uden at skulle igennem en anden klasse. I dette<br />
design går vi ud fra at lageret består af et stort firkantet areal som kan omdannes til et stort gitter så det er<br />
muligt at benytte x og y koordinater til at lokalisere en given Portion som står til tørre.<br />
I designet er der også inkluderet to associationsklasser der er der af to forskellige grunde. Til at starte med<br />
kan man kigge på Proces-klassen. Lige præcis denne klasse giver designet et sted hvor man kan trække en<br />
hvis mængde statistik ud fra. For at tage et eksempel kan det være at man gerne ville gennemløbe en<br />
Portions processer for at finde ud af hvor lang tid den har stået til tørring. Det er her Proces-klassen<br />
kommer ind. Den indeholder både start og stop tider for alle de behandlinger en Portion har været<br />
igennem, som alle vil blive gemt i en liste i Portions-klassen. Den anden associationsklasse i designet er<br />
BehandlingsIndeks-klassen. Denne klasse er der for at holde styr på den rækkefølge en Opskrifts forskellige<br />
Side 24 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
behandlinger skal komme i. Disse objekter af denne type bliver opbevaret i Opskrift-klassen, hvor en<br />
portion altid har styr på hvilket indeks den er kommet til, hvor opskrift-objektet så kan kalkulere den næste<br />
behandling ud fra det nuværende indeks.<br />
Når man snakker om multipliciteter kan man starte med at kigge på forholdet mellem Placering og Portion.<br />
Grunden til at det er nul til en, til nul til en, er fordi en Portion kan enten være under en Dragerings- eller en<br />
Tørringsbehandling. Men eftersom den kun skal tildeles en placering hvis dens behandling er en<br />
Tørringsbehandling er det ikke et krav at den skal have en placering som standard. Når den så skifter<br />
behandlingstype fra fx Tørring til Dragering ville dette placeringsobjekt så blive frigjort og mulig for andre<br />
portioner der skal tørre.<br />
Som nævnt tidligere vil Opskrift-klassen i implementeringsfasen få en liste over Processer. Grunden til det<br />
er, at man skal kunne følge og evt. generhverve en portions proces-forløb samt udregne forskellige ting ud<br />
fra dette.<br />
Tilstandsdiagrammer (Mads)<br />
Eftersom lagersystemet er bygget på at en vare kan have forskellige tørretider, som forklaret i det<br />
udleverede oplæg, kan dette illustreres igennem et tilstandsdiagram. Grunden til at dette er muligt er fordi<br />
man kan antage at de forskellige tørretider samt start og slut knuderne i systemet er stadier en portion kan<br />
antage mens den er på lageret til tørring.<br />
I følgende afsnit vil x være et udtryk for de dage en given portion har stået og tørret. Både minimum, ideal<br />
og maksimum er tal som lagt til 0 beskriver den deadline hvor en portion skifter status.<br />
Til at starte med, når portionen først lige kommer til lageret, er den i en start-tilstand hvor den endnu ikke<br />
kan plukkes til videre behandling. Dette er ikke muligt da man ellers ville kunne plukke portioner der stadig<br />
er 'våde'. Så derfor vil det ikke være muligt at plukke portionen i intervallet 0 < x < minimum. Når en portion<br />
så har stået i minimum tørringstid vil det være muligt for den at blive plukket til behandling. Det skal dog<br />
siges at varen vil have minimum som status indtil den når ideal tørretiden, altså: (minimum
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
muligt at kunne plukke varen i dette stadie og lige som tidligere vil den have denne status i følgende<br />
interval: (ideal maksimum, ender portionen automatisk i en slut-tilstand som er et udtryk for at den er overgået til<br />
spild. Disse intervaller er også et godt udgangspunkt for videre testing.<br />
Design Klasse Diagram (Fælles)<br />
Dette diagram findes også som bilag.<br />
Dette diagram er den centrale del af Design-Modellen i rapporten. Det er lavet på baggrund af analyse<br />
diagrammet som tidligere er beskrevet. Forskellen på analyse og design diagrammet er basalt set<br />
detaljeniveauet som kommer til udtryk i bl.a. indførelsen af typer på attributter samt metoderne der er i<br />
design klasse diagrammet. Dette er dog set med et meget generelt syn. Følgende er derfor en uddybelse af<br />
den udbygning der er på baggrund af analyse-diagrammet som ender med et produkt i form af design<br />
klasse diagrammet.<br />
Til at starte med kan man gå ind og se på hvad de forskellige værdier på de forskellige attributter skal være.<br />
For at tage et eksempel kan man se på Placerings-klassen. Her er der mange der vil argumentere for at dens<br />
x og y attributter burde være strings, så man måske kunne sætte et 'b' foran begge værdier for at indikere<br />
at placerings-objektet er den placering i buffer-området af lageret. Dette blev dog fravalgt da vi gik ud fra at<br />
lageret var et stort firkantet område i en hal hvor man kunne opdele dette i små firkanter og navngive dem<br />
med koordinater i form af tal, x og y. Disse attributter fik derfor værdien integers (hel tal).<br />
Der er ligeledes andre eksempler på disse valg, men for hurtigt at dække de trivielle valg kan man se på de<br />
forskellige tider (startTid og slutTid) som logisk nok blev sat til at være det allerede eksisterende Date<br />
objekt, da de skal være fælles for begge.<br />
Side 26 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Dernæst er der sådan noget som vareNr på en portion, samt navnet på en opskrift. Begge af dem kan man<br />
argumenter for og imod de valgte typer men at sætte vareNr til at være et integer og navnet på opskriften<br />
til at være en string virkede som det mest logiske for udviklerne.<br />
I Proces-klassens status attribut kunne man have gjort mange forskellige ting, for at indikere hvilken status<br />
et givent proces-objekt har på et givent tidspunkt. Som et primitivt udgangspunkt kunne man give den en<br />
string værdi, hvor man så skulle sørge for at alle statusser blev skrevet på præcis samme måde, for at sikre<br />
at de agerede på samme måde ved en given status. Problemet med denne tilgang er den menneskelige del.<br />
Her vil der være for stor risiko for at der på et eller andet tidspunkt vil være en stavefejl, som vil kunne få<br />
systemet til at indeholde proces-objekter med ugyldige statusser.<br />
En anden tilgang, som i dette tilfælde er blevet benyttet, er at have en enum-klasse som indeholder statiske<br />
elementer som så skal benyttes som typen for status attributten i Proces-klassen. På den måde er det sikret<br />
at der kun bliver benyttet de konstanter som er defineret i enum-klassen<br />
Vi vil nu kigge på de to ovenstående associationsklassers implementering. Som man kan se ud fra det<br />
øverste billede, som er et lille del af det tidligere beskrevet analyse diagram, kan man se at der er en<br />
associationsklasse mellem opskrift og behandling. Denne klasse sørger for at en behandling ikke har den<br />
samme placering i alle opskrifter. Måden dette gøres på er at indføre den som en fast klasse mellem de to<br />
klasser: Opskrift og Behandling. Denne BehandlingsIndeks klasse sikrer at behandlinger kan benyttes i<br />
forskellige opskrifter med forskellige placeringer i rækkefølgen.<br />
Men der bliver overset en lille ting, nemlig overgangen fra analyse diagrammets multiplicitet til design<br />
klassens, hvor der lige nu er inkluderet en BehandlingsIndeks klasse. Til at starte med kan man se at<br />
multipliciteten 0..* til 1..* forstået på den måde at intentionen var at en opskrift skal have mindst en<br />
behandling i rækkefølgen men en behandling kunne godt indgå i flere opskrifter. For at dette kunne lade sig<br />
gøre at holde styr på, blev BehandlingsIndeks indført.<br />
For at overføre dette til design klasse diagrammet kan man i dette tilfælde argumentere for, at et<br />
behandlingsindeks godt kan indgå i flere opskrifter. Derfor bliver diagrammet implementeret som<br />
.<br />
Side 27 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
ovenstående illustrationer. At et behandlingsindeks skal have en opskrift, som den ikke kender til, og at et<br />
behandlingsindeks kan indgå i flere opskrifter (1 → 1..*).<br />
Dernæst kan man se at behandlingsindekset skal have en behandling og en behandling sagtens kan indgå i<br />
flere behandlingsindekser, men som før skal behandlingerne ikke vide hvilke behandlingsindekser de indgår<br />
i (0..* → 1).<br />
Denne overgang er også gældende for den anden associationsklasse der indgår i analyse-diagrammet. Dog<br />
med den forskel at udviklerne fastslog at forholdet mellem Portion og Proces blev nødsaget til at være en<br />
komposition da det ikke ville give mening at en proces kunne stå alene uden nogen tilhørende Portion.<br />
Som man kan se af det over-all design klasse diagram er der en lille klasse som virker som om den er meget<br />
isoleret fra resten af modellen - nemlig SystemDato-klassen. Grunden til denne klasse er med i modellen, er<br />
for at kunne have et centralt sted for alle modelklasserne at hente deres Date-objekter til startTid og<br />
slutTid. Mange vil sige at det ville være nok bare at kalde new Date på disse tider når de skulle sættes, men<br />
eftersom udviklerne gerne ville kunne teste systemet ved at få tiden til at gå hurtigere, blev denne klasse<br />
implementeret så man fra andre klasser kunne sætte en ny tid for systemet. Derfor blev der også<br />
implementeret en TimeThread-klasse i Service pakken så den kunne håndtere hvornår og hvor ofte en ny<br />
dato skulle sættes. I selve implementeringen er denne klasse implementeret med to modes – et test og<br />
real-time mode. I det sidste mode vil der blive tjekket om computerens dato er en ny dato til forskel for den<br />
der allerede er sat i SystemDato-klassen efter et givent interval indtil systemet lukkes.<br />
Hvis man ser bort fra interfacet der også er med i ovenstående illustration, kan man se sammenhængen<br />
mellem de tre klasser: Service, TimeThread og SystemDato. Tanken bag denne kobling er at vi gerne vil tilgå<br />
en 'nuværende' dato i modellen uden at kalde op i DAO-en og Service klasserne. Derfor var det nødvendigt<br />
at oprette SystemDato-en. For hvert interval der går i TimeThread-tråd klassen skal dens run-metode sætte<br />
en ny dato i SystemDato klassen, samtidig med at den skal kalde en metode i Service klassen der tjekker<br />
Side 28 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
hele systemets objekters status. Dette gør at vi kan forkorte en flere dages lang proces ned til fx et par<br />
sekunder. Alt dette overholder stadig at der ikke bliver kaldt ned i lagene i den brugte arkitektur.<br />
Arkitektur (Mads)<br />
Når man snakker om arkitektur i et software-udviklingsprojekt har undervisningen givet os to modeller at<br />
vælge imellem. Den ene er den traditionelle fire-lags arkitektur hvor alt går strikt gennem alle tre lag for at<br />
tilgå modellen i bunden. Altså GUI → Service → DAO → Model, med ingen undtagelser. Der er mange<br />
forskellige holdninger til denne model. En af dem benytter argumentet med, at den ligger bund for mange<br />
unødvendige metodekald, eftersom alt skal igennem Service for bl.a. at kunne tilgå en given liste i DAO-en.<br />
Men på den anden side kan man også sige at det giver en større kontrol omkring hvad der virkelig foregår i<br />
de lavere-liggende lag i arkitekturen.<br />
Til dette projekt er der valgt en lidt anden tilgang til arkitekturen, ved at benytte en arkitektur som består af<br />
tre lag, men stadig med de samme fire elementer. Grunden til at denne er valgt, er for at effektivisere<br />
systemet, ved ikke at skulle følge en nær så stor 'method-call-path' ved evt. debugging.<br />
Desuden bliver det muligt at tilgå DAO-en direkte fra GUI-en. Det skal dog siges at der kun benyttes denne<br />
tilgang til at læse lister fra DAO-en, ikke til at ændre objekter i systemet. Denne arkitektur gør også at<br />
Service-klassen ikke bliver nær så lang og med et mindre indhold af lettere trivielle metoder.<br />
Som man kan se på modellen afhænger Service stadig af DAO-en. Grunden til dette er at når man endelig<br />
skal opdatere et objekt – i dette tilfælde et objekt af typen Opskrift – går dette stadig igennem Service for<br />
stadig at have en kontrol med hvad der bliver opdateret med hvilke værdier.<br />
Testrapport (Mads)<br />
Dette afsnit indeholder et afsnit omkring modul-test af en forretningsorrienterede klasse, i dette tilfælde er<br />
der valgt at det skal være Proces-klassen i en kobling med Toerring-klassen. Derudover er der et afsnit<br />
omkring en use-case test for en central use-case, her er der valgt use-casen: Opret Opskrift.<br />
Modultest af Proces-klasse<br />
/**<br />
Side 29 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
* Beregner den status en proces har ved metode-kaldet. Dette er forskelligt<br />
* alt afhængig af hvilken subklasse en behandling er. <br />
* Krav: currentDate skal være 'større' end startTid<br />
*<br />
* @param currentDate<br />
* den dato som systemet har på det givne tidspunkt<br />
* @return den aktuelle status for den nuværende proces som vil være<br />
* portionens aktuelle proces<br />
*/<br />
public StatusType beregnStatus(Date currentDate)<br />
I klassen Proces er der en metode der hedder beregnStatus som skal beregne den status den pågældende<br />
proces har ud fra en given dato som bliver givet med til metode-kaldet gennem en parameter. Det der<br />
kommer til at ligge bund for dette test-case er at Toerrings-klassen også benyttes da det er denne klasse der<br />
definere hvornår en proces har forskellige statuser.<br />
Så defor startes der med at definere et 'objekt' af klassen Toerring med værdier for minimum, ideal og<br />
maksimum tørringstider. Men for at dette kan lade gøres skal der kigges på de krav som er opstillet for<br />
oprettelse af denne klasse. Eftersom programmet ikke garantere brugbare resultater hvis disse krav ikke er<br />
opfyldt fra brugerens side. Derfor kigges der i dokumentationen for konstruktoren for denne klasse.<br />
/**<br />
* Oprettelse af en Tørring <br />
* Krav: 0 < minimum < ideal < maksimum<br />
*<br />
* @param minimum<br />
* @param ideal<br />
* @param maksimum<br />
*/<br />
public Toerring(int minimum, int ideal, int maksimum)<br />
Her kan man se hvordan konstruktoren for oprettelsen af dette objekt ser ud. Og der kan derfor læses at for<br />
at programmøren garentere et valid objekt af denne type skal følgende krav være opfyldt:<br />
0 < minimum < ideal < maksimum<br />
Dette krav bunder i opfattelsen omkring problemstillingen for systemet. Her forståes der at en tørring ikke<br />
kan vare nul dage og der skal mindst være en dags forskel mellem de tre stadier for at et valid Toerrings<br />
objekt bliver returneret. Derfor vil det objekt der bliver benyttet bruge følgende værdier for tørringer:<br />
Side 30 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Parameter Værdi<br />
Minimum 1<br />
Ideal 3<br />
Maksimum 5<br />
Disse værdier overholder det opstillede krav fra programmørens side og vil derfor give et valid objekt til<br />
videre brug i test-casene.<br />
Når det så kommer til oprettelse af proces-objektet antages der at der er et tilhørende portions-objekt som<br />
selvfølgelig også har et opskrifts-objekt. Dernæst antages der at startTid attributten på proces-objektet er<br />
sat til <strong>2012</strong>-05-05 som udgangspunkt.<br />
Når der så skal testes antages der at currentDate (parameteren i metodekaldet) er en nyere Date-objekt end<br />
startTid – så at sige. I tabellen over tests der er foretaget vil det være differencen mellem startTid og<br />
currentTid-parameteren som er med.<br />
Det der så testes for er om de forskellige StatusTyper der bliver returneret er passenden i forhold til den<br />
difference der er mellem startTid og currentTime. Følgende tabel giver et overblik over hvornår procesobjekten<br />
skal have specifikke status i henhold til differencen. De variabler som bliver brugt i beskrivelsen af<br />
intervalet for hvornår statusen er valid er en reference til de tørretidsspecifikationer som er opgivet ved<br />
oprettelsen af Toerrings-objektet. Ligeledes er x et udtryk for den førnævnte difference mellem startTid og<br />
currentDate.<br />
StatusType Inteval for status Ækvivalensklasse<br />
StatusType.NOT_DONE 0
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Altså er grænseværdierne for disse test et udtryk for en specifik difference mellem startTid og currentDate.<br />
startTid - currentDate Forventet resultat Faktiske resultat<br />
0 StatusType.NOT_DONE StatusType.NOT_DONE<br />
minimum - 1 StatusType.NOT_DONE StatusType.NOT_DONE<br />
minimum StatusType.MINIMUM StatusType.MINIMUM<br />
minimum + 1 StatusType.MINIMUM StatusType.MINIMUM<br />
ideal - 1 StatusType.MINIMUM StatusType.MINIMUM<br />
ideal StatusType.IDEAL StatusType.IDEAL<br />
ideal + 1 StatusType.IDEAL StatusType.IDEAL<br />
maksimum - 1 StatusType.IDEAL StatusType.IDEAL<br />
maksimum StatusType.MAKSIMUM StatusType.MAKSIMUM<br />
maksimum + 1 StatusType.OLD StatusType.OLD<br />
maksimum + n StatusType.OLD StatusType.OLD<br />
Som man kan se ud fra ovenstående tabel overholder metoden de forventninger der er stillet til den. Der vil<br />
dog ikke blive testet for ulovlige værdier som fx en negativ difference mellem startTid og currentDate da<br />
dette ikke er en mulighed i systemet.<br />
Nu hvor hele processen af testing er gennemgået for den største del af Proces-klassen, kan den følgende del<br />
let gennemgåes ud fra nogle få linjers forklaring. Det vil sige at følgende tabeller er en test gennemgang hvis<br />
en proces' behandling er af typen Dragering. Det brugte Dragerings-objekt har en varigheds-attribut med<br />
værdien tre. Denne attribut er den eneste interessante i Dragerings-klassen.<br />
StatusType Inteval for status Ækvivalensklasse<br />
StatusType.NOT_DONE 0 = varighed [varighed;varighed]<br />
I ovenstående tabel bliver der gået ud fra at der er plads på lagerert når en proces er færdig, har fået<br />
statustypen StatusType.DONE, hvilket forklare den sidste ækvivalensklasse. Hvis dette ikke var en antagelse<br />
ville det være nødvendigt at udvide ækvivalensklassen til at have følgende opbygning: [varighed;∞[ og<br />
endda gennemtænke om en dragering skal have muligheden i at blive for gammel selvom den endnu ikke er<br />
kommet ind på lageret.<br />
Med ækvivalensklasserne deffineret kan grænseværdierne samt de forventede resultater opsættes<br />
efterfulgt af testenes egentlige resultater.<br />
Side 32 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
startTid - currentDate Forventet resultat Faktiske resultat<br />
0 StatusType.NOT_DONE StatusType.NOT_DONE<br />
varighed - 1 StatusType.NOT_DONE StatusType.NOT_DONE<br />
varighed StatusType.DONE StatusType.DONE<br />
varighed + 1 StatusType.DONE StatusType.DONE<br />
Ovenstående antagelse med at værdierne for x er en difference som er udtrykt fra den forud-deffineret<br />
værdi for Dragerings-objektets varigheds-attribut.<br />
Use-case test af Opret Opskrift<br />
I nedenstående mock-up af den tidligere beskrevet use-case er der kort forklaret lidt omkring use-casen<br />
'Opret Opskrift'. Denne case er opdelt i fire kategorier som der bliver arbejdet udfra ved udarbejdelsen af<br />
denne use-case test.<br />
Use-case #U6<br />
Opret en opskrift<br />
Success guarantees<br />
Der bliver opretttet en opskrift i systemet<br />
Main success scenario<br />
1. Brugeren indtaster et navn på en opskrift<br />
2. Brugeren tilføjer x antal behandlinger til opskriften.<br />
3. Brugeren vælger at konfirmere oprettelsen af opskriften.<br />
Extensions<br />
1a. Brugeren glemmer at skrive navnet på opskriften<br />
2a. Brugeren kan ikke finde en given behandling og ønsker at oprette en ny<br />
2aa. Der eksistere ikke den ønsket behandlingstype (hverken tørring eller dragering kan bruges)<br />
2b. Brugeren tilføjer ingen behandlinger<br />
Ud fra ovenstående use-case mock-up kan man så danne et use-case test skema som danner bund for alle<br />
de kombination af udfald den givne use-case kan resultere i. Nedenstående tabel er af sådan en type tabel:<br />
Side 33 af 75
Test<br />
case<br />
ID<br />
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Test Source Initial System<br />
State<br />
U6-1 Use case #6 Programstart<br />
fra<br />
hovedvindue<br />
U6-2 Use case #6<br />
extens. 1a<br />
U6-2 Use case #6<br />
extens. 2a<br />
U6-3 Use case #6<br />
extens. 2aa<br />
U6-4 Use case #6<br />
extens. 2b<br />
Programstart<br />
fra<br />
hovedvindue<br />
Programstart<br />
fra<br />
hovedvindue<br />
Programstart<br />
fra<br />
hovedvindue<br />
Programstart<br />
fra<br />
hovedvindue<br />
Input Expected Results<br />
(a) Opskrift<br />
navn ”Lakrids”<br />
(b) Mindst en<br />
behandling tilføjes<br />
(c) Trykker på OK<br />
(a) Mindst en<br />
behandling tilføjet<br />
(b) Trykker på OK<br />
(a) Opskrift<br />
navn ”Lakrids”<br />
(b) Trykker på 'Opret<br />
Behandling'<br />
(c) Mindst en<br />
behandling tilføjes<br />
(d) Trykker på OK<br />
(a) Opskrift<br />
navn ”Lakrids”<br />
(b) Trykker på 'Opret<br />
Behandling'<br />
(c) Trykker på luk i<br />
'Opret<br />
Behandling's-vinduet<br />
(d) Trykker på luk i<br />
'Opret Opskrift'svinduet<br />
(a) Opskrift<br />
navn ”Lakrids”<br />
(b) Trykker på OK<br />
(a) En ny opskrift vil blive oprettet<br />
(b) Brugeren kommer tilbage til hovedvinduet<br />
(c) Listen over opskrifter vil vise den nye opskrift<br />
(a) Brugeren får at vide de skal angive et navn for<br />
at kunne oprette en opskrift<br />
(a) Brugeren opretter en ny behandling med de<br />
nødvendige og gyldige værdier<br />
(b) En ny opskrift vil blive oprettet<br />
(c) Brugeren kommer tilbage til hovedvinduet<br />
(d) Listen over opskrifter vil vise den nye opskrift<br />
(a) Brugeren kommer ud til hovedvinduet<br />
(b) Ingen ny opskrift er oprettet eller vises i listen<br />
over opskrifter.<br />
(a) Brugeren vil få at vide at der skal være mindst<br />
en behandling tilføjet<br />
(b) Brugeren bliver på 'Opret Opskrift's-vinduet<br />
Status (Mads)<br />
Som systemet ser ud nu på et designmæssigt niveau er der stadig nogle fejl, dog skal det siges at det ikke er<br />
noget udviklerne på nuværende tidspunkt kan identificere. Der er dog stadig mulighed for videre udvikling<br />
af systemet. Der vil fx kunne blive implementeret et kort over det pågældende lager hvor man selv ville<br />
kunne assigne forskellige fysiske områder til at have buffer-status eller lignende. Ud over det kan der<br />
implementeret en fane i GUI-en til at håndtere den over-all statistik så der fx kan blive genereret grafer ud<br />
fra gennemsnitlige tørretider over et foruddeffineret tidsinterval.<br />
Side 34 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Hvis man skal kigge på manglerne er der rigtig mange ting man kan argumentere for og imod. Men for at<br />
tage nogle eksempler kan man tage udgangspunkt i håndteringen af opskrifter. Lige nu kan systemet ikke<br />
håndtere hvis en lagerchef gerne vil slette en opskrift. Grunden til dette ikke er implementeret er fordi der<br />
på nuværende tidspunkt ikke er en log-tabel i databasen som man kan gemme sådanne ændringer i. Hvis<br />
man lige nu kunne slette en opskrift ville man ikke kunne fortryde det ved at hente dens data i log-tabellen.<br />
Dernæst kan man se på en lignende sag, nemlig håndteringen af behandlinger i systemet. Disse objekter<br />
kan heller ikke opdateres til at have andre attributværdier. Dette er valgt eftersom hvis det var muligt ville<br />
det påvirke alle de opskrift og portions-objekter som benytte det pågældende behandlings-objekt. Derfor er<br />
disse gjort 'statiske'.<br />
For at runde af på denne status del af rapporten kan man godt konkludere at hvis det som blev beskrevet i<br />
oplægget er det som kunden gerne ville have ville dette system godt kunne tages i brug.<br />
Resume af forløbet (Robert)<br />
Som udgangspunkt har vi aftalt at mødes kl. 08:30 hver dag, for derefter at arbejde til omkring middag eller<br />
til målene for dagen er nået.<br />
Vi startede med ITO-delen og blev hurtigt enige om at vi ville arbejde med klar arbejdsfordeling, for<br />
derefter at samle vores materiale og gennemgå det og eventuelt tilpasse det.<br />
Efter et kort møde med vores vejleder, holdte vi i gruppen et møde om hvordan opgaven skulle løses. Det<br />
største problem vi havde med ITO er fagets omfang og derfor at finde vores relevante fokuspunkter.<br />
Efter at have løst problemet angående relevant materiale og endelig overvandt frustrationen, nåede vi<br />
hvad der lignede et færdigt resultat og slog derefter over til næste opgave, nemlig software design delen.<br />
Vi fastholdte under hele processen de samme arbejdstider, med små dellegeringer til hjemmearbejde og<br />
begyndte nu på software design. Dette krævede en del gruppearbejde og de første par dage foregik meget<br />
på samme skærm, for at være fælles om den endelige grundstruktur for software konstruktionen.<br />
Arbejdsmetoden ændredes dog efter at have lavet analyse og design diagrammer. Ligesom i ITO var det<br />
nemlig fordelagtigt at dele arbejdet op i tre dele, da mange af opgaverne i software design er relative<br />
overkommelige for ene mand.<br />
Da vi følte os godt klædt på til at begynde med kodning, gik vi i gang med at kode modellen. Dette gjorde vi<br />
i nogenlunde fællesskab, for hele tiden at kunne diskutere den optimale løsning af metoder og være sikker<br />
på at vi overholdte blandt andet vores multipliciteter.<br />
Vi kom hurtigt i gang med GUI og efter at have tegnet og blevet enig om vores design, blev vi enige om at<br />
lave GUI hver mand for sig, da det viste sig at vi havde hver sin måde at programmere det på. Det største<br />
problem her var, at blive enige om brugen af Layouts, hvor vi endte med at blive enige om et par specielle<br />
Layouts men også absolutte designs hvor mange knapper og lister drillede. Da vi var færdige med denne<br />
version af programmet, var vi klar til JPA-versionen.<br />
Vi implementerede JPA uden de store problemer og testede derefter at objekterne blev gemt i mySQL. Da<br />
dette var en succes, følte vi os nu godt klædt på til at kalde os stort set færdige med programmeringsdelen.<br />
Enden på projektet synes endelig håndgribelig og vi satte os sammen for at lave en liste med nuværende<br />
mangler. Disse opgaver blev fordelt og lavet over en weekend, for derefter at blive samlet. Sidste proces gik<br />
ud på at samle projektet og rette for fejl og mangler.<br />
Side 35 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Refleksioner (Robert)<br />
Unified process(UP) er et redskab til at skitsere systemudviklingens cyklus. Det er ud fra denne cyklus, at vi<br />
har arbejdet med <strong>Carletti</strong> projektet. For at forstå denne cyklus, skal man præsenteres for de fire faser som<br />
beskriver cyklussen. I dette projekt lægger vi dog ikke vægt på den fjerde og sidste fase transition, som<br />
omhandler udførelsen (også kaldet deployment) af projektet i form af implementering hos kunden.<br />
Et redskab man bruger mens man arbejder ud fra UP er det iterative princip. Ved at arbejde iterativt,<br />
arbejder man sig igennem nogle faser, hvormed projektet vokser inkrementelt og de isolerede faser samles<br />
til en enhed.<br />
Man deler altså projektet op i små miniprojekter, hvor man opstiller nogle målbare artefakter eller krav.<br />
Dette hjælper med at skabe et overblik over projektet og dets forløb.<br />
Den første fase hedder inception og inkluderer faget ITO og SD. Denne fase handler blandt andet om<br />
business modelling eller med andre ord forretningsudvikling. For at kunne gennemføre et projekt, skal man<br />
skabe sig noget overordnet baggrundsviden og forståelse for hvilket forretningsområde man befinder sig i. I<br />
denne fase udvikles desuden nogle simple use cases, der skaber forståelse for simple overordnede<br />
funktioner i systemet.<br />
Dette er hvad vi har gjort i ITO og SD. Denne viden har kunnet bringe os videre til næste fase, elaboration.<br />
I denne fase arbejder vi videre med software design. Her skabes de centrale dele af systemet samt en<br />
dybere forståelse af systemets krav. Her udarbejdes detaljerede forklaringer af use cases,<br />
klassediagrammer og andre software design redskaber. Efter denne fase skal man have nået så langt, at<br />
man kan udarbejde en grovplan for resten af projektet. Man er nået så langt, at enden er håndgribelig.<br />
Disse redskaber udvikles i en iterativ proces, hvor man med udgangspunkt i den midlertidige løsning,<br />
gentager processen og skaber en bedre løsning. Et nyt krav kan for eksempel være grunden til ændring i en<br />
use case og på den måde forbedrer vi produktet.<br />
De centrale dele af systemet skabes og en simpel version af programmet kodes. Her blev der lavet en lille<br />
version af programmet, som var i stand til at køre en simpel simulering af en opskrift som skulle igennem<br />
en behandling.<br />
I den sidste fase construction, forsættes implementeringen af programmet. Her er der arbejdet på at samle<br />
alt vores materiale samt færdiggørelsen af programmet, så det er klar til præsentation.<br />
Udviklingsværktøjer:<br />
I dette projekt har vi udover det udleverede materiale også hentet information fra internettet. Kilderne fra<br />
internettet, der er brugt i projektet, er selvfølgelig refereret til.<br />
Derudover har vi til udviklingen af vores system design brugt Visual Paradigm og til vores java-kodning<br />
programmet Eclipse. Til JPA delen brugte vi mySQL til at teste, at vores program virkede efter hensigt.<br />
Side 36 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Ordbog<br />
Udtryk Definition<br />
Analyse Diagram Et generelt diagram der viser koblingerne mellem begreber i systemet<br />
Associationsklasse En klasse der bliver indsat i en forbindelse mellem to klasser for at sørge for at<br />
alle klasser af en given type ikke.<br />
BehandlingsIndeks En associationsklasse der håndtere den rækkefølge forskellige behandlinger har i<br />
en opskrift.<br />
Behandling En abstrakt klasse der gør det muligt at have en liste med både tørring og<br />
drageringsbehandlinger i<br />
Collection-framework Dette er et framework som Java er udstyrret til håndtere forskellige former af<br />
samlinger af objekter – Set, Tree, List<br />
Dragering En klasse der modellere en drageringsbehandling hvor den er deffineret med en<br />
varighed en drageringsbehandling tager<br />
DrageringsType En enumklasse der indeholder to konstanter som beskriver en type af dragering,<br />
enten en farve- eller en sukker-dragering.<br />
DSD Design Sekvens Diagrammer – Disse diagrammer bliver brugt i design fasen<br />
hvilket inkludere kaldene klasserne imellem<br />
Enkeltbrugersystem Et system der kun skal bruges af en bruger af gangen – dette gør at der ikke skal<br />
tages nær så høj forbehold for samtidighedsproblemer<br />
Grænseværdier Bruges i test-verdenen sammen med ækvivalensklasser hvor grænseværdier er et<br />
udtryk for de tal i ydrekanten af intevallet.<br />
Lagermedarbejder Aktør som hovedsageligt står for at plukke portionerne og sende dem videre til<br />
behandling<br />
Lagerchef Aktør som hovedsageligt står for at oprette opskrifter samt portioner.<br />
Modultest Dette er en testform hvor man kigger på fx en metode som tager forskellige<br />
parametre for derefter at resultere i noget bestemt. Ved at bruge denne<br />
testmetode kan man kontrollere udfra intervaller om disse resultater er valide.<br />
Opskrift En klasse der indeholder en liste over de BehandlingsIndekser (behandlinger) en<br />
portion skal igennem for at få en status som færdigbehandlet<br />
Placering En klasse der modellere en placering på lageret ud fra et koordinatsystem<br />
Plukke vare Når en portion har opnået en hvis status har den mulighed for at blive plukket.<br />
Dette betyder at portionen<br />
Portion En klasse der modellere en portion af en opskrift, altså en form for aktivt objekt i<br />
proces-forløbet.<br />
Proces En klasse der modellere en aktuel proces som en given portion lige nu er ved.<br />
slutTid Beskriver det tidspunkt når enten en portion eller en proces bliver afsluttet.<br />
SSD System Sekvens Diagrammer – Disse diagrammer bliver brugt for at give et<br />
helhedsindtryk af hvordan interaktionen mellem system og bruger er.<br />
startTid Beskriver det tidspunkt når enten en portion eller en proces bliver påbegyndt.<br />
StatusType En enumklasse der indeholder alle de konstanter som beskriver en pågælden<br />
Side 37 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
status for en proces.<br />
Tilstandsdiagram Et diagramtype der viser hvornår man kan gå fra en tilstand til en anden og hvad<br />
der skal være opfyldt for at det er validt. Sagt på en anden måde så er det et<br />
diagram der viser systemets forskellige tilstande.<br />
Toerring En klasse der modellere en tørringsbehandling som er deffineret med en<br />
minimal, ideal og maksimum tørretid<br />
Usecase test En testtype som tester om den interaktion mellem aktøren og systemet er<br />
håndteret korrekt eller om der sker uforudsete ting.<br />
Ækvivalensklasse Et begreb der bliver brugt indefor test-verdenen. Det beskriver basalt set et<br />
interval af tal hvor alle de tal resultere i det samme resultat når de sættes ind<br />
som parametre i en metode.<br />
Software konstruktion<br />
Klassemodel (Fælles)<br />
Følgende tekst beskriver hvordan den teoretiske model fra Software Design er implementeret ud fra de<br />
mønstre og principper fra undervisningen de foregående to semestre. Der vil være en beskrivelse af selve<br />
modellen i form af en forklaring af sammenhængene mellem klasserne, hvilket inkluderet en begrundelse<br />
for de valg af Collection-frameworket, samt en gennemgang af evt. polymorfi. Dernæst vil der være en kort<br />
forklaring på den genererede Java-doc, som er blevet genereret ud fra de kommentarer som ligger i koden.<br />
Der udover er der en gennemgang af de design-mønstre der er valgt, både mellem klasserne men også af<br />
opbygningen af individuelle klasser.<br />
Implementering af design-modellen<br />
Dette delafsnit beskæftiger sig mest med de valg der er blevet truffet ved implementeringen af modellen<br />
med hovedfokus på koblingerne mellem klasserne samt de Collections dette medfører.<br />
Sammenhæng mellem klasserne<br />
For at starte et sted kan der med fornuft begyndes med koblingen mellem Opskrift-klassen og Portion-<br />
klassen. Ifølge modellen er denne kobling af typen komposition. Dette betyder at en række ting skal være<br />
opfyldt for at denne kobling kan siges at være korrekt implementeret. For det første må det ikke være muligt<br />
at kunne oprette objekter af typen Portion på andre måder end igennem et objekt af typen Opskrift. Derfor<br />
skal konstruktoren i Portion-klassen have access-modify-eren 'package-private' da dette gør at det kun er<br />
muligt at oprette Portions objekter inde i den pågældende package og på den måde begrænse muligheden<br />
for oprettelse af det pågældende objekt. Nu hvor emnet er konstruktoren i Portions-klassen skal man huske<br />
at kigge på den pågældende multiplicitet for denne association. Her er det nemlig en kobling med<br />
multipliciteten en til mange hvilket betyder at det oprettede objekts konstruktor skal medtage et objekt af<br />
typen som oprettende objekt har.<br />
Side 38 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Dernæst kan der ses nærmere på de metoder som skal være til stede for at en komposition er gyldigt<br />
implementeret. Der skal som minimum være en metode som opretter Portions objekter. Normalt vil sådan<br />
en metode få de samme parametre med, som konstruktoren for den klasse som gerne vil oprettes har. Dog<br />
skal det siges, at i dette tilfælde har Opskrift-klassen alle de fornødne data til at kunne oprette et objekt af<br />
typen Portion, hvilket resulterer i at metoden ikke har nogle parametre med og derfor er kommet til at se<br />
ud som følger:<br />
public Portion opretPortion()<br />
Ovenstående metode kalder så konstruktoren i Portion-klassen som returnerer det nyoprettede objekt til<br />
brugeren som så kan benytte det derfra. Ved kald til denne metode bliver objektet også tilføjet til en liste<br />
over portioner som Opskrift-objektet har oprettet indtil nu.<br />
Der udover har udviklerne valgt at implementere en valgfri metode som gør det modsatte af den<br />
ovenstående metode. Den går nemlig ind og fjerner et Portions-objekt fra listen hvis listen vel at mærke<br />
indeholder det givne Portions-objekt. Her skal der lægges mærke til at valget af listen er faldet på typen<br />
ArrayList med en generisk type Portion. Baggrunden for dette valg ligger i at man er garanteret for at det<br />
samme objekt aldrig kan finde sted to gange i denne liste, da der for det første ikke er nogen 'tilføj'-metode<br />
som tilføjer objekter til listen. Dette ekskluderede valget af et Set da dette interface primært bliver brugt<br />
pga. denne egenskab. Derudover var det antagelsen at det altid skulle være muligt, hurtigt og nemt at tilgå<br />
og lave en iteration igennem listen, så man kunne tilgå et givent objekt nemmest, hvilket et ArrayList giver<br />
mulighed for.<br />
Vi hopper nu videre til koblingen mellem Portion-klassen og Placering. Denne association er en<br />
dobbeltrettet association med multipliciteten 0..1 til 0..1. Dette betyder at man her enten kan vælge at lade<br />
begge klasser stå for vedligeholdelse af dette link, eller man kan se på det forretningslogiske og vælge én<br />
klasse til at tage dette ansvar. I denne implementering er det Placering-klassen der skal stå for<br />
vedligeholdelse af dette link, da tanken bag dette var, at man gik hen til en placering og aktivt fjernede<br />
portionen fra placeringen. Derfor har Portion-klassen en 'package-private' setPlacering metode som kun kan<br />
tilgås gennem et Placerings-objekt, ergo har Placerings-klassen ansvaret.<br />
Med denne multiplicitet er ingen af klasserne tvunget til at have et objekt af modsatte parameter i dens<br />
konstruktor. I stedet har klassen en private attribut som har denne type, som så kan sættes til at være et<br />
konkret objekt af denne type på et givent tidspunkt. Dette gælder både for Placerings- og Portions-klassen.<br />
Dernæst kan man se på associationen mellem Portion- og Proces-klassen. Dette er af den samme type med<br />
Side 39 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
samme multiplicitet, som den sidst beskrevet komposition mellem Opskrift og Portion. Det inkluderer de<br />
samme krav for en gyldig implementation, i form af en ændring på konstruktorens access-modifyer, samt<br />
metode til oprettelse af objekter af typen Proces. Valget af collections i denne klasse er igen af typen<br />
ArrayList af den simple grund, at det skulle være muligt at få fat på den sidst tilføjede proces i listen over<br />
processer oprettet af den pågældende portion. Dette betød at Set ikke ville kunne benyttes da dette<br />
interface ikke indeholder implementering, som giver mulighed for at udtage specifikke elementer i henhold<br />
til et givent indeks.<br />
For at afslutte gennemgangen af valg af Collections skal der ses på associationen mellem Opskrift- og<br />
BehandlingsIndeks-klassen. Denne association vil resultere i, at der skal være en form for Collection i<br />
Opskrift-klassen over de BehandlingsIndeks-objekter som udgør den rækkefølge af behandlinger en portion<br />
skal igennem. Denne Collection kunne godt have været, uden problemer, af typen Set. Dog kom udviklerne<br />
ud for at dette var sværere at teste på under udviklingen af model-pakken. Et andet argument for at det<br />
kunne have været af typen Set var at lige præcis Opskrift-klassen indeholder en metode til at tilføje<br />
BehandlingsIndekser til listen. Dette kunne medføre at et objekt af denne klasse kunne blive tilføjet to<br />
gange, hvilket ikke vil give mening, da der så vil være to behandlingsindekser med den samme værdi for<br />
deres indeks attribut.<br />
Polymorfi<br />
I denne implementering er der næsten ikke benyttet polymorfi. Og her understreges ”næsten”. I denne<br />
implementering har man, som man kan se af design klasse diagrammet, valgt at have en superklasse –<br />
Behandling som også er en abstrakt klasse. Denne klasse har to subklasser som i teorien ville nedarve alle<br />
dens egenskaber. Men eftersom der her er valgt, at Behandling-klassen ikke har skullet have nogen<br />
egenskaber, hverken attributter eller metoder, men blot være der for at man kunne skabe en liste som både<br />
indeholdte objekter af typen Toerring samt Dragering, nedarver de to subklasser derfor ikke nogen<br />
egenskaber.<br />
JavaDoc<br />
Som en fast del af udviklingen af software systemer er det vigtigt at kommentere alle de metoder og svære<br />
logiske valg man har lavet inde i fx en metode. Dette har derfor resulteret i, at der i source-koden er blevet<br />
kommenteret for alle de metoder som ikke gav sig selv ud fra metodenavnet. Det skal derfor forstås på den<br />
måde at trivielle gettere og settere ikke er blevet kommenteret, da dette kun vil gøre source-koden<br />
linjemæssig længere.<br />
Måden der er blevet kommenteret på er ifølge en generel skabelon, som kan beskrives ud fra dette<br />
eksempel:<br />
Side 40 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
/**<br />
* Metoden opretter et objekt af typen Portion. Den får det første<br />
* behandlingsindeks med i constructoren så den ved hvilken behandling den<br />
* skal gennemføre først.<br />
* Hvis der ikke er noget behandlingsindeks med indeks nummer 1 vil det<br />
* returnerede portions-objekt blive sat til null.<br />
* Krav: En gyldig startTid, opskrift-objektet har et behandlingindeks i sin<br />
* liste med indeks-nummer 1<br />
*<br />
* @return skabte portions objekt til senere brug til fx. styrring af<br />
* behandlinger<br />
*/<br />
public Portion opretPortion()<br />
Den ovenstående kommentar er taget fra Opskrift-klassen for opretPortion-metoden. Her kan man se en<br />
lang beskrivelse som indeholder forskellige elementer som indgår i en JavaDoc (alle er dog ikke<br />
repræsenteret her). Det første er en kort beskrivelse af hvad den gør, efterfulgt af et html-linjeskift. Dernæst<br />
kommer der en uddybende forklaring på hvad der sker ved forskellige tilstande af objekter og systemer.<br />
Denne del indeholder også en beskrivelse af de krav metoden kræver, for at metoden opfører sig gyldigt og<br />
ikke sætter systemet i fare for evt. sammenbrud. Hvis en udefrakommende programmør skal benytte denne<br />
klasse til noget andet, er det kun garanteret at den vil fungere, hvis disse krav er opfyldt og ellers er det<br />
han/hendes egen skyld.<br />
I ovenstående eksempel er der vist hvordan et return-statement er medtaget. Denne del indeholder ikke et<br />
navn på det returnerede objekt eftersom et evt. navn på den interne variabel ikke påvirker objektet. I stedet<br />
er der en kort beskrivelse af det objekt som der bliver returneret og hvorfor det bliver returneret som det<br />
gør.<br />
For at vise en metode som medtager parametre tages der udgangspunkt i følgende eksempel:<br />
/**<br />
* Oprettelse af en Tørring <br />
* Krav: 0 < minimum < ideal < maksimum<br />
*<br />
* @param minimum<br />
* @param ideal<br />
Side 41 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
* @param maksimum<br />
*/<br />
public Toerring(int minimum, int ideal, int maksimum)<br />
Dette eksempel er forholdsvis simpelt da det er en konstruktor som tager tre heltal som parametre som har<br />
navnene minimum, ideal og maksimum. Når en kommentar-blok så bliver genereret bliver det vist som<br />
ovenstående @param notation. Hvis det ikke var fordi disse tre værdier er meget trivielle og lette at gætte<br />
sig til hvad repræsenterer, så ville man kunne give en kort beskrivelse af hvad de betød og evt. skulle bruges<br />
til. Som før ses, der at der til denne metode er stillet et krav for gyldig udførelse, som her er et simpelt<br />
matematisk udtryk, hvor de tre parametre indgår i.<br />
Hvis det ønskes kan resten af dokumentationen, JavaDoc, findes i source-koden eller bagerst i denne<br />
rapport som bilag.<br />
Design Mønstre<br />
For at optimere systemet så meget som muligt, er der også i dette system blevet benyttet design-mønstre. I<br />
dette system er der blevet brugt tre mønstre som udgangspunkt: observer-, singleton-, og strategy-pattern.<br />
Følgende tekst vil forklare hvordan og hvor disse patterns er fundet og implementeret i systemet.<br />
Observer<br />
Det klassiske observer mønster består normalt af fire elementer. For at starte på et generelt niveau er der to<br />
interfaces, Observer samt Subject, som indeholder metoder til at registrere og fjerne observerende objekter<br />
(Subject-interfacet) samt en metode til at update en observers tilstand (Observer-interfacet). Når man så<br />
har implementeret dem, kan man implementere de konkrete versioner af de to interfaces, som så er<br />
tvunget til at implementere de metoder som interfacene definerer.<br />
For at tage udgangspunkt i dette system er der også blevet implementeret to interfaceses med de<br />
repræsentative navne. Derudover er MainFrame klassen implementeret til at benytte Observer-interfacet<br />
og Service klassen til at benytte Subject-interfacet. Grunden til dette ligger i at udviklerne gerne vil have at<br />
visningen bliver opdateret når der rent faktisk er sket noget væsentligt i de underliggende lag i systemet.<br />
Dette gøres på den måde at MainFrame bliver registreret som observer på Service-klassen, som så siger til<br />
MainFrame at den skal opdatere visningen for hver gang TimeThread finder ud af at der er gået en ny dag<br />
og Service har opdateret alle portioners aktuelle processers status. Efter denne opdatering af status bliver<br />
update metoden i Observer-interfacet kaldt på den konkrete klasse MainFrame, som derefter vil opdatere<br />
visningen til at være akkurat som modellen. På den måde vil der altid være en valid aktuel visning af alle<br />
processer i GUI-en.<br />
I det normale Observer mønster er det muligt for det konkrete Subject at registrere mange observere. Dette<br />
Side 42 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
kunne også være gjort i dette systems tilfælde, men eftersom opgaven lød på at udvikle, og fremstille et GUI<br />
ville det ikke være nødvendigt, da det blev valgt kun at have ét sted som central visning med kun én klasse.<br />
Singleton<br />
Da det ønskes at der gemmes objekter et centralt sted i systemet, eller sørges for at der kun bliver<br />
opdateret igennem et objekt, var det nødvendigt at benytte dette mønster da det sikrer denne egenskab<br />
bedst. Pointen ved dette mønster er, at der kun bliver oprettet højest et objekt af klassen i hele systemets<br />
run time. Måden at gøre dette på er at gøre konstruktoren i klassen privat og lave en statisk metode som<br />
alle ville kunne tilgå, public access modifyer, som så tjekkede om der allerede eksisterede et objekt (statisk<br />
attribut af klassens type i klassen), hvorefter den enten vil oprette et hvis det ikke var tilfældet og så<br />
returnere det eller blot returnere det allerede oprettede objekt. Når denne getInstance metode først bliver<br />
kaldt bliver attributten sat til et nyt objekt af klassens type. Det betyder at hvis dette var et multi-bruger<br />
system skulle en klasse der var designet efter Singleton mønstret gennemtænkes endnu engang. Ved<br />
implementeringen af getInstance metoden skulle der så tages højde for at denne metode skulle<br />
implementeres så det ikke er muligt, ved et tilfælde, at systemet fx fik oprettet to objekter af typen DAO.<br />
Dette kunne gøres, og er gjort i dette system, ved at implementere metoden med acces-modifyeren<br />
synchronized. Dog er dette ikke nødvendigt da beskrivelsen af systemet inkluderede begrænsningen at<br />
systemet var et single-user system. Dette er dog gjort alligevel da det vil danne en bedre grund for evt.<br />
videreudvikling af systemet.<br />
public class Service implements Subject {<br />
private static Service unique;<br />
...<br />
public static synchronized Service getInstance() {<br />
}<br />
if (unique == null)<br />
unique = new Service();<br />
return unique;<br />
private Service() {<br />
}<br />
dao = DAO.getInstance();<br />
dato = SystemDato.getInstance();<br />
Side 43 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
}<br />
...<br />
I dette system er der benyttet singleton på DAO, Service og SystemDato. De to første klasser er allerede<br />
blevet forklaret hvorfor de er blevet implementeret således.<br />
Grunden til at SystemDato-klassen er implementeret på den måde ligger i at systemet kun skal hente de<br />
nødvendige datoer fra én klasse, så der ikke opstår en uens udvikling i tiden. Hvis der var to, ville det være<br />
muligt at nogle objekter fik deres datoer fra et SystemDato objekt mens andre fik fra en anden. Oven i det<br />
ville de to objekter af SystemDato kunne have to forskellige udgangsdatoer<br />
Strategy<br />
Pointen i strategy-mønstret er at generalisere klasserne hvor der på et eller andet punkt er en central klasse<br />
som alle subklasser nedarver fra. På den måde kan man benytte superklassen som en type definition på fx<br />
en attribut i ens application. På den måde kan der assignes et objekt af en subklasse til attributten som så<br />
ikke skal have skiftet værdi. Dette gør også at det er muligt at udvide systemet nemmere ved blot at lave en<br />
klasse som nedarver fra superklassen. Så længe attributten er defineret til at være af superklassens type, vil<br />
der ikke være noget yderligere problem i det.<br />
Grunden til at dette mønster er taget med i dette afsnit, ligger i implementeringen af Behandlings-,<br />
Toerrings- og Dragerings-klassen. Hele konceptet i strategy-mønstret kan ses her. Når et BehandlingsIndeks<br />
oprettes kræver det nemlig en eller anden form for behandling som en fast del af BehandlingsIndeks<br />
objektet. Hvis man ikke benyttede strategy mønstret kunne man fx have to attributter, en med typen<br />
Dragering, og en med typen Toerring. Så skulle der blot testes for hvilken af de to attributter der ikke var<br />
null for derefter at udføre behandling ud fra det andet. Men hvad hvis man havde ti forskellige<br />
behandlinger? Det ville så inkludere ti forskellige attributter i klassen der benytter en af behandlingerne,<br />
hvilket ikke er effektivt. Derfor er der i systemet implementeret en abstrakt klasse som både Toerring- og<br />
Dragering-klassen nedarver fra. På den måde skal der blot være en attribut i BehandlingsIndeks klassen som<br />
både kan have et konkret objekt værdi af typen Toerring og Dragering. Selv hvis systemet kommer til at<br />
inkludere flere behandlingstyper, er det kun oprettelsen af den nye behandlingstype som klasse der<br />
nedarver fra Behandling som skal implementeres, og intet i andre klasser - som udgangspunkt.<br />
Side 44 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Implementering af arkitektur (Robert)<br />
Vi vil nu vise hvordan vores 3 lags arkitektur er blevet implementeret i praksis. Dette vil vi gøre ved at vise<br />
hvordan en bestemt use case, nemlig ”Opret opskrift”, er implementeret. Som beskrevet i dens beskrivelse,<br />
går denne use case ud på at oprette og tilføje en opskrift til systemet.<br />
Den første fase i implementeringen gik ud på, hvad en opskrift skal indeholde. Vi blev enige om, at en<br />
opskrift som fx ”Lakrids”, skal gemmes i en liste, samt en antagelse om at en opskrift skal indeholde en eller<br />
flere behandlinger. Dette kræver at man har nogle behandlinger og disse et behandlingsindeks. Alt dette er<br />
blevet kodet på model-plan og sammenhængen kan tydes ud fra design klassediagrammet, samt DSD for<br />
use casen.<br />
For at vise sammenhængen i arktiekturen vil vi nu gennemgå use casen.<br />
Når vi opretter en opskrift i vores GUI, kalder vi en ”OpretOpskrift”-metode i vores service klasse. Denne<br />
metode henter da constructeren fra Opskrift-klasssen i modellen og kalder Dao for at gemme opskriften.<br />
De valgte behandlinger til opskriften bliver hentet til GUI fra Dao i form af en liste, hvor vi igen henter en<br />
metode fra service for at give behandlingerne til opskriften et behandlingsindeks..<br />
GUI:<br />
private class OkButtonActionListener implements ActionListener {<br />
….<br />
….<br />
if(opskrift == null){<br />
Opskrift o = Service.getInstance().opretOpskrift(navn);<br />
int indeks = 1;<br />
for (Behandling b : valgte) {<br />
o.addBehandlingsIndeks(Service.getInstance().opretBehandlingsIndeks(<br />
indeks, b));<br />
indeks++;<br />
}<br />
…<br />
…<br />
}<br />
Ovenstående viser hvordan vi kalder service klassen. Desuden henter listen ”valgte” sine behandlinger fra<br />
dao.<br />
Service:<br />
public Opskrift opretOpskrift(String navn) {<br />
Opskrift o = new Opskrift(navn);<br />
dao.addOpskrift(o);<br />
return o;<br />
}<br />
Ovenstående viser hvordan Service bruger modellen og Dao.<br />
Side 45 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Vi har i vores arkitektur model en forbindelse fra GUI’en direkte til DAO. Denne forbindelse er, udover<br />
eksemplet med listen ”valgte”, for eksempel implementeret når en portion har stået for længe til tørre og<br />
derfor skal tilføjes til spild. Tanken bag denne forbindelse ligger i, at der ikke skal andet end en simpel<br />
tilføjelse af et portion-objekt til en ArrayListe for at dette kan lade sig gøre. Her kunne man kalde en<br />
metode i Service som så kalder denne funktion i Dao, men det fandt vi i gruppen som unødvendigt da det<br />
blot skaber mere uoverskuelighed.<br />
private class BtnPlukListener implements ActionListener {<br />
public void actionPerformed(ActionEvent e) {<br />
if (!list.isSelectionEmpty()) {<br />
Proces p = (Proces) list.getSelectedValue();<br />
if (p.getStatus() != StatusType.NOT_DONE) {<br />
if (p.getStatus() == StatusType.OLD) {<br />
JOptionPane.showMessageDialog(MainFrame.this, "Tilføj til spild",<br />
"Næste behandling", JOptionPane.INFORMATION_MESSAGE);<br />
dao.addTilSpild(p.getPortion());<br />
} else {…}<br />
Her kalder vi direkte til Dao klassen for at tilføje den valgte Portion til spild (dao.addTilSpild(p.getPortion());<br />
Fejl håndtering (Frederik)<br />
I vores system har vi gået ud fra at den daglige bruger af systemet har modtaget et minimum af<br />
undervisning i hvordan systemet fungerer. Derfor har vi sigtet efter at gøre systemet meget brugervenligt<br />
og fejlfrit.<br />
Til at håndtere disse fejl har vi gjort følgende.<br />
If – sætninger<br />
Vi bruger hovedsagligt if - sætninger til at kontrollere at der bliver tastet et gyldigt input og at de<br />
overholder systemets krav, ved den pågældende handling der udføres.<br />
if (navn.length()!= 0 && valgte.size() != 0) {<br />
if (opskrift == null) {<br />
Opskrift o = Service.getInstance().opretOpskrift(navn);<br />
int index = 1;<br />
for (Behandling b : valgte) {<br />
o.addBehandlingsIndeks(Service.getInstance().opretBehandlingsIndeks(index, b));<br />
index++;<br />
}<br />
}<br />
else {<br />
Service.getInstance().updateOpskrift(opskrift, navn, valgte);<br />
}<br />
Det ovenstående eksempel viser at man ikke kan lave en opskrift uden at der er indtastet navn og valgt<br />
minimum en behandling, fra listen valgte behandlinger.<br />
Try – catch<br />
Try – catch bliver brugt til at håndtere exceptions. Ved oprettelsen af en behandling har vi eksempelvis<br />
brugt en Try – catch til at sørge for at der ikke bliver indtastet bogstaver, hvor der forventes en talværdi.<br />
try {……}<br />
catch (NumberFormatException ex) {<br />
Side 46 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
JOptionPane.showMessageDialog(BehandlingCDialog.this,<br />
"Vær venlig at brug tal", "Fejl ved input",<br />
JOptionPane.ERROR_MESSAGE);<br />
Til at vise hvilke fejl brugeren begår, har vi lagt stor vægt på fejlmeddelelser i Gui i form af en JOptionPane<br />
der kommer med en given løsning. Derudover er der også visse knapper og felter der først bliver aktiveret<br />
når de korrekte foregående handlinger er gjort. Dette viser vi senere i vores guidede tour af systemet.<br />
For at beskytte imod yderligere fejl har vi lavet JUnit-test. Her henviser vi til afsnittet med JUnit-test og<br />
testdata, for at vise netop hvilke fejl vi forebygger imod.<br />
JUnit test (Mads)<br />
Når en testcase er opstillet ud fra ækvivalensklasser samt grænseværdier skal det også bruges til noget.<br />
Derfor er der i den første version af dette system blevet implementeret JUnit test for de fleste af de mere<br />
interessante klasser med de metoder som ikke blot er af typen get og set.<br />
I dette afsnit vil der blive gennemgået en JUnit test ud fra den modul test som tidligere er blevet<br />
gennemgået af klassen Proces. Grunden til at denne klasse er valgt var af den grund at den indeholdte klare<br />
intervaller hvor objektet kunne have forskellige tilstande.<br />
Der er mange måder man kan implementere en sådan test og her vil der blive gennemgået to forskellige for<br />
at vise hvor meget kode der kan være til forskel, mellem en minimalistisk og en slavisk implementering.<br />
Til at starte med kan man kigge på grænseværdierne i tabellen som tidligere opstillet, og lave et assert-tjek<br />
for hver af resultaterne og sammenligne med de forventede resultater. Denne metode er en meget direkte<br />
tilgang, men kræver meget kopiering af kode som kan resultere i svær debugging ved evt. copy-paste fejl.<br />
Nedenstående udpluk af kode kommer fra testklassen for Proces-klassen. Her kan man se hvordan man kan<br />
tjekke for hver grænseværdi i tabellen.<br />
public class ProcesTest {<br />
...<br />
@Test<br />
public void testBeregnStatus_Toerring_SD(){<br />
Date curDate = null;<br />
proces = portion.getAktuelProces();<br />
Date start = proces.getStartTid();<br />
Toerring t1 = (Toerring) b1;<br />
curDate = DateUtil.createDate(start, 0);<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.NOT_DONE);<br />
curDate = DateUtil.createDate(start, t1.getMinimum() - 1);<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.NOT_DONE);<br />
curDate = DateUtil.createDate(start, t1.getMinimum() - 1);<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.NOT_DONE);<br />
curDate = DateUtil.createDate(start, t1.getMinimum());<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.MINIMUM);<br />
curDate = DateUtil.createDate(start, t1.getMinimum() + 1);<br />
Side 47 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.MINIMUM);<br />
curDate = DateUtil.createDate(start, t1.getIdeal() - 1);<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.MINIMUM);<br />
curDate = DateUtil.createDate(start, t1.getIdeal());<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.IDEAL);<br />
curDate = DateUtil.createDate(start, t1.getIdeal() + 1);<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.IDEAL);<br />
curDate = DateUtil.createDate(start, t1.getMaksimum() - 1);<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.IDEAL);<br />
curDate = DateUtil.createDate(start, t1.getMaksimum());<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.MAKSIMUM);<br />
curDate = DateUtil.createDate(start, t1.getMaksimum() + 1);<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.OLD);<br />
curDate = DateUtil.createDate(start, t1.getMaksimum() + 5);<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.OLD);<br />
}<br />
}<br />
Som man kan se på ovenstående eksempel er der rigtig meget kode for ikke særlig meget test. Derfor kan<br />
man optimere det ved at lade kode itterere igennem alle værdier fra den første grænseværdi og til den<br />
sidste. Nogen vil argumentere for at dette ikke er i henhold til ækvivalensklasse-testing eftersom man<br />
benytter sig af alle værdierne frem for blot grænseværdierne.<br />
public class ProcesTest {<br />
...<br />
@Test<br />
public void testBeregnStatus_Toerring(){<br />
proces = portion.getAktuelProces();<br />
Date start = proces.getStartTid();<br />
Toerring t1 = (Toerring) b1;<br />
for(int i = 0; i < t1.getMaksimum() + 3; i++){<br />
Date curDate = DateUtil.createDate(start, i);<br />
if(i < t1.getMinimum())<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.NOT_DONE);<br />
else if(i >= t1.getMinimum() && i < t1.getIdeal())<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.MINIMUM);<br />
else if(i >= t1.getIdeal() && i < t1.getMaksimum())<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.IDEAL);<br />
else if(i == t1.getMaksimum())<br />
Side 48 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.MAKSIMUM);<br />
else<br />
assertTrue(proces.beregnStatus(curDate) == StatusType.OLD);<br />
}<br />
}<br />
...<br />
}<br />
Som man kan se på ovenstående eksempel er dette meget mere minimalistisk at læse og forstå. Dog skal<br />
det siges at det dog kræver at man sætter de forskellige if-else if statements rigtigt op for at få de korrekte<br />
resultater i henhold til programmets nuværende implementering. Dette er dog ikke noget problem da disse<br />
statements blot skal laves i henhold til ækvivalensklassernes deffinitationer fra før.<br />
For at færdigøre denne gennemgang af JUnit test skal der også tages forbehold for at det ikke blot er<br />
tørrings behandlinger der kan være i et proces-objekt. Dette tjek er designet på samme måde som ved<br />
Toerrings-objektet så derfor henvises der blot til source-koden da det ville være redundant at gennemgå<br />
dette igen.<br />
For at have endegyldigt testet denne klasse skal konstruktoren i klassen også testes. Dette kan gøres ved at<br />
opstille de forventninger man har til den, som fx initialisering af forskellige lister og elementer ved at tjekke<br />
om de er null. Grunden til at gøre dette er for at undgå forskellige exceptions som fx null-pointer exceptions<br />
pga. ikke initializerede lister.<br />
I dette test-case er tjekket af konstruktoren designet som følgende hvor største delen af klassens attributter<br />
bliver tjekket om de er sat til det ønskede.<br />
public class ProcesTest {<br />
...<br />
@Test<br />
public void testProces() {<br />
assertTrue(proces.getStartTid() != null);<br />
assertTrue(proces.getBehandling() == b1);<br />
assertTrue(proces.getPortion() == portion);<br />
assertTrue(proces.getStatus() == StatusType.NOT_DONE);<br />
}<br />
}<br />
Specielt interessant kode (Fælles)<br />
Som ved alle andre systemer er der altid noget kode som er mere interressant end så meget andet. Derfor<br />
er dette afsnit tildelt til lige præcis dette, nemlig en gennemgang af det kode som udviklerne har fundet<br />
særlig interessant at arbejde med.<br />
TimeThread & SystemDato klasserne<br />
En af de sjovere problemer som dette system har været udsat for har været, hvordan skal det testes nu hvor<br />
systemet skal opdatere hver gang der er gået en ny dag? Det nemme svar ville være at implementere en<br />
knap til opdatering, men nu hvor undervisningen har vist at dette kan håndteres igennem brugen af tråde i<br />
programmeringen var dette det absolutte mest optimale valg. Og det sjoveste, nu hvor det fik GUI-en til at<br />
skifte farve automatisk.<br />
Side 49 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Så hvad er det lige der er blevet gjort for at systemet er kommet til at kunne automatisk opdatere systemet i<br />
real-time men samtidig at opdatere lidt oftere når systemet bliver testet?<br />
Det første problem der skulle overvindes var at lave en tråd som konstant kører, sideløbende med hovedsystemet.<br />
Så derfor var det nødvendigt at implementere en klasse til lige præcis dette formål, nemlig<br />
TimeThread-klassen.<br />
public class TimeThread extends Thread {<br />
…<br />
private final int DELAY = 10000;<br />
private final boolean TEST = true;<br />
…<br />
}<br />
Denne klasse extender som en selvfølge Thread superklassen for at det er muligt at kører den som en tråd<br />
sideløbende med resten. For at håndtere både hvor ofte tråden skal tjekke for om der er gået en ny dag<br />
(real-time) eller inkrementere test-systemets dato med en (test), samt håndtere om den skal gøre det ene<br />
eller andet er der i klassen blevet deffineret to konstanter. Nemlig DELAY som håndtere hvor ofte den skal<br />
gøre noget samt TEST som håndtere om det er det ene eller andet mode systemet skal kører efter.<br />
public class TimeThread extends Thread {<br />
…<br />
public void run() {<br />
Date date;<br />
try {<br />
if (TEST) {<br />
while (true) {<br />
Thread.sleep(DELAY);<br />
date = DateUtil.createDate(dato.getDato(), 1);<br />
dato.setDato(date);<br />
service.checkVareStatus();<br />
}<br />
} else {<br />
while (true) {<br />
Thread.sleep(DELAY);<br />
date = new Date();<br />
if (DateUtil.daysDiff(date, dato.getDato()) != 0) {<br />
dato.setDato(date);<br />
service.checkVareStatus();<br />
}<br />
}<br />
}<br />
} catch (InterruptedException e) {<br />
}<br />
}<br />
…<br />
}<br />
Så er det basale på plads, så er der faktisk kun en interessant metode tilbage, nemlig run-metoden. Denne<br />
metode bliver brugt når tråden, som noget af det første i programmet, bliver initialiceret hvilket gør at det<br />
der er deffineret i denne metode skal danne rammer for hele systemets levetid. For at håndtere det at<br />
Side 50 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
tråden ikke skal slutte er der i denne lavet et tjek på om systemet er i det ene eller andet mode for derefter<br />
at begynde en uendelig løkke. Til at starte med i loopet bliver tråden sat til at sove i det antal milisekunder<br />
som er deffineret i DELAY konstanten for at danne et interval for hvornår tråden skal gentage sine aktioner.<br />
Når dette så er overstået er det så afhængigt af om systemet er i test-tilstand eller ej hvad den så gør. Hvis<br />
den er i test-tilstand henter den så systemets nuværende dato fra singleton klassen SystemDato som den så<br />
tilføjer en dag til efterfulgt af at den sætter SystemDato til at have den nye dato. Så for hver DELAY<br />
milisekunder bliver systemets dato inkrementeret med en.<br />
Men hvis systemet ikke er i test men i real-time tilstand går den ind og tjekker på om computerens<br />
nuværende dato er en anden end den i SystemDato klassen. Hvis dette er sandt vil SystemDato blive sat til<br />
at have den aktuelle computer dato. Igen, dette tjek vil blive foretaget for hvert DELAY milisekunder.<br />
Som en afsluttende del i både test og real-time modes bliver service metoden checkVareStatus kaldt. Denne<br />
metode bliver beskrevet som det næste.<br />
SystemDato klassen er en af de mere centrale klasser i systemet. Denne klasse holder altid den aktuelle<br />
dato om systemet så er i test-mode eller ej. Grunden til at denne klasse er i model pakken er alene fordi de<br />
klasser som fx Portion og Proces der skal tilgå en eller anden form for dato som skal repræsentere start- og<br />
slut-tider bliver nød til ikke bare direkte at tilgå computerens dato da dette ville gøre det umuligt at benytte<br />
et test-mode. På den måde henter de datoen fra denne klasse som altid har systemets aktuelle date objekt<br />
lige meget modet.<br />
checkVareStatus & beregnStatus metoderne<br />
Nu hvor systemets tidshåndtering er blevet forklaret er disse metoder det naturlige næste-valg, siden det er<br />
de metoder som bliver kaldt for hver gang TimeThread gennemgår en itteration.<br />
For hurtigt at gennemgå meningen med systemet, kan det sumeres op på få linjer. For hver 'dag' der går i<br />
systemet så skal systemets aktuelle processer (aktive portioner) opdateres, forstået på den måde at der skal<br />
tjekkes for om de skal have en ny status ud fra både den nuværende behandling samt forløbet de har været<br />
i behandlingen indtil nu.<br />
public class Service implements Subject {<br />
…<br />
public void checkVareStatus() {<br />
for (Opskrift o : dao.getOpskrifter()) {<br />
for (Portion p : o.getPortioner()) {<br />
Proces pp = p.getAktuelProces();<br />
if (pp.getStatus() != StatusType.DONE<br />
&& pp.getStatus() != StatusType.SPILD) {<br />
pp.beregnStatus(dato.getDato());<br />
}<br />
}<br />
}<br />
notifyObserver();<br />
}<br />
…<br />
}<br />
Den metode som så bliver kaldt for hver dags-inkrementering er checkVareStatus. Nogle vil nok mene at<br />
denne metode i sig selv, absolut ikke er interessat da det blot er to for-løkker med et enkelt tjek i midten.<br />
Men enkelt er nogle gange godt. Her tager vi alle opskrift-objekterne fra DAO-en, og som vi ved kan vi kører<br />
alle dens portioner igennem da de ligger som lister i opskrift-objekterne og derefter tjekke den aktielle<br />
processes status. Hvis den aktuelle proces ikke har status af DONE, hvilket vil betyde at portionen er færdig,<br />
Side 51 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
eller SPILD, hvilket betyder at den aktuelle portion er overført til spild, skal der kaldes en beregnStatus på<br />
portionen. Grunden til at dette tjek af den nuværende status er nødvendigt er fordi hvis de er færdige er de<br />
faktisk pakket og hvis de er spild, ja så er de godt på vej ud til en grisse-farm som fodder.<br />
public class Proces {<br />
…<br />
public StatusType beregnStatus(Date currentDate) {<br />
if (behandling instanceof Dragering) {<br />
if (DateUtil.daysDiff(<br />
getDoneDate(((Dragering) behandling).getVarighed()), currentDate) == 0) {<br />
slutTid = currentDate;<br />
status = StatusType.DONE;<br />
portion.naesteBehandling();<br />
}<br />
} else if (behandling instanceof Toerring) {<br />
Toerring t = (Toerring) behandling;<br />
int minDiff = DateUtil.daysDiff(getDoneDate(t.getMinimum()), currentDate);<br />
int idealDiff = DateUtil.daysDiff(getDoneDate(t.getIdeal()), currentDate);<br />
int maxDiff = DateUtil<br />
.daysDiff(getDoneDate(t.getMaksimum()), currentDate);<br />
if(status != StatusType.SPILD && status != StatusType.DONE){<br />
if (minDiff >= 0 && idealDiff < 0) {<br />
status = StatusType.MINIMUM;<br />
} else if (idealDiff >= 0 && maxDiff < 0) {<br />
status = StatusType.IDEAL;<br />
} else if (maxDiff == 0) {<br />
status = StatusType.MAKSIMUM;<br />
} else if (DateUtil.daysDiff(getDoneDate(t.getMaksimum()), currentDate) > 0) {<br />
status = StatusType.OLD;<br />
portion.setSlutTid(SystemDato.getInstance().getDato());<br />
}<br />
if (status != StatusType.NOT_DONE)<br />
slutTid = currentDate;<br />
}<br />
}<br />
return status;<br />
}<br />
…<br />
}<br />
Det beregnStatus så gør er faktisk slavisk arbejde, så at sige. Den har en parameter i form af den nuværende<br />
dato som start-tiden for processen skal tjekkes op i mod. Som man måske kan gætte sig til er det datoen fra<br />
SystemDato som normalt bliver givet med. Så hvorfor overhovedet have denne parameter med? Jo, for at<br />
kunne teste uden at skulle sætte SystemDato-klassen op, simpel dovenskab, og en lille bonus... Klassernes<br />
afhængighed bliver ikke nær så stor.<br />
Det selve metoden gør at tjekke for om behandlingen er af en bestemt type for efterfølgende at gennemgå<br />
en lang række tjeks for at se om der er sket nok til at processen skal skifte status. Som en start kan<br />
behandlingen fx være af typen Dragering. I dette tilfælde kan processen have to forskellige statustyper,<br />
NOT_DONE og DONE. Det skal så siges at en dragering har en varigheds-attribut som repræsentere den tid<br />
Side 52 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
behandlingen tager. For derfor at gå fra NOT_DONE til DONE kræver det at currentDate er lig med startTidattributten<br />
plus varigheds-attributten. Hvis dette er tilfældet skiftes der status og den næste behandling i<br />
opskriften bliver kaldet.<br />
Men hvad hvis den nu behandlingen er af typen Toerring? Jo her er det mere interessant da dette, som<br />
beskrevet i afsnittet omkring testing, indeholder nøje implementerede tjek for værdierne. Hver af disse<br />
tjeks kan resultere i at processen skifter status til MINIMUM til IDEAL til MAKSIMUM til OLD. Dette er den<br />
naturlige gang en proces kan komme igennem, forhåbentligt bliver portionen plukket før den ender med<br />
status OLD.<br />
Når alle portioner er blevet tjekket igennem kaldene i checkVareStatus er der et sidste metodekald til<br />
notifyObserver som leder til den sidste del af dette afsnit, nemlig ColorRender-klassen i MainFrame-klassen.<br />
ColorRender-klassen<br />
Det er okay bare at inkludere en processes status i dens toString metode for at indikere hvor langt den er<br />
nået i tørringen på lageret, men det giver ikke rigtig noget illustrativt til at idendikere den pågældende<br />
status. Altså det er nemmere at overse tekst med samme farve men med forskellig indhold. Derfor har<br />
udviklerne haft den ide, lige fra starten af designprocessen at der skulle være en eller anden form for farvekodning<br />
for hvornår en proces har en given status.<br />
public class MainFrame extends JFrame implements Observer {<br />
…<br />
private class ColorRenderer extends BasicComboBoxRenderer {<br />
private static final long serialVersionUID = 1L;<br />
@SuppressWarnings("unused")<br />
private JList list;<br />
@SuppressWarnings("unused")<br />
private Border border;<br />
public ColorRenderer(JList list) {<br />
this.list = list;<br />
border = new LineBorder(Color.WHITE);<br />
}<br />
public Component getListCellRendererComponent(JList list, Object value,<br />
int index, boolean isSelected, boolean cellHasFocus) {<br />
super.getListCellRendererComponent(list, value, index, isSelected,<br />
cellHasFocus);<br />
setText(value.toString());<br />
StatusType status = ((Proces) value).getStatus();<br />
if (status == StatusType.NOT_DONE)<br />
setBackground(listOpskrifter.getBackground());<br />
else if (status == StatusType.MINIMUM)<br />
setBackground(Color.yellow);<br />
else if (status == StatusType.IDEAL)<br />
setBackground(Color.green);<br />
else if (status == StatusType.MAKSIMUM)<br />
setBackground(Color.red);<br />
else if (status == StatusType.OLD) {<br />
Side 53 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
setBackground(Color.black);<br />
setForeground(Color.white);<br />
}<br />
if (isSelected)<br />
setBackground(new JList().getSelectionBackground());<br />
return this;<br />
}<br />
}<br />
}<br />
Til denne opgave er der blevet implementeret en privat klasse i GUI-pakkens MainFrame-klasse. Det klassen<br />
gør er at nedarve fra BasicComboBoxRender som basalt set er den der håndtere hvordan det illustrativt skal<br />
vises i GUI-en og ikke mindst hvad der skal stå i de forskellige elementer i JListen. Når listens indehold så<br />
bliver sat ved at kalde setListData bliver hver objekt som bliver sat i listen tjekket for dens pågældende<br />
status for derefter at sætte en tilhørende baggrundsfarve for at indikere den illustrativt.<br />
Denne illustrative funktion gør det muligt for folk der måske er ordblinde også at arbejde med dette system.<br />
Oven i det kan det være at det gør at folk, gennem læsningen af farver, undgår at der er særlig mange vare<br />
som går til spilde.<br />
Guided Tour (Fælles)<br />
Vi vil i vores guided tour vise hvordan vores system virker i en simulering. I det gennemgående eksempel vil<br />
vi vise hvordan en ny opskrift oprettes og oprette en portion med denne.<br />
Når programmet startes mødes vi af et vindue, hvor vi har valgt at bruge tabs til at manøvrere rundt i<br />
programmet. En opskrift tab der viser en liste over opskrifter, samt to knapper: enten til at oprette en ny<br />
opskrift eller få vist hvilke behandlinger en opskrift indeholder. Vi starter med at se hvad ”NiceLakrids”<br />
indeholder, for derefter at lave en ny opskrift.<br />
Side 54 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Vælges en behandling, aktiveres knapperne i midten, hvorefter man kan rykke op og ned på<br />
behandlingernes behandlingsindeks. Det er også muligt at fjerne en behandling fra NiceLakrids, eller tilføje<br />
en ekstra fra ”Alle behandlinger”. Det er ikke muligt at fjerne en behandling fra ”Alle behandlinger”.<br />
Vi opretter nu en ny opskrift og opretter og tilføjer denne en tørrings behandling, med minimum tørring 1<br />
dag, ideal tørring 2 dage og maksimum tørring 3 dage. Dette bliver denne opskrifts eneste behandling.<br />
Vi trykker nu ”Ok” knappen og opskriften bliver tilføjet listen over opskrifter i vores ”Opskrift” tab.<br />
Side 55 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Vi trykker nu på vores ”Portion” tab. Her findes en liste over alle igangværende processer. Til at starte med<br />
er listen altså lige nu tom. Vi trykker på ”Opret Portion” og får en liste med de mulige opskrifter. Vi vælger<br />
nu den netop oprettede opskrift og sætter en portion i gang.<br />
Da denne portions første og eneste behandling er af typen tørring, skal den ind på mellemvarelageret og<br />
have en placering. Vi vælger derfor en placering.<br />
Side 56 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Når en placering er valgt, sættes processen i gang. Portionens aktuelle proces vises i listen. I dette eksempel<br />
er der kun en behandling, som er en tørring. Denne tørring bør plukkes efter 2 dage, da den der har den<br />
ideelle konsistens. Til at illustrere processens status markeres portionen i listen i forskellige farver. Grå når<br />
portionen ikke har nået minimal tørring endnu og derfor ikke kan plukkes, gul ved minimal tørring, grøn ved<br />
ideel tørring, rød ved maksimal tørring og sort når tørringen har været for længe på lager og skal plukkes til<br />
spild. I dette eksempel plukker vi ved ideel tørring og portionen sendes derfor til pakning.<br />
Sammenligner vi de to virksomheders nettoomsætning, er Toms’ 4,31 gange større end <strong>Carletti</strong>s. Toms’ har<br />
dog endnu mere på lager end <strong>Carletti</strong> i forhold til omsætning da Toms’ varebeholdning er 5,9 gange større<br />
end <strong>Carletti</strong>s. Antager vi, at gælden til leverandørerne, er hvad der er blevet brugt på dette punkt, har<br />
Toms’ brugt 4,6 gange mere end <strong>Carletti</strong>.<br />
Side 57 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Toms har meget mere på lager, men <strong>Carletti</strong> bruger mere på leverandører i forhold til beholdningen. Dette<br />
kan tyde på at <strong>Carletti</strong> vil gøre mere for at komme af med deres varer, men at de også må betale sig fra det<br />
i form af flere penge på transport eller leverandører.<br />
Disse tal kan selvfølgelig ikke sammenlignes ordentligt, da vi har lavet nogle antagelser, samt vi ikke kender<br />
grunden til fx Toms store varebeholdning. Der kan være forskel på fx produktionstiden hos Toms, som gør<br />
at varerne skal ligge længere tid på lageret.<br />
Som endelig vurdering af logistik systemet, må man sige at <strong>Carletti</strong> A/S er velfungerende, da de trods alt har<br />
et stort overskud(reference). Det ser ud til, at de er gode til at få sendt deres varer af sted fra deres lager,<br />
selvom de har en høj lagerservicegrad. Deres samspil mellem leveringsservice og logistikomkostninger ses<br />
fx i form af, at de både er masseproducerende men samtidig kan omstille sig. Dette viser, at de er<br />
leveringsfleksible og samtidig har logistikomkostningerne til at kunne fuldføre dette. Et spil som resulterer i<br />
logistisk effektivitet.<br />
Konklusion<br />
Delkonklusion - Informations Teknologi i Organisationer:<br />
Arbejdet med ITO har været en stor udfordring og en periode med mange frustrationer. Det var utrolig<br />
svært at begrænse sideantallet, da ITO er et meget vidt begreb og de givne problemstillinger kunne<br />
angribes på mange måder. Da vi endelig synes at have overkommet vores frustration og vi var kommet<br />
frem til en fornuftig indgangsvinkel, kunne vi begynde at skrive.<br />
Vores resultat i ITO er endt med at have størstedelen af fokus på hvordan <strong>Carletti</strong> fungerer som<br />
produktionsvirksomhed, samt en løsning på mellemvarelager problemet.<br />
Delkonklusion - Software Design:<br />
Efter at have lavet en business case i ITO blev vi hurtigt enige om nogle centrale use cases. Dette gjorde at<br />
arbejdet med system design blev sat hurtigt i gang, da vi allerede har skabt os et godt overblik over,<br />
hvordan vores IT-løsning i sidste ende skal fungere. Dog faldt vi over nogle frustrationsmomenter, blandt<br />
andet synes iterationsprocessen uendelig, i det man hele tiden skulle vurdere og revurdere ens arbejde i<br />
forhold til nye tiltag.<br />
Vores resultat i SD gav et godt startskud til vores software konstruktionen. Vi synes især vores<br />
færdiggørelse af design diagrammet gav grundlag for gode centrale løsninger i forhold til use cases og<br />
derefter andre SD redskaber.<br />
Delkonklusion - Software Konstruktion:<br />
Vores software konstruktion er lavet på baggrund af vores system design. Det var derfor relativt hurtigt at<br />
få lavet programmets model og lave en simpel simulering uden GUI. SK forløbet handlede derfor at lægge<br />
sig tæt op ad vores design, som var en af udfordringerne i SK.<br />
Side 58 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Den største udfordring i software konstruktionen var at lave vores GUI, hvis simple design vi trods alt er<br />
meget tilfredse med. Alt i alt synes vi dog at vores program er yderst velfungerende og at det er lykkedes at<br />
opnå et brugervenligt enkeltbrugersystem.<br />
Overordnet konklusion:<br />
I dette projekt har vi arbejdet ud fra problemstillingen med et mellemvarelager problem angående<br />
overskridende tørretider, og vores opgave har været at lave et system der løser dette.<br />
Vores system håndterer oprettelsen af opskrifter, portioner, behandlinger, samt placeringer. Derudover<br />
bliver tørretidernes status vist i en liste med portioner i farvekoder til hurtigt at skabe et overblik over<br />
portionens status i handlingsforløbet. I forhold til <strong>Carletti</strong>s nuværende system med sedler, synes vi at dette<br />
er en fremragende løsning til deres problem med spildprocent.<br />
Samarbejdsmæssigt har vi været gode til i gruppen, at uddelegere opgaver men samtidigt assistere<br />
hinanden.<br />
Side 59 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Bilag<br />
Klassebeskrivelser<br />
Navn:<br />
Opskrift<br />
Mening med klassen:<br />
Denne klasse er roden til at hele modellen kan fungere. Uden den her klasse vil mange af de følgende<br />
klasser ikke kunne eksistere. Opskrift-klassen er en simpel klasse der modellere en opskrift på et produkt<br />
som fx drageret lakrids.<br />
Denne klasse kunne dog godt have indeholdt en liste over ingredienser og lignende, men eftersom dette<br />
er et lager system var det kun nødvendigt med en rækkefølge af behandlinger.<br />
Attributter:<br />
navn : String<br />
o Dette er en form for overskrift på opskriften – som fx ”Drageret Lakrids”, som identificere<br />
objektet<br />
count : int<br />
o Denne variabel holder styr på hvor mange portiner der er lavet af den specifikke opskrift<br />
og danner bund for et ID på portion-objekterne der bliver skabt ud fra opskriften<br />
portioner : List<br />
o Dette er en link-attribut som holder styr på alle de portioner som enten stadig er under<br />
behandlig eller som er færdigbehandlede. Spildte portioner bliver fjernet fra denne liste.<br />
behandlingsIndekser : List<br />
o Denne liste er også en link-attribut. Dens opgave er holde objekter af typen<br />
BehandlingsIndeks – som holder styr på de behandliger en opskrift skal igennem og i<br />
hvilken rækkefølge de skal igennem dem.<br />
Metoder:<br />
Opskrift(navn : String)<br />
o Konstruktoren for klassen som opretter et objekt med et specifikt navn<br />
opretPortion() : Portion<br />
o Metode til at oprette et nyt portions-objekt. Denne metode får ingen parametre med da<br />
klassen indeholder nok information til selv at oprette et Portions objekt med de rette<br />
informationer. Dette sikre også at brugeren ikke videregiver forkerte data til metoden. Når<br />
den objektet er blevet oprettet vil det oprettede objekt både blive tilføjet til listen over<br />
portioner samt returneret til brugeren.<br />
fjernPortion()<br />
o Metode til at fjerne et specifikt portions objekt fra listen med opskriftens portioner.<br />
Denne metode vil normalt vis kun blive brugt hvis en portion er blevet for gammel og skal<br />
flyttes til spild.<br />
naesteBehandlingsIndeks(indeks : int) : BehandlingsIndeks<br />
o Når en portion så er færdig med en behandlig og skal videre til den næste behandling i<br />
rækkefølgen af behandlinger bliver denne metode kaldt ud fra portionens nuværende<br />
behandlingsindeks. Det nye BehandlingsIndeks vil derefter blive fundet frem og<br />
returneret. Hvis portionen har været ved den sidste behandling vil der bliver returneret<br />
null.<br />
addBehandlingsIndeks(behandlingsIndeks : BehandlingsIndeks)<br />
o Denne metode tilføjer et BehandlingsIndeks til opskriften. Der skal dog sørges for at<br />
Side 60 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Multiplicitet og association:<br />
behandlingsindeksernes indeks kommer i en kontinuerlig rækkefølge så der startes fra<br />
nummer et og ellers to, tre, og fire osv. Der må bare ikke optræde nogle gaps mellem<br />
dem.<br />
Denne klasse har to associationer til andre klasser. Den ene er hen til klassen BehandlingsIndeks som er en<br />
enkeltrettede association mod den sidstnævnte klasse. Grunden til dette er at en Opskrift kan skal have<br />
mindst et BehandlingsIndeks, ergo mindst en behandling, men kan have flere. Modsat er det ikke<br />
nødvendigt for BehandlingsIndekserne at vide hvilken Opskrift de tilhører da man på den måde kan bruge<br />
dem til andre Opskrift-objekter så længe det giver meningen i deres rækkefølge. Denne multiplicitet bliver<br />
implementeret gennem en liste i Opskrift objektet over BehandlingsIndekser.<br />
Den anden association er over til klassen Portion (beskrevet senere). Denne sammenhæng er af typen<br />
komposition af den grund at en Portion altid skal have en Opskrift tilknyttet, derfor skal den af gode<br />
grunde oprettes igennem en Opskrift. Dette sikre at Portionen får en Opskrift tilknyttet da det kan<br />
videregives ved oprettelsen. Selve multipliciteten er næsten allerede forklaret. En Opskrift kan have<br />
mange portioner på en gangn men en Portion skal have en Opskrift. Selve implementeringen af dette<br />
ligger i bl.a. en liste i Opskrift-klassen samt metoder til at oprette en Portion. Portions-klassens<br />
konstruktor er derfor gjort package-private så det kun er interne klasser i model pakken der kan benytte<br />
den – her tiltænkt Opskrift-klassen.<br />
Side 61 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Navn:<br />
Portion<br />
Mening med klassen:<br />
Denne klasse er til for at modellere en portion af en opskrift – forstået på den måde at det er når man har<br />
besluttet sig for at der skal laves mere af en type Opskrift oprettes der et objekt af Portions-klassen for at<br />
illustere en nybegyndt omgang af en Opskrift.<br />
Attributter:<br />
vareNr : int<br />
o Dette nummer et ID på hvor i rækkefølgen af oprettede portioner af en specifik opskrift<br />
denne portion er. Dette nummer er videregivet fra Opskrift-objektet som opretter<br />
Portionen.<br />
startTid : Date<br />
o Når en portion bliver oprettet gennem en opskrift bliver der registreret en dato på<br />
hvornår portionen blev startet/oprettet.<br />
slutTid : Date<br />
o Når en portion har været gennem alle behandlinger bliver der registreret en dato for<br />
hvornår portionen blev færdig.<br />
opskrift : Opskrift<br />
o Som beskrevet tidligere er dette en link-attribut til Opskrift-klassen som bliver videregivet<br />
ved oprettelsen af Portions-objektet gennem kaldet til opretPortion.<br />
processer : List<br />
o Liste over de processer (behandlinger) en portion har været igennem indtil nu. Hvis det<br />
sidste element i listen er null er det en indikation på at portionen er færdig.<br />
placering : Placering<br />
o Denne attribut beskriver den placering den specifikke portion har på lageret når den står<br />
og udfører en proces med en behandling af typen Toerring<br />
Metoder:<br />
Portion(opskrift : Opskrift, vareNr : int, behandlingsIndeks : BehandlingsIndeks)<br />
o Klassens konstruktor, package private, som opretter og initialisere de forskellige<br />
attributter klassen har. Her iblandt sætter opskrifts objektet, vareNr samt det første<br />
behandlingsindeks i rækkefølgen af behandlingsindekser<br />
naesteBehandling()<br />
o Denne metode får fat i det næste BehandlingsIndeks fra Opskrift objektet hvor efter den<br />
begynder en ny Proces med den pågældende Behandling som ligger i BehandlingsIndeksobjektet<br />
opretProces(behandling : Behandling) : Proces<br />
o Når et Portions-objekt skal til sin næste behandling skal denne registreres gennem<br />
oprettelsen af et Proces-objekt som holder behandlingen samt status for denne.<br />
getAktuelProces() : Proces<br />
o Når man ønsker at finde ud af hvor en Portion pt. er i hele forløbet kaldes denne metode.<br />
Hvis en portion er færdig vil den returnere null ellers vil den sidste proces i portionens<br />
liste over processer blive returneret.<br />
Multiplicitet og association:<br />
Denne klasse har tre associationer til andre klasser, men eftersom den ene af dem allerede er blevet<br />
beskrevet vil der her blive forklaret de to andre. Den første association er til klassen Placering. Her kan en<br />
Side 62 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
portion enten have nul eller en placering forstået på den måde at enten er Portionen på lageret (optager<br />
en placering) ellers er den til dragering (optager ingen placering). Implementeringen af denne er en simpel<br />
attribut i klassen af typen Placering som kan sættes gennem kald til setPlacering(placering : Placering).<br />
Den anden association er til klassen Proces. Denne association er af typen komposition som gør at Portion<br />
skal stå for oprettelsen af objekter af Proces-klassen. Forholdet mellem Portion og Proces er en til nul til<br />
mange, alene af den grund at en portion har været igennem mange processer. Nogen vil dog mene at en<br />
portion kun burde have en proces, men eftersom vi gerne vil holde styr på hvad en portion har været<br />
igennem og hvornår, er der her valgt at holde multipliciteten som en til nul til mange. Implementeringen<br />
af dette forhold er som i tidligere beskrivelse. Nemlig i form af en liste med processer i Portions-klassen<br />
samt et objekt af typen Portion i Proces-klassen som bliver givet ved oprettelsen af Proces-objekterne.<br />
Side 63 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Navn:<br />
Proces<br />
Mening med klassen:<br />
Klasse til at modellere en proces, en specifik portion har været igennem på en specifikt tidspunkt. En<br />
proces er derfor noget der bliver oprettet løbende når en Portion er blevet færdig med en foregående<br />
behandling og så skal til en ny.<br />
Attributter:<br />
startTid : Date<br />
o Når en proces bliver oprettet bliver der registreret en tid<br />
slutTid : Date<br />
o Når en proces, dens behandling, er færdig bliver der ligeledes registreret en tid<br />
behandling : Behandling<br />
o Link-attribut som beskriver den behandling en proces skal igennem før den kan erklæres<br />
færdig.<br />
portion : Portion<br />
o Link-attribut som er det objekt, af typen Portion, som har oprettet den specifikke proces.<br />
status : StatusType<br />
o For hver gang beregnStatus() bliver kaldt bliver attributten sat til at være den nye status<br />
processen har – se beskrivelse af enumklasse. Attributten beskriver hvor i behandlingen<br />
en proces er.<br />
StatusType.NOT_DONE – når en behandling ikke er færdig<br />
(behandlingsuafhængig)<br />
StatusType.MINIMUM – når en tørring har opnået minimum tørretid<br />
StatusType.IDEAL – når en tørring har opnået ideal tørretid<br />
StatusType.MAKSIMUM – når en tørring har opnået maksimum tørretid<br />
StatusType.DONE – når en dragering er færdig<br />
StatusType.OLD – når en portion har tørret længere tid end maksimum<br />
Metoder:<br />
Proces(behandling : Behandling, portion : Portion)<br />
o Konstruktoren for klassen. Denne er package-private da denne klasse har et kompositionsforhold<br />
til Portions-klassen. Når denne bliver kaldt bliver den kaldt så den kan oprette en<br />
ny proces for en specifik portion med en specifik behandling.<br />
beregnStatus(currentDate : Date) : StatusType<br />
o Metode til at beregne en eventuel ny status for processen. Denne metode får en dato<br />
med som den bruger til at sammenligne med Proces-objektets startTid. Hvis<br />
beregningerne ud fra currentDate så opfylder kravet for et status-skift bliver statusattributten<br />
sat til den nye beregnede status. Denne vil også blive returneret. Det er<br />
forskelligt hvad kravenen for sådan et skift er, alt afhængig af om det er en behandling af<br />
typen toerring eller dragering.<br />
Multiplicitet og association:<br />
Denne klasse har to associationer, hvor af den ene allerede er blevet forklaret. Der vil nu blive forklaret<br />
den anden. Den anden er en enkeltrettet association til klassen Behandling. For at forklare dette er det<br />
vigtigt af forstå at grunden til at Proces-klassen er i modellen er for at vi kan køre statistik på hvornår de<br />
forskellige processer er startet, sluttet og for hvilke behandling. Derfor er en proces en form for<br />
indpakning af en behandling der gør at vi kan tilføje flere data til en behandling som ikke ville have noget<br />
Side 64 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
direkte med en behandling at gøre. Så en proces har en behandling den holder styr på men behandlingen<br />
kender ikke noget til processen da den er enkeltrettet og kan derfor bruges i mange processer, bl.a. for<br />
andre portioner og opskrifter samt behandlingsindekser.<br />
Side 65 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Navn:<br />
Placering<br />
Mening med klassen:<br />
Klassen skal repræsentere de placeringer der er på lagergulvet på lageret. De bliver beskrevet ud fra to<br />
koordinater så de nemt kan findes.<br />
Attributter:<br />
x : int<br />
o Koordinat værdien for x-aksen<br />
y : int<br />
o Koordinat værdien for y-aksen<br />
portion : Portion<br />
o Objektet af typen Portion som bliver sat når en portion kommer ind på den specifikke<br />
placering.<br />
Metoder:<br />
Placering(x : int, y : int)<br />
o Klassens konstruktor som opretter et objekt med et koordinatsæt x og y<br />
frigoer()<br />
o Når en portion skal til en dragerings-behandling og lige har stået på lageret bliver denne<br />
metode kaldt som så vil frigive placeringen og sætte portionens placerings-attribut til null<br />
så placerings-objektet kan optages af en ny portion<br />
optag(portion : Portion)<br />
o Når en portion skal have en plads på lageret kaldes denne metode som så både vil sætte<br />
dens egen portions-attribut til at være portionen men også sætte portionens placeringsattribut<br />
til at være den valgte placering.<br />
isFri() : Boolean<br />
o Tjekker om portions-attributten er sat, hvis den er bliver der returneret false ellers true.<br />
Multiplicitet og association:<br />
Denne multiplicitet er allerede forklaret tidligere.<br />
Side 66 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Navn:<br />
BehandlingsIndeks<br />
Mening med klassen:<br />
Klasse til at kunne holde styr på i hvilken rækkefølge de forskellige behandlinger skal komme i.<br />
Attributter:<br />
indeks : int<br />
o Nummer som beskriver den placering en behandling har i forhold til andre i opskriftens<br />
behandlingsforløb<br />
behandling : Behandling<br />
o Behandlingen på det specifikke indeks som en portion skal igennem når den kommer til<br />
dette indeks<br />
Metoder:<br />
Indeholder almene get metoder til brug i andre klasser.<br />
Multiplicitet og association:<br />
Denne klasse har to associationer hvoraf den ene er beskrevet tidligere. Den anden association er en<br />
enkeltrettet nul til mange til en til klassen Behandling. Der skal derfor forståes at et behandlingsindeks skal<br />
have en behandling for at kunne eksistere men behandlingen behøver ikke at vide hvilket indeks den ingår<br />
i. Dette gør derfor også at den samme behandling kan indgå i mange forskellige behandlingsindekser.<br />
Side 67 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Navn:<br />
Behandling<br />
Mening med klassen:<br />
Denne klasse er en abstrakt klasse der gør det muligt at generalisere de to under-klasser som værende<br />
den samme type. Dette er den hovedsagelige grund til at denne klasse er med i systemet. Eftersom de to<br />
under-klasser ikke har noget attribut-mæssigt til fælles er denne klasse tom.<br />
Attributter:<br />
Metoder:<br />
Multiplicitet og association:<br />
Side 68 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Navn:<br />
Toerring<br />
Mening med klassen:<br />
Denne klasse skal modellere en tørring af en portion ud fra nogle givne attributter der beskriver hvor lang<br />
tid en portion skal være på lager for at opnå en specifik tørre-status.<br />
Hvis en portion står længere end til maksimum tid vil portionen få StatusType.OLD. Dette bliver beregnet,<br />
som beskrevet, i Proces-klassen<br />
Attributter:<br />
minimum : int<br />
o Antal dage en portion skal stå, beregnet ud fra processens startTid, for at få<br />
StatusType.MINIMUM<br />
ideal : int<br />
o Som ved minimum blot får portionen StatusType.IDEAL<br />
maksimum : int<br />
o Som ved minimum blot får portionen StatusType.MAKSIMUM<br />
Metoder:<br />
Multiplicitet og association:<br />
Denne klasse er en sub-klasse til super-klassen Behandling. Grunden til dette er en del af designet, er for<br />
at man kan generellisere mellem de to behandlingstyper, tørring og dragering, så man kan lave en liste<br />
med begge typer behandlinger i, i Proces klassen.<br />
Side 69 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Navn:<br />
Dragering<br />
Mening med klassen:<br />
Er med i modellen for at modellere en behandling af typen dragering<br />
Attributter:<br />
type : DrageringsType<br />
o Denne attribut er af en enum-type som begrænser hvilke værdi attrubutten får<br />
DrageringsType.FARVE – type en Dragering får hvis portionen skal have et farvelag<br />
på<br />
DrageringsType.SUKKER – type en Dragering får hvis portionen skal have et<br />
sukkerlag på<br />
varighed : int<br />
o Beskriver den varighed det tager, i dage, før at portionen er færdig med den pågældende<br />
dragerings-behandling.<br />
Metoder:<br />
Multiplicitet og association:<br />
Denne klasse er en sub-klasse til super-klassen Behandling. Grunden til dette er en del af designet, er for<br />
at man kan generellisere mellem de to behandlingstyper, tørring og dragering, så man kan lave en liste<br />
med begge typer behandlinger i, i Proces klassen.<br />
Side 70 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Navn:<br />
SystemDato<br />
Mening med klassen:<br />
Denne klasse er med for at have et centralt sted objekter i modellen kan hente en dato fra. I samarbejde<br />
med TimeThread gør det det muligt at simunere en eksekvering af systemet så man ikke skal vente en hel<br />
dag på at se om systemet opdatere en proces' status. Grunden til at den ligger i modellen er at hvis den lå<br />
andre stedder vil model-klasserne ikke kunne tilgå den da det vil give et kald op i de fire(tre) lag af<br />
modellen, hvilket ikke er en valid aktion.<br />
Klassen er designet efter singleton-mønstret hvilket betyder at der i hele systemet kun er et objekt af<br />
denne type.<br />
Attributter:<br />
dato : Date<br />
o Denne attribut holder på systemets nuværende dato. Den vil ved initialisering blive sat til<br />
systemets nuværende dato igemmen kald til Date-konstruktoren<br />
Metoder:<br />
Multiplicitet og association:<br />
Denne klasse har ikke et forhold til andre klasser som den har kendskab til. Se beskrivelsen for<br />
TimeThread-klassen for større uddybelse.<br />
Side 71 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Navn:<br />
TimeThread<br />
Mening med klassen:<br />
Denne klasse håndtere det at tjekke for om der er gået en dag. Klassen er en udvidelse af java klassen<br />
Thread hvilket gør at den kører sideløbende med resten af programmet. Klassen er opbygget så den har to<br />
tilstande, en til test og en til real-time. Det gør at man kan teste så man siger at for hver gang der er gået<br />
et konstant antal sekunder vil der være 'gået' en dag. Dette gør at når systemet skal testes for fx skift i<br />
portioners statuser skal programmøren der tester det ikke vente en hel dag på at se et skift i status. Den<br />
anden tilstand er den som bliver valgt når systemet skal kører ude på lageret. Her tjekker tråden for om<br />
der er gået en dag, igen, hver gang der er gået et antal sekunder.<br />
I begge tilstande vil der ske det samme når kravene for et dag-skifte er opfyldt, uafhængig af hvilken<br />
tilstand der er tale om. Det der sker er at singleton-objektet af klassen SystemDato bliver sat til en ny dato<br />
og Service klassens metode, checkVareStatus bliver kaldt for at opdatere alle portioners status.<br />
Attributter:<br />
final DELAY : int<br />
o Denne konstant bestemmer hvor ofte der skal ske noget, om det er tjek for ny dag (realtime<br />
mode) eller om det er at der skal inkrementeres en dag. Denne konstant er udtryk for<br />
de millisekunder tråden skal sove før den tjekker igen.<br />
final TEST : boolean<br />
o Konstant til at holde styr på om det er test-mode eller ej. Hvis true den sat til test-mode.<br />
Metoder:<br />
Multiplicitet og association:<br />
Denne klasse har to forhold der er værd at forklare, dette er kort beskrevet i meningen med klassen. Når<br />
kriterierne for et tjek er opfyldt går klassen ind og opdatere datoen på singleton objektet af SystemDato<br />
samt kalder checkVareStatus i singleton objektet i Service. Multipliciteten er lidt triviel at forklare da den<br />
kun kan trække et objekt fra hver klasse da der kun er muligt at oprette et af begge objekter.<br />
Side 72 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Navn:<br />
Service<br />
Mening med klassen:<br />
Klasse som har ansvaret for at oprette objekter samt lagre dem i DAO-en. Det er også denne klasses<br />
ansvar at tjekke alle portioners dato hver gang TimeThread sætter den til det. Denne klasse er som DAO<br />
og SystemDato også designet ud fra singleton-mønstret.<br />
Attributter:<br />
Metoder:<br />
opretOpskrift(navn : String) : Opskrift<br />
o Metode til at oprette og opbevare et Opskrift-objekt ud fra et givent navn.<br />
opretBehandlingsIndeks(indeks : int, behandling : Behandling) : BehandlingsIndeks<br />
o Metode til at oprette og returnere et behandlingsindeks ud fra et indeks og en behandling<br />
opretPlacering(x : int, y : int) : Placering<br />
o Metode til at oprette et Placerings-objekt samt opbevare det.<br />
opretToerring(minimum : int, ideal : int, maksimum : int) : Toerring<br />
o Metode til at oprettet et Toerrings-objekt ud fra givne værdier for forskellige stadier for<br />
tørring. Det er dog et krav at følgende udtryk er overholdt: 0 < minimum < ideal <<br />
maksimum. Dette objekt bliver også opbevaret i DAO-en.<br />
opretDragering(type : DrageringsType, varighed : int) : Dragering<br />
o Metode til at oprette et Dragerings-objekt udfra dens type samt varighed. Dette objet<br />
bliver også opbevaret i DAO-en.<br />
checkVareStatus()<br />
o Denne metode bliver hovedsageligt kaldt af TimeThread som efter et givent tidsrum<br />
kalder den. Derefter tjekker metoden om der er nogle ændringer i de forskellige<br />
portioners status ved at kalde beregnStatus(currentDate : Date) hvor parameteren er<br />
datoen fra SystemDato-klassen. Når disse er tjekket bliver der kaldt en notifyObserver<br />
metode der siger til GUI-en at der er sket ændringer i de forskellige statuser og den skal<br />
derfor opdatere sine grafiske repræsentationer i form af lister.<br />
Multiplicitet og association:<br />
Denne klasse er en af de mere centrale og interessante klasser når man snakker om forhold til andre<br />
klasser. Til at starte med så har den et forhold til SystemDato-singletonklassen. Grunden til dette er at når<br />
TimeThread-klassen tjekker og udfører aktionerne ved et gyldigt tjek er at kalde checkVareStatus som går<br />
ind og sammenligner den nuværende SystemDato dato med de forskellige deadlines som portionerne har.<br />
Derfor skal den kunne hente SystemDato objektet for at hente dens dato og sammenligne ud fra den. Der<br />
udover har den et forhold til DAO-klassen. Da denne klassen fx opretter en Opskrift skal denne også kunne<br />
gemmes efter oprettelsen. Dette gøres ved at hente DAO-singleton-objektet og gemme den i det. Dog<br />
behøver DAO-en ikke kende noget til Service klassen, derfor den givne multiplicitet.<br />
Dernæst har denne klasse en implementering af interfacet Subject. Grunden til dette er for at hvergang<br />
klassen har kørt dens checkVareStatus skal den sende besked til dens observere, som i dette tilfælde er<br />
GUI-en, MainFrame, da denne så skal opdatere dens respektive grafiske lister.<br />
Side 73 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
Design Klasse Diagram<br />
Side 74 af 75
23. april - <strong>2012</strong> Robert Nogal<br />
24. maj - <strong>2012</strong> <strong>Carletti</strong> Projekt <strong>2012</strong> Emil Thygesen<br />
Mads Pedersen<br />
<strong>Carletti</strong> Tidslinje<br />
Historisk tilbageblik fra 1990<br />
1990 – første pc bliver købt<br />
Posepakkemaskine anskaffes til dragé<br />
afdelingen – omsætningen stiger til 109<br />
mio. kroner<br />
1991 – stor ekspansion ved tilkøb af nye<br />
maskiner. 1992 – opkøb af tempereringsmaskiner<br />
fra nedlagte tyske fabrikker.<br />
1992 – køb af affugtningsanlæg til<br />
forbedring af skumprodukter. Salg og<br />
eksport stiger til 125 mio. kroner<br />
1992 – edb-systemet Concorde<br />
anskaffes.<br />
1994 – Jomet-pakkemaskine bliver købt<br />
til pakning af posevarer og p-tærter.<br />
Salget af posevarer fortsætter med at<br />
stige.<br />
Big Ben flyttes til Bentsfors hvorefter<br />
det flyttes til Warszawa et par år senere.<br />
Erling støbeanlægget flyttes ligeledes til<br />
Polen.<br />
1996 – Nordic Candy lukker – opkøber<br />
bøttepakker og SQC-system. Mangel på<br />
tørreplads og udbygning af kontor.<br />
1998 – Pålægschokolade pakningen<br />
bliver fuldautomatisk.<br />
2000 – Fabrik i Mjölby opkøbes.<br />
Fabrikken i Skødstrups pakkesystem<br />
opgraderes og omsætningen dette år steg<br />
til over 400 mio. kroner.<br />
2001 – Mange ældre maskiner bliver<br />
skiftet ud med nyere og Guernsey Bell<br />
bliver opkøbt pga. deres is produkter.<br />
Der bliver satset mere og mere på<br />
produkter der tjenes penge på.<br />
Pladsmangel – udbygning af fabrikken,<br />
hal 4 bliver til, en top moderne<br />
chokoladefabrik<br />
Hal 4 trækker mange ressourcer,<br />
yderligere investeringer bliver udskudt.<br />
1995 – <strong>Carletti</strong> opkøber Brdr.<br />
Christensen. Produktsortimentet<br />
udvides med velindarbejdet varer,<br />
såsom pålægschokolade.<br />
Salgsstyrken vokser og omsætningen<br />
stiger med over 30 mio. kroner. Dog er<br />
der underskud på 5 mio. kroner<br />
1996 – Concorden bliver udvidet med<br />
nye moduler: databasemodul, lønmodul<br />
og edi-modul.<br />
1999 – Brdr. Christensen implementeres<br />
og det ny in<strong>dk</strong>øbte grej køres ind i<br />
produktionen.<br />
2000 – Dansk Chokoladefabrik<br />
indlemmes. En konkurrent mindre.<br />
2001 – AXAPTA bliver implementeret.<br />
Fedt siloen i Skødstrup kan ikke<br />
længere opfylde fabrikkens krav.<br />
2003 – Der bliver satset stort på<br />
pålægschokoladen og det giver pote.<br />
2006 – Bulk-pakker alt pakning tiden<br />
bliver reduceret kraftigt. P-tærte og<br />
skumbananernes 50 års jubilæum.<br />
Side 75 af 75