business

IT-system i moderna bilar – Del 1

Anders Tufvesson 09 januari 2014

Jag kommer under dom närmaste månaderna skriva lite bloggposter om IT-system i dagens bilar. Våra bilar blir mer och mer beroende av olika typer av IT-system för att fungera och som konsument blir det betydligt svårare att förstå vad som kostar pengar och varför.

Skälet till den här lilla serien är att jag köpte en ny bil i januari 2013. Den var då begagnad av 2012 år modell. Den var alltså knappt 1 år gammal. Jag är mycket nöjd med bilen och under större delen av 2013 levde vi i symbios. Det var bara en sak som jag saknade. Min föregående bil hade ett drag och den nya hade inte det. I november gav vi upp. Vi hade under hela året saknat ett drag i många olika situationer och att låna kompisens bil, som har drag, blev till slut ohållbart. Vi beslöt oss därför att sätta på ett drag. Jag kontaktade företaget där jag köpte min bil för ett pris på ett drag, monterat och klart. Jag fick ett pris på 10.900 kronor. Mycket pengar med inte hutlöst på något sätt. Men bara för att jämföra satte jag mig ned med Google och sökte lite. Ganska snart hittade jag den här artikeln i Teknikens värld: Dragkrok på bilen – ett dyrt lyxtillval. Jag kollade upp den leverantör som är alternativet till märkesverkstaden i artikeln och det visade sig att han reser runt i Sverige och monterar drag. Det är vad han gör. Prislappen på ett monterat drag var 8.900 kronor. Dvs. 2000 kronor billigare för ett drag från Westfalia som gör det drag som jag skulle få på bilen som ”original”. Dessutom slapp jag åka iväg med bilen till verkstaden och sedan hämta den. För 8.900 kronor kommer montören hem till mig och monterar den på kvällen. Perfekt, tänkte jag och slog till.

Här slutar inte historien. För det visade sig att när draget var monterat har mitt bilmärke en lite ”feature” som gör att ESP-varningen tänds. Jag blev upplyst om att jag måste ”koda in” draget i bilen, så att bilen vet att draget finns där. Enligt personen som monterade var det en kostnad på 200-300 kronor. Det var ingen fara att köra med bilen och min leverantör som sätter på 100-tals (1.000-tals?) drag varje år sa (detta är hörsägen) att vissa märken gör så här och andra inte.

Några veckor senare bokade jag tid på märkesverkstaden för första servicen och upplyste då servicemottagaren att jag har satt på ett drag och behövde koda in det. Jag blev minst sagt förvånad när hon meddelade att det skulle kosta 1.000 kronor. Min lilla vinst på 2.000 blev hastigt och lustigt 1.000 kronor. Med det som framför allt gör mig lite fundersam är hur it-system hanteras av tillverkare i bilar. Jag har under det senaste året blivit väldigt imponerad av hur välbyggd min bil är. Till och med under bilen är det en detaljkvalitet som är enormt bra. Hur kommer det sig då att de inte kan bygga ett IT-system i bilen som inte känner av att jag sätter på ett av de vanligaste tillbehören som dessutom är det som bilföretaget har som ”original”?

Är det för att se till att märkesverkstäder eller andra verkstäder som har utrustning för det skall ha ett försprång eller finns det något annat skäl? Som en lite notering här så tar en konkurrerande verkstad här i Karlstad som inte är märkesverkstad 400-500 kronor för uppdateringen. Dom har samma kostnader för utrustningen.

Jag har därför börjat fundera lite på hur framtidens datasystem i bilar kommer påverka oss och varför det inte är Plug and Play? Jag skickade ut ett antal frågor till följande generalagenter: Audi, BMW, Ford, Kia, Mercedes, Nissan, Volvo, VW och Toyota.

Nu återstår att se om följande bloggpost blir om IT-system i bilar eller kundsupport hos generalagenter. Hittills har jag haft kontakt med tre av dem. En har redan fått en stor stjärna i kanten. Men mer om det i nästa bloggpost.

Etiketter:

09 januari 2014 |

3 Kommentarer

  1. Pingback av IT-system i moderna bilar – Del 2 | Business by web den 15 januari 2014 kl: 15:00
    IT-system i moderna bilar – Del 2 | Business by web skriver:

    […] en vecka sedan skrev jag ett inlägg om IT-system i moderna bilar. Jag avslutade med en stilla undran om nästa artikel skulle bli en fördjupning i ämnet eller […]

  2. Pingback av IT-system i moderna bilar – Del 3 | Business by web den 20 februari 2014 kl: 11:49
    IT-system i moderna bilar – Del 3 | Business by web skriver:

    […] har skrivit två tidigare delar i den här serien. Ni hittar del ett här och del två här. Det här är del tre och jag kommer skriva del fyra efter Webbdagarna i […]

  3. Pingback av IT-system i moderna bilar – Del 4 | Business by web den 21 mars 2014 kl: 10:46
    IT-system i moderna bilar – Del 4 | Business by web skriver:

    […] här är fjärde delen om IT-system i moderna bilar. De övriga blogginläggen hittar du här: Del 1. Del 2 och Del […]

Tyck till! :)

Ibland är innovation bättre än revolution

Mattias Norell 30 maj 2012

Jag fick min första dator, en Apple Macintosh IIvi, när jag var 15 år. Utan att överdriva kan jag säga att detta förändrade mitt liv. Inte så mycket för att vi nu hade en dator hemma utan för att det var just den datorn, en Apple Macintosh IIvi.

På den här tiden hade ingen av mina vänner en Appledator. De hade, citat, ”riktiga datorer”, slutcitat. Deras datorer använde MS-DOS eller, om de hade en riktig bra dator, Windows 3.1. När de sa ”riktig dator” menade de en dator som det fanns spel till, en vara som det på den tiden fanns ytterst få av till Apples datorer. De få spel som fanns krävde mycket bättre datorer än den jag hade för handen på hjärtat, Apple Macintosh IIvi var ingen snabb dator. Där emot hade den öppnat dörren till en helt ny värld för mig. Jag var inte speciellt imponerad av många av de spel mina vänner hade så att det inte gick att spela på den gjorde inte så mycket (jag hade min Playstation) utan jag började utforska hur den fungerade. Vad det egentligen var som fick en dator att starta och fungera. Detta ledde i sin tur till att jag började lära mig bygga webbsidor, gick vidare till att förstå hur databaser fungerade och slutligen lärde mig programmera både för webben och andra plattformar.

Nu för tiden går det att köpa en bra dator för några tusen. Det skulle gå att uttrycka det på ett annat sätt: dagens 15-åringar behöver i stor utsträckning inte tänka så mycket på själva datorn utan kan spela sina spel, lyssna på sin musik och sedan uppdatera sin Facebook-status om något som är världsnyheter för dem utan att bry sig om datorn klarar av det. På sätt och vis har datorernas otroliga utveckling skjutit sig själv i foten då även om mängden datoranvändare idag är fler än någonsin är det inte en lika stor del som sätter sig ner, lär sig hur och varför datorer fungerar som de gör. Något som över tid kan leda till problem för hela it-branschen.

Denna slutsats kom även en grupp engelsmän fram till. Antalet elever i brittiska skolor som gick datortekniska linjer sjönk och intresset för hur datorer fungerade hade bytts ut till ”hur får jag flest re-tweets på Twitter”. De bestämde sig för att ge brittiska skolbarn en liten knuff i rätt riktning. Raspberry Pi Foundation, och i förläningen resultatet Raspberry Pi, föddes.

Raspberry Pi är en dator i storleken av ett kreditkort.  Den är inte speciellt kraftfull eller användbar jämfört med dagens datorer utan den är byggd med en enda tanke, att den ska vara enkel att leka med och lära sig av. Prestandamässigt går den att jämföra med en dator från åren 1997-2000 men med trumfkortet att tack vare en potent grafikkrets kan spela upp film i full hd-kvalité samt rendera 3D-grafik i hög upplösning. Man skulle kunna säga att den, bortsett från grafikchipet, är en ganska medioker sak. En modern smartphone i stil med iPhone 4S eller Samsung Galaxy SII springer segervarv runt en Pi om man ser till processorkraft. Men, om man enbart ser till processor och ramminne har man missat poängen. Den här lilla datorn kan för dagens 14-15-åringar vara det min gamla Applebruk var för mig. En väg in på vad som i mitt fall visade sig vara helt rätt spår i livet. Den har det som behövs för att lära sig allt från att bygga webbsidor till avancerade 3D-spel. Har man dessutom elkunskaper kan man enkelt (nåja) bygga ut sin Pi med egen hårdvara. Den är kort och gott ett roligt sätt att lära sig hur en dator fungerar, inte genom att läsa hur man kan göra i en bok utan praktiskt lära sig genom att göra det själv. Att en Raspberry Pi endast kostar 35 dollar gör det förmodligen ännu enklare för skolor, föräldrar och dataintresserade att motivera ett köp. Det priset är dessutom för premiummodellen, det finns en budgetmodell för 25 dollar.


Raspberry Pi är en väldigt liten men väldigt trevlig sak.

Det är kanske inte svårt att förstå varför jag lyfter på hatten för personerna bakom Raspberry Pi-projektet och önskar att skolor även i Sverige beställer både en och tusen exemplar. Inte för att jag tror en Raspberry Pi omvänder alla landets skolungdomar till dataingenjörer men några kommer säkert upptäcka något de inte annars skulle gjort. Det är såklart inte den slutgiltiga lösningen på att få ungdomar intresserade av datorer men några skulle säkert ta det till sig och vilja lära sig mer. De andra som inte får samma aha-upplevelse kan säkert komma på något annat att använda den till.

Uppdatera sin Facebook-status till exempel.

Etiketter:,

30 maj 2012 |

1 kommentar

  1. En bit ur ”Ibland är innovation bättre än revolution” | blog.mattiasnorell.com skriver:

    […] Läs resterande inlägg på Business by web. « Säg hej till familjens nya medlem – del 3 […]

Tyck till! :)

Gör GDI+ till ett minne blott – använd WPF!

Anders Tufvesson 03 mars 2012

I var och vart annat projekt man sitter i (i alla fall när det gäller e-handel eller integration) så skall det skalas bilder. De skall ha bestämda storlekar, bestämda bredder, de ska beskäras och ramas in.

GDI+ ligger under System.Drawing vilket har en liten drawback, ända upp till senaste versionen av .NET (4.5) så skriver Micosoft så här på MSDN:
Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions. For a supported alternative, see Windows Imaging Components.
GDI+ ligger säkerligen på många av våra webbar och i många av våra Windows-tjänster och fungerar riktigt bra, men varför chansa i fortsättningen? Dessutom kan jag tycka att resultatet av det som GDUI+ genererar inte alltid är tillfredsställande ur en kvalité. Men det finns en lösning!

Windows Imaging Components

Det finns två sätt att arbeta med Windows Imaging Components (vidare kallat WIC). Det ena är via Windows Presentation Foundation (vidare kallat WPF) och det andra är via COM. Det senare alternativet kan vara användbart där vi har problem med trust eller vi inte vill programmera i något av de språk som tillhandahålls inom ramen för .NET. Men för den här gången kommer vi fokusera på C#.

Tanken jag har med detta lilla blogginlägg är att ge er alla lite hjälp på vägen, lite kod ni kan kopiera och utgå i från i era egna projekt. Så slipper ni skriva allt från början, vilket gör en övergång ganska mycket smidigare.

Jag har fokuserat på tre olika typer av bildomskalingar.

  • En omskalning där vi håller en av sidorna konstant och låter den andra skala efter behov. Det här är det klassiska sättet att skala om bilder.
  • Där vi använder en fixerad storlek (både höjd och bredd) på resultatet och lägger in vår omskalde bild i denna, så att den får plats.
  • Samt en tredje variant där vi, likt vår förra variant, använder en fixerad storlek på bilden men den här gången så skalar vi ner bilden så att en av sidorna exakt matchar en av resultatet sidor och sedan beskär vi bort överflödet av bilden.

Klassisk omskalning

Den klassisk omskalningen är bara ”vänligt” implemneterad, med det menar jag att den alltid kommer att skala om en bild proportionellt. Den väljer alltid den skalning som blir minst om man anger båda parametrarna, annars kan man skicka in 0 (noll) på en av dem för att vara övertygad om att skalning sker med den aktuella parametern i avseende.

private BitmapFrame ResizeImage(BitmapSource input, int width, int height) {
  double newHeightRatio = (height / (double)input.PixelHeight);
  double newWidthRatio = (width / (double)input.PixelWidth);

  if (newHeightRatio <= 0 && newWidthRatio > 0)
    newHeightRatio = newWidthRatio;
  else if (newWidthRatio <= 0 && newHeightRatio > 0)
    newWidthRatio = newHeightRatio;

  var scale = Math.Min(newWidthRatio, newHeightRatio);
  if (scale > 1)
    scale = 1;
  var target = new TransformedBitmap(input, new ScaleTransform(scale, scale));
  return BitmapFrame.Create(target);
}

WPF innehåller en så kallad BitmapSource som transformerar vår bild, denna tar emot en transformationstyp och .NET tillhandahåller några standardiserade. Dessa är

  • MatrixTransform
  • RotateTransform
  • ScaleTransform
  • SkewTransform
  • TranslateTransform

Just nu kommer jag enbart att fokusera på ScaleTransform eftersom det är den som är mest intressant för mig, men här kan vi lätt modifiera koden ovan för att exempelvis rotera eller skeva en bild istället.

Det här sättet att skala bilder med WPF är det snabbaste och ger en helt godkänd bildkvalité. Vi har inte heller någon möjlighet att direkt påverka bilddjupet, resultatbilden kommer i detta fall att ha samma upplösning (DPI) som orginalet.

Det här är ressultatet av en sådan här omskalning. Jag har talat om att bilden skall vara 200 px hög.

Det inte den här metoden ger möjlighet till är att välja vilken algoritm som skall användas för omskalningen. För att kunna ange detta måste vi använda ett annat sätt när vi skalar om bilderna, och förlorar då effektivitet. Det här är en avvägning man får göra i fall till fall, dock tycker jag att den algoritm som används av exemplet ovan ger en bra bildkvalité till en bra hastighet.

public BitmapFrame Resize(BitmapFrame input, int width, int height, BitmapScalingMode salingMode, int dpi) {
  var group = new DrawingGroup();
  RenderOptions.SetBitmapScalingMode(group, scalingMode);
  group.Children.Add(new ImageDrawing(photo, new Rect(0, 0, width, height)));
  var targetVisual = new DrawingVisual();
  var targetContext = targetVisual.RenderOpen();
  targetContext.DrawDrawing(group);
  var target = new RenderTargetBitmap(width, height, dpi, dpi, PixelFormats.Default);
  targetContext.Close();
  target.Render(targetVisual);
  var targetFrame = BitmapFrame.Create(target);
  return targetFrame;
}

I exemplet ovan kan man se hur vi kan välja både skalningsmetod och djup i bilden som vi producerar. Vi använder en helt annan metodik för att skala bilderna vilken tar mer kraft från systemet.

Skala en bild och placera den i en ram

Om man alltid vill ha en fast storlek på bilderna, tillexempel till en produklista där det skulle se otroligt dumt ut om bilderna var i olika bredder eller höjder, kan man välja att lägga dem i en ”omgivande ram”. Lösningen är vanlig och gör det mycket enklare att designa webbplatser.

public BitmapFrame ResizeAndFit(BitmapSource input, int width, int height) {
  if (input.PixelWidth == width && input.PixelHeight == height)
    return BitmapFrame.Create(input);

  if (input.Format != PixelFormats.Bgra32 || input.Format != PixelFormats.Pbgra32)
  input = new FormatConvertedBitmap(input, PixelFormats.Bgra32, null, 0);

  var scale = Math.Min((double)width / input.PixelWidth, height / (double)input.PixelHeight);
  if (scale > 1)
    scale = 1;

  var x = (int)Math.Round((width - (input.PixelWidth * scale)) / 2);
  var y = (int)Math.Round((height - (input.PixelHeight * scale)) / 2);
  var scaled = new TransformedBitmap(input, new ScaleTransform(scale, scale));
  var stride = scaled.PixelWidth * (scaled.Format.BitsPerPixel / 8);
  var result = new WriteableBitmap(width, height, scaled.DpiX, scaled.DpiY, scaled.Format, null);
  var colorFrame = GetColorBitmap(width, height, Brushes.White);
  var colorFrameStride = colorFrame.PixelWidth * (colorFrame.Format.BitsPerPixel / 8);
  var colorFrameData = new byte[colorFrame.PixelHeight * colorFrameStride];
  var data = new byte[scaled.PixelHeight * stride];

  colorFrame.CopyPixels(colorFrameData, colorFrameStride, 0);
  scaled.CopyPixels(data, stride, 0);

  result.WritePixels(new Int32Rect(0, 0, width, height), colorFrameData, colorFrameStride, 0, 0);
  result.WritePixels(new Int32Rect(0, 0, scaled.PixelWidth, scaled.PixelHeight), data, stride, x, y);

  return BitmapFrame.Create(result);
}

private BitmapSource GetColorBitmap(int width, int height, Brush color) {
  var renderBitmap = new RenderTargetBitmap(size.Width, size.Height, 96, 96, PixelFormats.Pbgra32);
  var drawingVisual = new DrawingVisual();
  using (var context = drawingVisual.RenderOpen()) {
    context.DrawRectangle(color, null, new Rect(0, 0, size.Width, size.Height));
  }
  renderBitmap.Render(drawingVisual);
  return renderBitmap;
}

Den här typen av omskalning blir lite mer avancerad. Här måste vi nämligen rita ut vår omskalde bild i en ytterligare bild. Först så ser vi till att båda våra bildformat är på samma format, om vår inkommande bild inte är 32bitars RGB (Bgra32) så omvandlar vi källan till detta, exempel på andra format kan vara 16bitars RGB eller CMYK.

Efter detta skalar vi ner bilden så att den får plats i vår ram. Det vi gör är att vi räknar ut proportionell skalning i både X- och Y-led för att sedan välja den som är minst. Det kommer vara den skalfaktor vi använder för att se till att bilden får plats i vår destinationsstorlek.

Som standard är vår nya skrivbara bitmap transparent, detta fungerar mycket bra för PNG och kanske till och med är önskvärt. Det vi i så fall gör är att vi raderar våran colorFrame från koden ovan och låter inte denna skrivas till bilden. När vi skalar foton är det i de flesta fall önskvärt att spara bilderna som JPEG eftersom det tar minst plats. JPEG stödjer inte transparens och därför måste vi måla vår bakgrund i en önskad färg.

Vi kopierar sedan över vår bakgrund och därefter vår bild till vår destination och returnerar denna. Omskalningen är klar!

Det här är resultatet. Jag har talat om att jag vill ha en bild som är 500 px bred och 200 px hög, och med blå bakgrund.

Skala en bild och beskär det som inte får plats

Om du vill ha en fast bildstorlek men inte vill ha en ”ful” färgad ram kring din bild så kan det vara nog så bra att beskära bort en del av bilden. Om dina orginalbilder ligger väldigt nära dina omskalade bilder i proportioner så är detta ett utmärkt alternativ, på bilderna som jag använder blir resultatet dessvärre mycket sämre. s

public BitmapFrame ResizeAndCrop(BitmapSource input, int width, int height) {
  if (input.PixelWidth == width && input.PixelHeight == height)
    return BitmapFrame.Create(input);

  var useScaleH = (width / (double)input.PixelWidth) * input.PixelHeight;
  var newSizeH = 0;
  var newSizeW = width;
  if (useScaleH < height) {
    var newSizeH = height;
    var newSizeW = 0;
  }

  var scaled = ResizeImage(input, newSizeW, newSizeH);
  var x = ((scaled.PixelWidth - width) / 2);
  var y = ((scaled.PixelHeight -height) / 2);
  var stride = scaled.PixelWidth * (scaled.Format.BitsPerPixel / 8);
  var result = new WriteableBitmap(width, height, scaled.DpiX, scaled.DpiY, scaled.Format, null);
  var data = new byte[scaled.PixelHeight * stride];
  var copyWidth = scaled.PixelWidth - (scaled.PixelWidth - width);
  var copyHeight = scaled.PixelHeight - (scaled.PixelHeight - height);
  if (x < 0) {
    x = 0;
    copyWidth = scaled.PixelWidth;
  }
  if (y < 0) {
    y = 0;
    copyHeight=scaled.PixelHeight
  }

  scaled.CopyPixels(data, stride, 0);
  result.WritePixels(new Int32Rect(x, y, copyWidth, copyHeight), data, stride, 0, 0);

  return BitmapFrame.Create(result);
}

Det här ser mer avancerat ut än vad det är. Vi måste först räkna ut vilken sida som, när vi skalat ner bilden, kommer att vara lika stor som den nya bilden medan den andra sidan är större. När vi gjort det kan vi skala ner bilden proportionellt.

Vi skapar därefter en destinationsbild som är exakt så stor som vi vill ha den. Eftersom vår nedskalade bild är större än denna måste vi räkna ut en ram som skall användas för att beskära bilden. Det gör vi genom att räkna ut hur mycket som ”hänger över” i bredd- och höjdled. Vi centrerar bilden genom att dela dessa värden i hälften och koperar nu över de pixlar som ligger inom ramen till vår destinationsbild.

Viktigt att notera här är att om orginalbilden är mindre än destinationsbilden så kommer vi bara kopiera över bilden till det övre vänstra hörnet. Det är för att vi inte vill sträcka ut bilden och förstöra den. Det bästa är inte använda denna metod vid sådana bilder, utan i stället lösa det problemet på annat sätt, exempelvis genom att lägga en ram kring den.


Det här är resultatet. Jag har talat om att bilden skall vara 500 px bred och 200 px hög. Min orginalbild är stående och denna liggande, därför förlorar vi mycket av bilden. Två bildformat som ligger nära varandra i proportioner resulterar

Avkoda och koda bilder från disk/ström.

För att allt det här ska fungera behöver du också några småsaker, exempelvis en bild-decoder och en bild encoder. Självklart finn detta inbyggt och är inte direkt rocket-sience. Här kommer lite exempel:

Stream orginalImage = null; //Load stream from image-file or like.
var orginalImageDecoder = BitmapDecoder.Create(
                                    orginalImage,
                                    BitmapCreateOptions.PreservePixelFormat,
                                    BitmapCacheOption.None);
BitmapSource source = orginalImageDecoder.Frames[0];

När du skall spara dina omskalade bilder kan du göra det i sex format som Microsoft tillhandahåller. Dessa är

  • BmpBitmapEncoder
  • GifBitmapEncoder
  • JpegBitmapEncoder
  • PngBitmapEncoder
  • TiffBitmapEncoder
  • WmpBitmapEncoder

alla dessa format används på samma sätt som nedan. JpegBitmapEncoder har dessutom möjlighet att sätta kvalité för kompressionen.

Stream resizedImage = null; //Init a writable stream for the destination
BitmapFrame resizedImageFrame = null; //Frame from one of the resize algorithms above.
var targetEncoder = new JpegBitmapEncoder(){
    QualityLevel = 85;
};
targetEncoder.Frames.Add(resizedImageFrame);
targetEncoder.Save(resizedImage);

Jag hoppas att det här har väckt dina tankar lite kring att kanske använda WPF för att göra din bildmanipulering i framtiden.

Etiketter:, , , , , , , , , , , , , , ,

03 mars 2012 |

3 Kommentarer

  1. Kommentar av Bobbi den 31 mars 2017 kl: 3:01
    Bobbi skriver:

    You’re a real deep thnekir. Thanks for sharing.

  2. Kommentar av Adiana den 31 mars 2017 kl: 3:15
    Adiana skriver:

    That’s a smart answer to a diuffcilt question.

  3. Kommentar av Santa Clara insuranse den 16 maj 2017 kl: 11:20
    Santa Clara insuranse skriver:

    Hey. Very cool blog!! Man .. Excellent .. Amazing .. I’ll bookmark your website and take the feeds additionally…I’m happy to locate a lot of useful information right here within the post. Thanks for sharing..

Tyck till! :)

Designa för Windows

Anders Tufvesson 01 december 2011

Något jag väldigt sällan stöter på i min yrkesroll just nu är att göra desktop-applikationer för Windows. Under alla mina studieår på universitetet hade jag inte en enda gång möjlighet att läsa någon kurs i människa datorinteraktion och i gränssnittsdesign. Jag är enormt intresserad av dessa ämnen och väldigt iver att lära mig mer.

I förra veckan fick jag ett litet miniuppdrag att skapa en enkel desktop-applikation till en av våra kunder inom finanssektorn. Idén är superenkel. Man matar in två värden, man väljer ett filnamn och man hämtar hem en fil från nätverket. Användarna av den här applikationen är personer med varierande datorkunskaper men med en sådan här enkel applikation kan man inte göra fel, eller?

Jag tänkte dela med mig lite av några do’s and don’ts när det gäller gränssnittsdesign av desktop-applikationer. Kanske kan det inspirera er att se på gränssnitten på ett annat sätt och även kanske bygga gränssnitt annorlunda. Först och främst vill jag göra det klart att det jag skriver här inte passar i alla sammanhang – det finns alltid undantag. Dessutom är jag väldigt allergisk mot att lägga in saker i en applikation ”för att det går”.

Om man designar en applikation för ett specifikt operativsystem (exemeplvis Windows®, MacOS® eller en specifik fönsterhanterare till Linux) så ska man följa de guidelines som är uppsatta för detsamma. Genom att göra gränssnittet harmoniserat med övriga element i systemet blir ovana användare tryggare och dessutom erhålls en känsla av att applikationen hänger ihop med systemet. Vilket är väldigt viktig användarupplevelse enligt mig.

Läsordning

Det finns många studier på hur användare tittar på en ny skärm de inte sett förut. En kunskap om detta underlättar oerhört när man gör ett nytt gränssnitt. Bilden nedan visar hur användaren tittar från vänster till höger och uppifrån och ner. I länder med annan läsordning än vänster till höger kan detta variera.

Bild: Microsoft Corporation

På grund av att den vanlige användaren tittar så här ska vi också fylla på med information från vänster till höger. Den viktigaste informationen till vänster och mindre viktig information till höger. Jobbar vi med formulär ska dessa fyllas i från vänster till höger i första hand och i andra hand uppifrån och ner.

Jag ska visa en bild som jag tycker är så givande. Jag har lånat den från Microsoft Guidelines för gränssnittsdesign. På bilden ser vi ett gränssnitt där ordningen man ska utföra uppgifterna är väldigt i oordning. Det är jobbigt för en användare att arbeta i det här formuläret eftersom man först och främst inte direkt ser i vilken ordning det krävs att man gör saker men också för att det tar onödigt med tid att hoppa mellan de olika fälten.

Bild: Microsoft Corporation

Om vi ordnar om fälten i det här formuläret enligt läsordningen ovan så blir det som bilden nedan. Direkt ser man i vilken ordning man förväntas fylla i formuläret. Det här är ganska enkelt och tänka på och man behöver inte ha några layout-kunskaper eller någon känsla för layout för att lyckas. Det är bara rena regler! Det gillar jag!

Bild: Microsoft Corporation

Ordningen vänster till häger gäller också när man bygger verktygsfält. Fyll på med de mest använda ikonerna till vänster och fortsätt sedan åt höger med fallande signifikans och användning. Tänk också på att skärmbredden (i pixlar) varierar för varje användare vilket gör att för vissa användare kan knappar i höger-kanten döljas när fönstret blir mindre. Detta bör man lösa genom att låta de knappar som döljs kunna visas i en nedfällbar meny, det är oftast inte rekommenderat att skapa en ytterligare rad eftersom detta bryter tanken om att de mest använda verktygen skall ligga till vänster.

Bild: Apple Inc.

Alignering (aligning)

En viktig sak när man arbetar med gränssnittsdesign är att hålla designen så alignerad  som möjligt. Detta hjälper ögat att sålla och sortera i informationen. Tittar du på bilden kanske du instiktivt känner att det är svårt att hitta informationen i fönstret. Ju fler kolumner (grids) vi lägger till desto mer avancerat blir gränssnittet.

Bild: Microsoft Corporation

I nästa bild reduceras antalet kolumner till 4 i stället för 9. Gränssnittet känns ”luftigare” och det är lättare för ögat att hitta informationen vi är ute efter. ”Less is more” skulle man kunna säga här. Det här är också en enkel regel man alltid kan applicera, och gäller även på webben faktiskt.

Bild: Microsoft Corporation

Menyer och menyval

Något annat som är ganska enkelt att arbeta med är segment i menyer. Här finns ingen direkt regel, men kommandon som logiskt hör i hop grupperas ihop. Exempel: Nytt, Spara, Öppna, Stäng hör ihop, och Klipp ut, Kopiera, Klistra in hör ihop. Genom att segmentera menyn så blir det flera fall enklare att snabbt hitta det man söker.

Bild: Apple Inc.

Det är högt rekommenderat att arbeta med kortkommandon. Bilden ovan visar en menyer på MacOS® men principen är den samma även i Windows®. Det vi bör tänka på när vi tilldelar kortkomandon är att man gör det enligt ”gängse standard”. Det finns en visst antal kortkommandon som användare vanligen vill utför samma operationer i olika program. Detta är exempelvis; kopiera (CTRL+C), Spara (CTRL+S), Avsluta (ALT+F4), Öppna (CTRL+O). Om ditt program exempelvis använder CTRL+S för att stänga programmet utan att spara pågående arbete blir användaren ganska förvånad (och kanske irriterad) när han använder det kommandot och förväntar sig att det skall spara hans arbete. Dock är detta en helt annan historia, som ni kan läsa mer om på Microsofts webbplats!

Inaktivera otillgänliga val

En viktig detalj i ett gränssnitt är att enbart visualisera de verktyg som fungerar att använda. Ett formulär kan ha många kontroller som kanske kan användas vid ett visst givet tillfälle.

Det enklaste, och kanske bästa sättet, att göra detta är att inaktivera de kontroller som inte är tillgängliga. Det gör att användare inte försöker använda dem eller lägger energi på att fylla i dem.

Nästling

Jobba gärna med att nästla element som hör i hop, exempelvis genom att lägga alla kontroller för att söka i en gruppering vid namn ”Sök”. Det gör det lättare för användaren att hitta vad han eller hon söker. Det är också bra att indentera element som är underelement till en annan kontroll, som enbart är tillgängliga när ett överordnat element är aktiverat.

Bild: Microsoft Corporation

Det man dock aldrig ska göra är att nästla simpla element. Med det menar jag att man exempelvis aldrig ska lägga ett textinmatningsfält i beskrivningstexten till en kryssruta. Personer med nedsatt syn och som använder skärmläsningshjälpmedel kan ha svårt att uppfatta sådana konstruktioner.

Bild: Microsoft Corporation

Försök i stället att omformulera meningen så att du kan lägga textinmatningen sist eller på en ny rad.

Spacing

Vi har ofta problem med språkanpassning (localization). Ord och meningar har olika längd på olika språk och ibland får vi inte plats med etiketten innan själva datan börjar.

Ett enkelt knep för att komma förbi detta är att ta för vana att alltid lägga den beskrivande etiketten ovanför dataetiketten. Då har vår beskrivning möjlighet att växa sig mycket större innan den inkräktar på något.  Det finns också studier (enligt ”Jävlaskitsystem”) som visar på att det är lättare för ögat att hitta den information man söker när etiketterna är ordnade på detta sätt.

Bild: Microsoft Corporation

Till slut kan jag tipsa om att alltid använda de spacing-guidlines som Microsoft Visual Studio® föreslår när du placerar ut kontroller. Det hjälper dig till att bli en bättre UI-designer för Windows. Dessutom är den så smart att den hjälper dig att hålla dina aligneringar. Så om bara du gör alla knappar och inmatningsfält som hör till samma gruppering lika stora så kommer Visual Studio ® hjälpa dig med resten!

Mer?

Är du nyfiken på mer? Då kanske du kan läsa några av de här:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa511275.aspx
http://developer.apple.com/library/mac/#documentation/UserExperience/Conceptual/AppleHIGuidelines/Windows/Windows.html

http://javlaskitsystem.se/

Jag har lånat de flesta bilder från Microsoft Corporation och några från Apple Inc. för denna artikel. Om det är så att Microsoft eller Apple anser att jag använt deras material olovligt kommer jag omedelbart att ta ned dem. Jag drog mig för att göra egna bilder eftersom jag tycker bilderna är så talande och bra gjorda.

Etiketter:, , , , ,

01 december 2011 |

1 kommentar

  1. Kommentar av Carita G den 02 juni 2016 kl: 8:54
    Carita G skriver:

    Tack för denna artikel, väldigt bra infomation om hur man skapar en desktop applikation

Tyck till! :)

Driftsäkerhet, tester och fel

Anders Tufvesson 16 november 2011

Hur skriver man kod som anses var driftsäker och vad är det – Är det kod med väldigt lite fel? Kod som inte behöver underhållas så ofta?

Jag reflekterar ofta om den tid som finns att lägga ner på ett kodstycke. Ofta är det så att beställarna vill ha jobbet utfört till så liten kostnad som möjligt (vilket jag förstår) och då blir det minimalt med tid på varje sak. Men ”vad kostar detta i längden?” brukar jag tänka då.

Som utvecklare har man alltid en viss tid till tester, det är så oerhört viktigt att testa det man skapat så att det uppför sig som förväntat. Man testar ofta normalfallen och några yttre fall som man kan tänka sig inträffar. Det brukar räcka väldigt långt. Men som alltid finns det massor av undantagsfall som man kanske inte räknat med och var ska man dra gränsen? Allt beror, tycker jag, på ändamålet och hur viktigt det är för kunden att systemet i alla skeden går smärtfritt.

Det är oerhört vanligt att vi skriver så kallade enhetstester till våra metoder, vilket testar att våra metoder beter sig som vi förväntar sig vid de vanligaste indatafallen. När det kommer till integrationstester så blir vi ofta mer frikostiga hur vi utför dem, här burkar det nämligen gå åt en del tid eftersom integrationstesterna är svåra att utföra. Något många beställare inte är beredda att lägga allt för mycket tid på.

När det däremot gäller acceptanstester så är beställare ofta mer benägna att lägga tid. Acceptanstestet är deras kvitto på att de fått vad de beställt men den här typen av tester testar i stort sett aldrig ytterligheterna.

Vi bygger sällan, om ens aldrig, system som är ämnade för att skydda eller rädda liv. Det gör att man kan fokusera mycket mer på att komma framåt i utvecklingen än att kontrollera för fel, vilket är viktigt i många av de branscher vi arbetar med (framförallt webb). Det här ses ofta positivt på från ett beställarhåll eftersom man erhåller något nytt hela tiden. Men å andra sidan här vill beställarna ha en hög tillgänglighet, applikationen skall vara driftsäker.

Men tillbaka till ursprungsfrågan; hur skriver vi kod som är driftsäker?
Hur konstigt det än kan låta tycker jag att det här är ett delat ansvar. Framförallt skall vi förklara varför vi vill lägga tid på de olika typerna av tester, vi är experterna, men å andra sidan måste beställare av applikationer vara medvetna om att tester får ta tid. Hur mycket vi skall testa och vad vi ska testa måste tas fram i perspektiv till verksamheten.

Det finns flera sätt att få något väldigt driftsäkert, och det vanligaste måste vara att man är många som delar på ansvaret att kontrollera att en viss del av kod utför det den skall. Och att utföra många och långa tester för att se till att den uppför sig som man förväntar sig i alla möjliga situationer.

Som jag skrivit i ett tidigare inlägg måste det finnas utrymme i en budget för underhåll av applikationer. Det gäller både webb- och desktopapplikationer. Omgivningen förändras något så oerhört, framförallt på webben där det kommer nya webbläsare och nya krav från beställaren varje dag. Men även desktopapplikationer behöver underhållas för att passa nya operativsystem och nya krav. Lägger man inte ner tid på att anpassa och underhålla applikationerna under tid kommer man tillslut till en punkt där det blir ett allt för stort jobb att göra.

Statens Järnvägar lanserade 1980, efter tio års utveckling och tester, ett system förhindra olyckor i tågtrafiken. Systemet hette, och heter fortfarande, ATC. Här fanns (och finns) det ingen tolerans för fel eller situationer som man inte räknat med. Sedan 1980 har det kommit tre versionuppdateringar av ATC men det det tog 13 år innan en första versionsuppdatering kom (1993 släpptes ATC2).

Hur kommer det sig då att ett sådant system klarar sig från större underhåll av koden?
Jag tror, utan att vara någon expert, att det handlar om två saker. Först och främst är det en väldigt statisk och sluten miljö men också att man har lagt ner otal timmar på testning av alla möjliga fall. Att man la ner tio år av utveckling och tester innan man införde det i stor skala på alla tåg är nog en av framgångssagorna. Efter 30 år med systemet är det så inkört att förarna nuförtiden helt förlitar sig på systemet, man kör som det heter på ”pipet” och litar fullt ut på att ATC-systemet varnar vid för höga hastigheter, röd signal eller systemfel. Hör man inget ”pip” är det bara att gasa på!

Men för oss som inte har ett slutet system eller kan lägga tid på tester?
Vi kanske får acceptera att vi kommer att ha fel i våra applikationer till en viss gräns och att vi måste vara beredda på att kontinuerligt lägga tid på att rätta de fel som uppkommer. När det kommer till driftsäkerheten finns det inga genvägar, och jag vet att man ibland brukar lösa prestandaproblem på webbplatser genom att låta dem starta om allt som ofta. En fräsch start löser ofta mycket konstiga tillstånd i ett system men är ingen bra utväg. I dessa fall kanske man ska fundera på om det inte är värt att lägga tid på att hitta felen och rätta dem.

Utvecklare: varför skriver ni fel över huvud taget?
Den frågan får jag ibland och den är alltid lika intressant att svara på. Det finns ingen, eller i alla fall nästan ingen, utvecklade som medvetet skriver kod som man vet är fel. Däremot finns det alltid massa undantag på in och utdata som kan ställa till det. Det värsta en utvecklare kan handskas med är indata från okända källor (som användare), för man vet aldrig hur den ser ut. Utöver detta har vi fall där data har blivit korrupt eller andra hjälpfunktioner man använder sig av får problem med att köra. Kanske är det slut på RAM-minne, slut på diskutrymme, fullt på stacken, för långsam nätverksanslutning, kommunikationsproblem med I/O, ja allt detta kan hända men kanske inte är något man kontrollerar när man ska addera två tal. Jag vet att jag överdriver lite granna nu, men i realiteten skulle vi behöva kontrollera så otal många fall för att verifiera att allt fungerar som det skall om vi ska täcka alla möjliga fel som uppkommer. Varje fall måste dessutom hanteras på olika sätt, sådant tar tid!

I bland händer det förvisso att vi skriver fel också, men det är sällan med flit. I avancerade applikationer finns det alltid möjlighet till tankevurpor.

Så slutligen så kan jag konstatera att vi skulle behöva lägga mycket tid på tester om vi vill få allt problemfritt från början, men att vi åtminstone lägger tillräckligt med tid för att hitta de värsta felen och sedan löser resten när de inträffar.

Kuriosa:
För den intresserade finns ATC i version 1, 2, 2.1 samt 2.2. De stora skillnaderna är mellan ATC1 och ATC2 där är frikostigare med att lossa en automatisk driftsbroms som ATC har slagit till vid för hög hastighet/närmande av stoppsignal om den märker att föraren försöker bromsa själv. Dessutom ändrades vad som bänder om flera hastighetangivelser tas emot, tidigare använde ATC den lägsta medan i den nya versionen den som senast togs emot. De två senaste uppdateringarna 2.1 och 2.2 syftar enbart till att lösa specifika problem. 2.1 möjliggör för systemet att ta emot körbesked via radio som ett komplement till balisier på marken. Det gör att man kan ge nya körbesked (ex. höjd hastighet) om en ex. signal längre fram slår om från rött till grönt. På så sätt  kan man häva ett besked om hastighetsnedsättning innan man når nästa signalen vilket resulterar i att tåg kan köras snabbare och mer effektivt. Version 2.2 löser problem för tåg som åker över Öresunsbron och in i Danmark där man har en annan typ av ATC. Omkopplingen mellan systemen måste ske automatiskt, vid exakt rätt tillfälle, i 200km/h.

Källor:
http://techworld.idg.se/2.2524/1.160472/med-atc-systemet-gar-taget-som-pa-rals

Etiketter:, , , , ,

16 november 2011 |

3 Kommentarer

  1. Kommentar av Andreas Eriksson den 16 november 2011 kl: 19:35
    Andreas Eriksson skriver:

    Mycket bra skrivet och en hel del sanning.

  2. Kommentar av Rikard Elofsson den 17 november 2011 kl: 8:59
    Rikard Elofsson skriver:

    Kan gissa att du gärna läser Jörgen Städjes alster, han gillar också att grotta ner sig i ATC-systemet… :)

  3. Kommentar av Henrik Bäck den 17 november 2011 kl: 9:13
    Henrik Bäck skriver:

    Ja, han skriver mycket bra om diverse system. Läste om kärnkraftverket i Oskarshamn tidigare, mycket intressant.

Tyck till! :)

Krångel med HOSTS i Mac OS 10.7.2

Anders Tufvesson 25 oktober 2011

Det är flera med mig som upplevt problem med HOSTS-filen i senaste uppdateringen av Mac OS X. Av någon anledning tar det lång tid för den att lösa upp namn ur densamma och vissa namn kan den inte lösa upp alls.

I min frustration har jag upptäckt några saker som kan vara fler till hjälp, därför delar jag med mig av det här:

  • Maximalt 11 hostnamn per rad
    Det verkar finnas en begränsning som gör att om du lägger till fler än 11 hostnamn på samma rad för en IP-adress så spårar något ur och det blir enormt långsamt.
  • Låt ”fe80::1%lo0 localhost” ligga sist.
    Av någon anledning fungerar min HOSTS-fil mycket bättre när denna rad ligger sist i filen.
  • Om din dator sitter på ett IPV6-interface och du vill ha adresser till loopback-interfacet, lägg till två rader. En med 127.0.0.1 och en med ::1.

I övrigt så får inte heller /private/etc/hosts vara en symlink till en annan fil.

Om detta inte löser problemen ska man fundera över att kanske göra en ren installation av operativsystemet eller sätta upp dnsmasq lokalt.

25 oktober 2011 |

0 Kommentar

   Inga kommentarer än... Bli den första!

Tyck till! :)