Arkiv för ‘Produktivitet’ Kategorin

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

lördag, mars 3rd, 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.

Designa för Windows

torsdag, december 1st, 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.

Driftsäkerhet, tester och fel

onsdag, november 16th, 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

Underhåll och förvaltning

onsdag, oktober 12th, 2011

SJ X2000-konceptetJag sitter ombord på tåget på väg till en av våra trogna kunder. Tåget jag åker är ett X2-sätt byggt någon gång i början av 90-talet. En tid innan Internet, en tid med stordatorer, en tid då du troligt satt hemma med ditt CLI-baserade användargränssnitt och gjorde otroliga saker i Basic.

Byggt av ABB är det ett stycke svensk ingenjörskonst i sitt esse. Tåget var otroligt tekniskt avancerat när det lanserades. Tåget är fullproppat med datorer (vilket inte var vanligt tidigare) för varje minsta lilla sak och alla dessa datorer är sammankopplade i ett avancerat nätverk. Datorerna sköter styrningar för korglutning, dörrstängning, motorer, skyltar och mycket mer. Det gäller att de verkligen fungerar som de ska!

Det hela får mig att tänka på kvalité och underhåll. Med ett tågsätt som är över 20 år, är det fortfarande ett av de mest kvalitativa i Sverige. Visst har det varit problem med X2-sätten under åren, men det skulle jag villa säga beror på dåligt underhåll. Tågen är byggda i Sverige, för de svenska järnvägarna och för det svenska klimatet.

Det samma gäller när vi programmerar på ett sätt. Vi skriver ett stycke kod som är helt anpassat till den verksamhet och de förhållanden som råder för tillfället. Koden vi gör har förvisso inget slitage men omgivningen runt vår kod förändras fort. Det gör att vi inte enbart kan fokusera framåt, utan måste underhålla det vi en gång skapat.

Om vi lyckas underhålla våra kreationer och lyckas få vår omgivning att förstå att sådant som en gång är skapat också måste ses över kan våra kreationer leva i många år och även senare ”gå som tåget”.  Vi behöver kanske inte alltid bygga nytt, men vi måste förstå att det får kosta pengar att underhålla och ”uppgradera” vår kod till nyare stadier. Gör vi inte det är vi ute på hal is och står där mitt i ödemarken med något som inte fungerar.

Foto Alexander Fäldt.

Reflektioner från dag 2 – iStrategy i Amsterdam

torsdag, maj 12th, 2011

Dag 2 levererade på en helt annan nivå än dag 1. Gillian Muessig från SEOmoz avslutade med ett briljant föredrag om SEO och hur sökmotoroptimering har blivit svårare och ännu mer viktigt. Tyvärr lägger företag inte den mediepeng som behövs. Hört den förut? Men gamal tekniker som att skriva text på rätt ställe och jobba med länkar på traditionellt sätt håller inte längre. Vi måste börja jobba med sociala länker och när jag säger vi så här det äkta länkar med exempelvis twittrare med hög trovärdighet som skriver dem. Så sök har gått från något till alla egentligen kunde göra till något väldigt komplext där tonalitet och en genomtänkt webbcopy är ett krav. Det kliar i mina fingrar på att få sätta igång!

En annan bra föreläsare var Paul Duay. Han började med orden: ”De som sägar att sociala medier inte handlar om ROI har helt fel”. För enligt Paul så har sociala medier absolut med ROI att göra. Men inte i form att släppa iväg säljerbjudande på en Facebook-sida utan att hitta de vägar då ni sparar och genererar pengar till ert företag genom att hjälpa och stödja er målgrupp. Sedan finns det undantag. Dell har ett twitter flöde där de säljer lätt begagnade datorer som del kallar Dell Outlet. Det är bara försäljning och det flödet följs av nästan 1,6 miljoner. Enligt Paul så kan Twitter och Facebook minska sälj- och eftersälj-support samt öka återköpsfrekvensen. Det mest spännande är att Paul jobbar uteslutande med B2B. Vem sa att sociala medier inte funkar i B2B-företag.

En annan föreläsning handlade om Mobil marknadsföringsstrategi. Talare var Paul Berney från MMA. Det första han sa var: En iPhone-app är INTE en mobil marknadsföringsstrategi. Det är mycket mer. Det är att som vanligt att känna sin målgrupp och ge dem det de vill ha. Enkelt va? Han gav ett bra exempel från Sydafrika. En hel del har smartphones men många har fortfarande vanlige enkla mobiltelefoner. De flest med kontantkort som ofta tar slut. Vodaphone provade därför ett koncept som heter de kallade ”Please call me”. Dvs. när ditt kontantkort var slut kunde de skicka ett sms till någon via Vodaphone där det stod ”Please call me” och telefonnumret. En tjänst som används väldigt mycket. Naturligtvis går det att köpa reklamplats här för ett sms är 160 tecken och det finns gott om plats. Exempelvis ”Köp en hamburgare och få en gratis genom att smsa XXXXX”. Mer exempel på smarta lösningar finns här. Men en sak ringer i öronen från den föreläsningen. Du kan få billigt och snabbt ELLER kvalitet. Det är svårt, om inte omöjligt att kombinera.

Till slut vill jag ta upp Foresquare och en av deras grundare Naveen Selvadurai. En tjänst som påminner om Facebook Places men var ute för två år sedan. Foresquare har inte slagit här i Sverige men i USA är det stort. Tanken var att användare skulle checka in på olika ställen och den informationen sedan skall kunna användas av andra för att utforska städer. Vilka trender finns? Var är de heta ställena i stan? Vilka erbjudande finns från olika ställen. Han gav exempel på när en person skulle till GAP i New York, men gick till HM istället för de hade ett erbjudande via Foresquare. Företag kan registrera sig och när de har gjort det så får de via post Foresquare-klisteretiketter att sätta på rutan. Ett kreativt sätt att använda Foresquare är en tillverkare av djurmat som finns på Youtube. Nu kommer en härlig: Klicka här! Det här ger direkt koppling mellan mobiltelefon och verkligheten. Smart!

Jag ger konferensen 4 av 5. De når inte riktigt ända fram då en del föreläsningar var mer av en säljpitch och att konferensanläggningen i Amsterdam inte riktigt höll svensk standard.

De små detaljera på en webbplats irriterar

onsdag, januari 12th, 2011

De flesta större organisationer har idag har övergripande kontroll på sin webbplats. Struktur, design och de stora penseldragen finns där. Idag är det ofta de små detaljerna som vi som användare av en webbplats irriterar oss på. Ofta är det i olika processer som vid köp, bokning och registrering det blir fel.

För några dagar sedan hjälpte jag min Mamma och Pappa att köpa en TV. Det blev en Philips. Philips har, som många tillverkare idag, en registreringsprocess på sin webbplats. Men det går inte bara att registrera en produkt, jag måste skapa ett personlig konto först. Jag satte igång och när jag var färdig med formuläret så fanns det ett kryss där jag kunde kryssa i om jag ville ha nyheter, programuppdateringar och kampanjer från Philips. Ett kryss för alla. Nu var det frågan om en TV så programuppdateringar är inte intressant. Nyheter och kampanjer, nej tack. Jag kryssade inte och klickade bara på ”Skapa konto”. Då dyker följande sida upp:

Ja, jag är väldigt säker och lite irriterad för att jag måste godkänna det igen precis som det är frågan om att godkänna ett avtal. Jag svarade nej och då kommer jag tillbaka till formuläret med följande varning:

Jag har skrivit in ett lösenord på 14 tecken som är för långt. Jag provade igen och kom tillbaka igen. Den här gången var det 11 tecken. Kollade upp hur många tecken som ett lösenord skall vara och det visare sig att Philips tycker att optimala lösenord ser ut så här:

6 till 10 tecken! Om jag vill ha ”skunk” som lösenord är det upp till mig. Inte bra säkerhet men som sagt, det är upp till mig. Vill jag vara säker så kanske en rimlig begränsning är 50 tecken? Disk kostar inte mycket idag, varför bara 10 tecken? En annan fråga är att om ni vete hu många tecken jag kan fylla i, varför inte tala om det när ni varnar mig? ”Du har skrivit ett lösenord som innehåller mer än 10 tecken” vore mer  rimligt felmeddelande. När jag fyllt i ett, enligt Philips, lämpligt lösenord svarade de med: ”Ditt konto har skapats utan problem”. Jag och Philips är inte överens i det fallet.

Det är de små detaljerna du kommer bli bedömd på. Att testa webbar och användningen av webbar kommer bli viktigare framöver när alla konkurrenter inom en bransch har bra webbar. I Philips fall har de en kund som troligen är nöjd med sitt köp men på webbplatsen tappar varumärket i värde.

När kineserna börjar ifrågasätta ligger vi risigt till!

måndag, december 20th, 2010

1 300 000 000 stycken kineser ligger i startgroparna att ta våra jobb. Jag vet att de antagligen är ca 20-30 miljoner fler men låt oss säga ca 1,3 miljarder kineser. Fast egentligen är det ”bara” ½ miljard av dem som har det bra ekonomiskt som kan utmana oss. Fast det är ungefär lika många ekonomiskt välbärgade kineser som antalet invånare i EU. Många personer är ute och föreläser om hotet från öst i form av Indien och Kina. Men än så länge finns det en sak som gör att vi klarar oss. Kineserna har inte börjat ifrågasätta. Jag höll för några veckor sedan två föreläsningar i webbstrategi på Karlstads Universitet. Det var 20 stycken kineser och 10 stycken svenska som gick kursen ”Business by web”. Vilket sammanträffande.

Kineserna lyssnade och antecknade men ställde inte några frågor i klassrummet. De svenska studenterna ifrågasatte och försökte utmana mig i det som jag pratade om. Kineserna kom fram på raster och frågade en och en, men det var för att få ett förtydligande. Inte en sekund ifrågasatte de något jag sagt utan det var en sanning för dem. En svensk student lär sig ifrågasätta och tänka annorlunda. En kinesisk lär sig det som läraren säger (kopiera). Så länge det håller i sig kommer Sverige kunna utmana ett land som Kina med sina enorma kunskapsresurser i form av invånare med hög utbildning. Ett land där svenska språket inte ens hade räknats som ett minoritetsspråk. För att räknas som ett minoritetsspråk i Kina måste minst 10 miljoner människor prata språket.
Till svenska studenter vill jag bara säga en sak: Fortsätt ifrågasätt och använd er fantasi. På så vis kan vi utveckla Sverige och nå nya framgångar.

Ibland bestraffas fantasi

söndag, december 12th, 2010

Linus Omark har det som de flesta hockeyspelare (och fotbollsspelare) från Sverige saknar. Hårt drillade i lagspel har lekfullheten och fantasin prioriterats ned. Men förändringarnas vindar blåser i Sverige. Att göra en spelare är viktigare än att vara en bricka i spelet. Men när Linus Omark gör sin NHL-debut får han kritik för det han gör, av motståndarna. En en artikel på aftonbladet.se ber han om ursäkt för den kritik som riktats mot honom. I artikeln kan vi längst ned läsa vilka som kritiserar. Det är spelare i Tampa Bay, det vill säga det lag som Linus förnedrade. :)

Det är dags att NHL får en lirare som använder sin fantasi som Linus gör. Härligt att se men samtidigt så tycker jag att Tampa Bay skall skämmas.

Kommentatorernas kommentar: ”Welcome to the big leauge” säger allt!

Till Mattias Öhlund kan jag bara säga: ”Surgubbe! Du är grymt avundsjuk att du inte levererar på den fantasifulla nivån!”

Här är en annan goding med Linus Omark:

Läser du också mail på semestern?

torsdag, juli 8th, 2010

Det är många som inte kopplar av helt från arbetet under semestern. En del fortsätter kolla mailen löpande, via mobilen eller handdatorn. Andra loggar in någon gång i veckan och läser av inboxen.  Jag själv tillhör de som stänger av synkningen i mobilen under semestern, men loggar in någon gång då och då för att hålla inboxen tom.

Och är det just det som får oss att kolla av mailen?  Vi vill inte börja vår första arbetsdag med att ha 400 olästa mail, i mångas fall säkert ändå fler. Och kanske är vi också rädda för att missa något ”riktigt mail” bland alla dessa bacom-mail som samlar sig på sommaren  (ja, bacon-mail är alltså inte spam, utan sådana mail vi själva en gång bett om att få – men som vi inte läser, tex nyhetsbrev, uppdateringar etc).

Om vi skulle använda våra intranät, vår collaboration-plattform (tex Sharepoint) mer till att dela information skulle detta problemet delvis lösa sig. Där finns sjävla informationen, och det är enkelt att skapa prenumerationer, tex en gång i veckan eller en gång i månaden som berättar vad som är nytt/ändrat.

En annan möjlighet är förstås att tänka på vem vi mailar på sommaren. Kanske ska vi inte använda grupper för att tala om att det bjuds på glass vid eftermiddagsfikat, utan istället skicka mailen till dem vi vet är på plats. Givetvis är chat (instant messaging) ett verktyg som skulle kunna fungera utmärkt här.

Kanske kan vi alla hjälpas åt, och låta denna sommaren bli sommaren då mailskörden efter semestern är mindre. Nästa sommar arbetar vi smartare och delar information på ett mer strukturerat och smart sätt.  Vad tror ni?

Trevlig sommar!

//Magnus

Mera produktivitet!

torsdag, juni 10th, 2010

Har du nånsin funderat över hur din tid på dagarna verkligen spenderas?  Hur mycket tid lägger du på informationssökning, på att fråga kollegor om tips och råd, på att sortera mail, leta filer på den gemensamma hårddisken, eller rentav uppfinna något som någon annan redan har gjort.

Allteftersom vår datamognad ökar är vi bättre på att återanvända saker vi själva har gjort – men att ta del av och nyttja varandras prestationer har många en bit kvar till. Det finns de som tar ett stort grepp om detta med fina strategier och modeller och kallar det för knowledge management och att skapa en lärande organisation. Det är ofta rätt och vackert – men långt ifrån en konkret verklighet vi operativa individer brottas med dagligen.

Börja enkelt . Det handlar kanske om att skapa en gemensam yta på intranätet där alla skickade offerter finns, eller där presentationer finns, eller slutrapporter från projekt etc. Och sedan använda denna istället för att dubbellagra saker i mailen eller på c:. Eller bara att kunna hitta företagets organisationsnummer eller bankgiro. Ta reda var i din organisation som det finns behov för detta och vad för uppgifter som ofta efterfrågas eller uppfinns på nytt. Vissa kallar det genialt. Jag kallar det det produktivitet. Dvs att du får mer gjort på din arbetade tid.