Bygg VS2010-projekt, men behåll TFS 2008

clock juni 16, 2010 21:22 by author Daniel Hognert

För oss som börjat migrera vissa projekt till Visual Studio 2010, men ännu inte fått klartecken (eller licens) till att uppdatera Team Foundation Server 2008 till nästa version, finns det några väldigt enkla steg att följa för att få igång dina automatiska byggen och tester (Continuous Integration). På egen risk förstås.

Följ bara instruktionerna på http://www.richard-banks.org/2009/11/how-to-build-vs2010-solutions-using.html



Automatisk uppdatering av versionsnummer i TFS bygge

clock november 18, 2009 17:53 by author Magnus Härlin

Om man har en automatiserad byggprocess i TFS och vill att versionen på alla assemblies ska uppdateras automatiskt för varje bygge kan man ta hjälp av MSBuild Community Tasks som har många bra tasks för MSBuild. I mitt exempel så tar jag och lägger in Build numret som ÅÅMM och sen tar jag changeset numret från TFSen. På så sätt är det lätt att spåra tillbaks en specifik release till en kodbas. Vill man ändra Major och Minor versionen är det bara gå in och göra det i byggscriptet.

 

För att lägga in versionshanteringen i byggprocessen går man in i projektfilen och lägger till:

 <Import Project="..\MsBuildTasks\SetVersion.targets" /> 

Pathen ska förstårs vara till den plats där man skapar SetVersion.targets filen i förhållande till projektet.

 

Har man flera projekt lägger man till referensen i alla projektfilerna som man vill ha versionen uppdaterad på. I den katalogen där man har SetVersion.targets filen behöver man även lägga in MSBuild.Community.Tasks.dll. Man får lägga till en fil som heter AssemblyVersion.cs i projekten man vill ha versionen också. Den populeras automatisk av bygget men måste vara med i projektet för att den ska komma med i kompileringen. 

 

 <Project InitialTargets="SetVersion" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">     <UsingTask AssemblyFile="MSBuild.Community.Tasks.dll" TaskName="MSBuild.Community.Tasks.AssemblyInfo" />   <UsingTask AssemblyFile="MSBuild.Community.Tasks.dll" TaskName="MSBuild.Community.Tasks.Tfs.TfsVersion" />

   <PropertyGroup>

           <Major>1</Major>

           <Minor>0</Minor>

           <Build>0</Build>

           <Revision>0</Revision>

  </PropertyGroup>

   <Target Name="SetVersion" Condition="'$(IsDesktopBuild)'=='false'">

            <TfsVersion LocalPath="$(SolutionDir)" TfsLibraryLocation="$(SolutionDir)\Dependencies">

             <Output TaskParameter="Changeset" PropertyName="Revision"/>

           </TfsVersion>

           <Time Format="yyMM">

             <Output TaskParameter="FormattedTime" PropertyName="Build" />

           </Time>

            <Message Text="%0a%0dMaking files writeable" />

           <Exec Command="attrib Properties\AssemblyVersion.cs -R" />

                      <AssemblyInfo CodeLanguage="CS" OutputFile="Properties\AssemblyVersion.cs" 

    AssemblyVersion="$(Major).$(Minor).$(Build).$(Revision)"

      AssemblyFileVersion="$(Major).$(Minor).$(Build).$(Revision)"

             Condition="$(Revision) != '0'" />

            <Message Text="%0a%0dMaking files readonly" />

           <Exec Command="attrib Properties\AssemblyVersion.cs +R" />

   </Target>

 </Project>

 När byggservern bygger projekten så kommer den sätta variabeln $(IsDesktopBuild) till false. Lägger man inte in det conditionet kommer versionen uppdateras varje gång och det finns ingen anledning att göra det när man bygger på klienten. Skulle man jobba offline och inte ha tillgång till TFSen när man bygger får man ett exception. På det här sättet kan man bygga offline men när byggservern gör bygget så läggs versionnumret in.



S.O.L.I.D. Design Principles – Separation Of Concerns

clock februari 5, 2009 17:54 by author Magnus Härlin

Separation Of Concerns är den första principen i SOLID och innebär att en klass bara ska göra en enda sak. I mitt exempel har vi en PriceCalculator klass som räknar ut hur mycket det kostar att hyra en film. Förutom att räkna ut priset kollar den vad det är för kundtyp och filmtyp. Switch och if satsen är inte helt otydligt men det går att få klassen betydligt tydligare. Nu har den fler ansvar och skulle man lägga till en kundtyp eller en filmtyp till skulle koden börja likna spagettikod och vara jobbig att underhålla.

 

Ett anrop till klassen ser ut såhär:

 

PriceCalculator priceCalculator = new PriceCalculator();

int price = priceCalculator.CalculatePrice(CustomerType.VIP, MovieType.Normal);

 

När CalculatePrice klassen anropas med VIP kund och Normal film kommer den att skicka tillbaks ett pris på 20 kr för att VIP kunden får 5 kr i rabatt. Här nedanför är koden för att komma fram till det.

 

public enum CustomerType

{

    Normal,

    VIP

}

 

public enum MovieType

{

    Normal,

    Transfer

}

 

public class PriceCalculator

{

    public int CalculatePrice(CustomerType customerType, MovieType movieType)

    {

        switch (customerType)

        {

            case CustomerType.Normal:

                if (movieType == MovieType.Normal)

                {

                    return 25 - 0;

                }

                else if (movieType == MovieType.Transfer)

                {

                    return 35 - 0;

                }

                break;

            case CustomerType.VIP:

                if (movieType == MovieType.Normal)

                {

                    return 25 - 5;

                }

                else if (movieType == MovieType.Transfer)

                {

                    return 35 - 5;

                }

                break;

        }

 

        return 0;

    }

}

 

 

Ett första steg för att få koden mer lättläst är att ta bort CalculatePrice klassens ansvar för att kolla kundtyp, filmtyp och vad det ska vara för rabatt. Vi delar upp det i två klasser. Kundtypen används bara för att ta reda på vad det ska vara för rabatt så vi skapar en kundklass med en property för rabatt. Filmtypen används för att bestämma vad det ska vara för pris på filmen så vi skapar en klass filmklass som har en property för pris. Genom att göra det här så blir det inte så mycket kvar att göra för PriceCalculator mer än att ta priset – rabatten och returnera värdet. Slutresultatet för PriceCalculatorklassen blir alltså:

 

    public class PriceCalculator

    {

        public int CalculatePrice(Customer customer, Movie movie)

        {

          return movie.Price - customer.Rebate;

        }

    }

 

Men hur ska vi göra för att på ett tydligt sätt visa att det finns olika filmtyper som har olika pris? Ett sätt är att skapa en basklass som heter film och har ett fast pris på 25 och sen göra en underklass som ärver den klassen och gör en override på priset.

 

    public class Movie

    {

        public virtual int Price { get { return 25; } }

    }

 

    public class TransferMovie : Movie

    {

        public override int Price { get { return 35; } }

    }

 

På precis samma sätt kan vi göra med kundklassen för att kunna sätta olika rabatt.

 

    public class Customer

    {

        public virtual int Rebate { get { return 0; } }

    }

 

    public class VIPCustomer : Customer

    {

        public override int Rebate { get { return 5; } }

    }

 

För att göra ett anrop för en VIP kund på en normal film nu så skiljer det inte så mycket från tidigare. Man byter ut Enum typerna till klasserna man skapat istället bara.

 

PriceCalculator priceCalculator = new PriceCalculator();

int price = priceCalculator.CalculatePrice(new VIPCustomer(), new Movie());

 

Returvärdet man får kommer att vara 20 kr precis som tidigare.

 

Separation Of Concerns är alltid bra att ha i bakhuvudet när man kodar och börjar få nestlade if satser eller switchsatser. Ibland går det att på ett smidigt sätt bryta isär det man gör och på så sätt få kod som är lättare att underhålla och tydligare att använda.



Pimp My Code

clock februari 2, 2009 09:06 by author Magnus Härlin

Under förra veckan gå gick Pimp My Code av stapeln i Göteborg. Det var en väldigt lyckad och intressant kväll.

 

Första sessionen höll Joakim Sundén i. Han pratade om kodkvalitén och proffesionalismen hos programmerare. Några av dom intressantaste punkterna som  han tog upp var

·         ”Broken window theory” – Om man har ett krossat fönster i ett hus och inte reparerar det kommer det leda till att flera fönster krossas och att det är större risk för inbrott eller skadegörelse. Det samma gäller för kod, om man ser många fulfixar så är det större risk att det leder till fler.

·         Förändring börjar alltid hos en själv. Om man själv har attityden att alltid checka in bättre kod än man checkade ut så är det ett bra utgångsläge.

·         Parprogrammering ger 60 % buggupptäckningsgrad jämfört med att sitta och koda själv.

·         Parprogrammering tillsammans med TDD ger ca 98 % buggupptäckningsgrad jämfört med att sitta och koda själv utan TDD.

 

Andra sessionen höll Patrik Löwendahl och den handlade om S.O.L.I.D. principerna som jag nämnt tidigare i ett tidigare inlägg. Jag kommer att lägga upp en post om varje enskild princip så jag nämner inte så mycket mer om det här.

 

Tredje sessionen höll Fredrik Normén och den handlade om Refaktorering till Mönster och exemplet var ett väldigt klassiskt på hur en swith sats lätt kan växa sig lite för stor eller riskera att göra det och hur man genom att använda Separation Of Concerns kan lösa det snyggare. Jag kommer att ta upp det i inlägget om Separation Of Concerns som är den första principen i S.O.L.I.D.

 Sista sessionen höll Dag König och den handlade om Kodkvalité och hur man kan mäta den med olika verktyg. Bland annat fxCop som man kan koppla in till Visual Studio och sen även Visual Studios egna code metrics. Med fxCop kan man välja vilka regelbibliotek man vill att den ska använda och så får man veta om koden bryter mot några av dom. Den kan vara namnstandard som inte följs eller att man bryter mot best practices. Code Metrics i VisualStudio har några olika kategorier som LinesOfCode, ClassCoupling, CyclomaticComplexity (hur många utgångar en funktion kan ha) och Maintainability Index där bra värden är < 70 men sen finns det förstås alltid undantag.


TDD Exempel

clock november 21, 2008 15:29 by author Magnus Härlin

Det här är ett kort exempel på hur man skulle kunna lägga upp testdriven utveckling av en funktion som ska ta in en sträng och parsa den och returnera ett nummer.

I TDD är det tre steg man alltid gör om och om igen tills allt är klart, stegen är:
• Skriv ett test som inte går igenom
 Ingen kod utan ett fallerande test
• Få testet att lyckas
Med så enkel kod som möjligt
• Gör koden bättre
Refaktorera

När man skriver första testet ska det vara det enklaste sättet att få funktionen att lyckas. Allra enklaste hade jag tyckt var att skicka in en tom sträng, men eftersom kravet inte sa någonting om det så blir det första jag får man först se till att kravet är tydligt genom att fråga sin chef eller kund istället för att gissa. Nu har vi fått ett tydligare krav och vet att skickar man in en tom sträng ska funktionen returnera 0.

Vi börjar skriva testet, skapar en i stort sett tom funktion så att vi kan kompilera projektet och köra testet.


//Testprojektet
        [TestMethod]
        public void CanParseEmptyStringToInteger()
        {
            ParseStringToInteger parser = new ParseStringToInteger();

            int actual = parser.ParseToInteger(String.Empty);

            Assert.AreEqual(0, actual);
        }

//Logik klassen
        public int ParseToInteger(string stringToParse)
        {
            return -1;
        }

När vi kör testet första gången får vi ett rött fallerande test precis som väntat.

Det absolut minsta vi behöver göra för att få koden att fungera är att ändra så att vi skicka tillbaks 0. Vi uppdaterar koden så att det står return 0;
 i funktionen istället och kör testet igen. Det blir grönt för att testet gick igenom. Kommer det här fungera senare? Det spelar ingen roll! För man koncentrerar sig på ett test i taget och det absolut lättaste sättet att få det att gå igenom var att göra såhär. Då är det rätt sätt.

Uppenbarligen har vi inte täckt in alla krav än så vi skapar ett test till där vi skickar in 1.

[TestMethod]
        public void CanParseStringWithNumberOneInToInteger()
        {
            ParseStringToInteger parser = new ParseStringToInteger();

            int actual = parser.ParseToInteger("1");

            Assert.AreEqual(1, actual);
        }


Testet misslyckas så våran nuvarande kod täcker inte in det nya testfallet än. Vi gör följande uppdatering:

public int ParseToInteger(string stringToParse)
        {
            return int.Parse(stringToParse);
        }


Nu går det andra testet igenom men det första misslyckas. Vi måste lägga till ett sätt för att se om strängen är tom och sen vet vi sen tidigare att vi bara behöver returnera 0 för att kravet ska uppfyllas för det första testet också.

public int ParseToInteger(string stringToParse)
        {
            if (string.IsNullOrEmpty(stringToParse))
            {
                return 0;
            }

            return int.Parse(stringToParse);
        }


Nu vet vi att funktionen gör precis det vi förväntar oss av den. Den parsar en sträng till en siffra och alla krav är uppfyllda och vi skapade först tester från kraven och sen funktioner som uppfyllde testerna.

Är det krav på att vi ska validera det som kommer in kan vi förstås lägga till funktioner för det och fortsätta på samma sätt som vi gjort hittills.

Så lätt är TDD, kan kännas lite konstigt i början man har man väl vant sig vill man aldrig sluta.



Vad krävs för att komma igång med TDD?

clock november 17, 2008 08:41 by author Magnus Härlin

Vad tjänar man på jobba med TDD jämfört med att skriva testen efteråt? I båda fallen skriver man test för samma funktioner och kan få samma code coverage.

 

TDD leder ofta till bättre design och mindre buggig mjukvara. Anledningen är att utvecklare inte motiverade att hitta felen i sin kod utan bara visa att den som fungerar.

 

Vad finns det för problem med att arbeta med TDD? Det är en ganska hög tröskel för att komma igång med det. Dom tre största inlärningsmomenten är:

·         Lära sig skriva bra enhetstest

·         Lära sig att låta testen driva utvecklingen (TDD)

·         Lära sig att göra en bra design

 

I den ordningen är det bra att lära sig momenten också.

 

Vad är det då som gör ett test bra? Framförallt är det att det är lättläst test där det är tydligt vad det testar. Det är absolut inte ett krav att ett test ska testa all funktionalitet i en klass utan hellre flera lättlästa korta test som tydligt testar olika delar av klassen.

 

I nästa blogginlägg ger jag exempel på hur man kan driva designen med test.

 

En best practice för att det ska vara bra design är att följa S.O.L.I.D

·         Single Responsibility Principle (SRP)

·         Open Closed Principle (OCP)

·         Liskow Substitiution Principle (LSP)

·         Interface Segragation Principle (ISP)

·         Dependency Inversion Principle (DIP)

 

För att hitta bra förklaring och översikt över principerna kan man titta in på: http://www.lostechies.com/blogs/chad_myers/archive/2008/03/07/pablo-s-topic-of-the-month-march-solid-principles.aspx

 

Som med allt annat så är bästa sättet att lära sig samtliga delar att öva. Sen är det klart att det kan gå lite fortare och vara roligare om man har någon mer erfaren i teamet som man kan fråga och få guidning av.



PDC 2008 - Los Angeles

clock november 11, 2008 22:32 by author Janne Hasslöf

Microsoft är proffs på stora evenemang.
Det märks redan vid hotellet med veckoagendan på ett stort uppslag i lobbyn och tidtabeller för bussar till pdc och evenemang. Det är bara att gå ut på trottoaren på morgonen så kommer en funktionär och tar hand om en och visar till bussen.
Efter en kort stund sitter jag på andra raden i den stora key-note-salen.  Rockmusiken dunkar. Rökmaskinerna jobbar och alla är spända. Snart....snart börjar det.....Nu tar kameramannen på sig lurarna. Det är mycket tv-kameror här och säkert plats för 100 journalister....spännande. Visst låter man lite som ett barn på julafton, men så är det :-)

Det första Microsoft lanserade på PDC var Windows Azure, Microsofts nya plattform för att drifta och koppla samman tänster på nätet, eller i molnet som man säger numera.
Windows Azure tillhandahåller idag 4 tjänster som utveklare och driftavdelningar kan använda sig av:

Service Bus
En klassisk buss som knyter ihop tjänster i molnet enligt samma principer som en vanliga företagsbuss knyter ihop tjänstebaserade applikationer på ett intranät.  

SQL Data Services
Enklare databastänst som håller en applikations data tillgängligt i molnet.  Kommer sannorlikt att bygas ut till en kraftfulare version i kommande releaser.

Workflow Service
Här kan man utvekla och drifta sina flöden av aktiviterer som skall ske när applikationer postar meddelanden på service-bussen .

Access Control Service
Denna tjänst styr behörigheten i de övriga tänsterna och har möjlighet att hämta behörighetsinformation från en mängd olika identites och behörighetssystem. Så som Microsoft LiveID, ett företags Active Directory, etc.  

För att lära dig mer om Windows Azure, gå in på http://www.microsoft.com/azure/default.mspx. Här kan man även anmäla sig till att vara med i ett utvecklarprogram. Jag kommer att återkomma till Azure i kommande inlägg när jag gett mig på att testa lite mer. 

Andra ämnen som jag tycker var speciellt intressanta och som jag kommer att återkomma till är 

Dublin
Den nya runtime-miljön för WCF och WF som är en utbyggnad av WAS som finns i dag.  Prestanda, enklare konfiguration och möjlighet till övervakning har varit fokus i denna version som Dan Eshner beskriver med orden "It just works!" 
Kolla Dublin här: http://channel9.msdn.com/pdc2008/BB18/

B2B
Kolla in hur man kan utnyttja Azure till att bygga en ny typ av Business-To-Business applikationer
http://channel9.msdn.com/pdc2008/BB59/

REST
Mycket av kommunikationen i Azure och andra ställen i molnet kommer att baseras på  REST-protokollet framöver. Här visas det hur man bygger WCF-tjänster som utnyttjar REST.
http://channel9.msdn.com/pdc2008/TL35/

Skalbarhet
Många siter växer ur sin kostym och designen kan inte längre leverera de responstider som förväntas. Här är en dragning om hur Microsoft ser på skalbarhet i framtiden och vilka principer som man kan sikta in sig på i framtiden.
http://channel9.msdn.com/pdc2008/BB54/

VS2010
Det händer massor i VS2010 tillsammans med TFS och det är riktigt kul att se alla nya features som man ju helst vill ha redan nu! Vill du tex. lära dig att analysera hur man skall angripa en befintlig applikation som akritekt så kolla på:
http://channel9.msdn.com/pdc2008/TL15/
Om du vill se hur man kan använda nya VSTS för att höja kvaliten på kod och applikationer så kolla på:
http://channel9.msdn.com/pdc2008/TL03/

Vill du själv botanisera i föreläsningar på PDC så bandades nästa alla och ligger uppe på
http://sessions.microsoftpdc.com/timeline.aspx
http://channel9.msdn.com/pdc2008/

Vi Hörs!
-Janne



Kasta om dina beroenden (Dependency Inversion)

clock september 18, 2008 15:14 by author Ola Håkansson

Inom objekt-orienterad programmering finns det väldigt många koncept och principer. Dependency Inversion Principle (DIP) är en av dem och används ofta när man talar om Dependency Injection och Inversion of Control containers. Men man behöver inte använda en container så som Unity, Castle Windsor, Autofac eller Ninject för att få använda sig av DIP.

Principen med dependency inversion säger helt enkelt att vi skall kasta om de beroenden som vår kod har. För att inte göra en parafras så citerar jag här på engelska direkt från en artikel om DIP hos Object Mentor (PDF):

  • High level modules should not depend upon low level modules. Both should depend upon abstractions.
  • Abstractions should not depend upon details. Details should depend upon abstractions.

Så som alla goda principer inom objekt-orienterad programmering är själva språket eller plattformen man kodar på totalt oviktig. Principen med dependency inversion fungerar lika bra om du sitter och kodar i Java, .NET eller något annat. Däremot kan DIP anses vara lite vagt formulerad för oss som just nu sitter på .NET-plattformen. Vad betyder det här med moduler? Det närmsta vi skulle komma är nog assemblies. Och vad är det för abstraktioner vi vill göra egentligen?

Poängen med dependency inversion principle är att vi vill ha kod som är lätt att ändra på. Vissa kanske skulle anse att dålig kod är något som t ex konkatenering av strängar. Visst varje gång vi konkatenerar strängar så slängs objekt till garbage collector och StringBuilder är kanske att föredra. Men det är inte alltid dåligt att konkatenera strängar. Bra kod är kod som man tittar på utan att ta en djup suck och funderar över var man skall börja ändra någonstans eller hur mycket som kommer gå fel när man ändrar i den. Om du känner att det kommer bli jobbigt att ändra på en bit kod, att det blir oanade följder när en bit kod ändras eller att koden är omöjlig att återanvända då är något fel.

Säg att vi har en bit kod som ser ut såhär:

public class CurrencyConverter { public decimal Convert(decimal amount, Currency fromCurrency, Currency toCurrency) { var client = new CurrencyConvertorSoapClient(); decimal rate = client.ConversionRate(fromCurrency, toCurrency); return rate * amount; } }

Så vad är det som kan vara fel med den här lilla biten kod? Vad den gör är ju ganska självklart. Tar in ett belopp och konverterar från en valuta till en annan med hjälp av en webbservice. Väldigt enkelt.

När vi kodar har vi oftast två koncept eller mått för vad vi vill uppnå. Cohesion och Coupling. Med cohesion menas hur sammanhållen koden är och att den bara har ett väldefinerat ansvar. Koden ovan har flera olika ansvar, den hämtar både växlingskursen och räknar ut beloppet. Vad vi vill ha är hög sammanhålling (high cohesion). Koden har också en stark koppling (coupling) till en webbservice. Vad händer om vi vill hämta växelkursen från någon annan källa. En databas eller så kanske den kommer in till systemet från fil. Det går heller inte att enhetstesta koden. Växelkursen ändras hela tiden och att gå mot en webbservice tar oftast ganska lång tid. Vi har inte uppnått low coupling.

Att fixa detta är faktiskt väldigt enkelt. Genom att kasta om våra beroenden kan vi refaktorisera om koden så att den uppnår detta.

public interface IExchangeRateRetriever { decimal GetExchangeRate(Currency fromCurrency, Currency toCurrency); } public class WebServiceExchangeRateRetriever : IExchangeRateRetriever { public decimal GetExchangeRate(Currency fromCurrency, Currency toCurrency) { var client = new CurrencyConvertorSoapClient(); return client.ConversionRate(fromCurrency, toCurrency); } } public class CurrencyConverter { private IExchangeRateRetriever _retriever; public CurrencyConverter(IExchangeRateRetriever retriever) { _exchangeRateRetriever = retriever; } public decimal Convert(decimal amount, Currency fromCurrency, Currency toCurrency) { decimal rate = _retriever.GetExchangeRate(fromCurrency, toCurrency); return rate * amount; } }

Vad vi har gjort är helt enkelt att bryta ner vår klass CurrencyConverter till dess minsta beståndsdelar. Nu har den bara hand om att räkna ut beloppet och ingenting annat. Vi har skapat ett kontrakt (interface) som vi använder oss av. Genom att CurrencyConverter nu måste ta emot ett objekt som uppfyller det här kontraktet i konstruktorn så använder vi oss av constructor injection. Vi kodar mot ett gränssnitt och inte implementationen genom att vi använder oss av dependency inversion principle. Vi har också uppnåt high cohesion och low coupling. Det går nu också att enhetstesta koden genom att t ex bara skapa en fejkad klass som uppfyller kontraktet IExchangeRateRetriever.

public class FakeExchangeRateRetriever : IExchangeRateRetriever { public decimal GetExchangeRate(Currency fromCurrency, Currency toCurrency) { return 0.1507; } }

Dependency injection handlar om att bryta ut saker som inte skall förhålla sig till varandra. Koden för att konvertera beloppet skall inte ha något med växlingskursen att göra. Det är nu också oerhört enkelt att ändra på koden som så skulle behövas. Det enda problemet som kvarstår nu är hur vi får in beroenden till klassen nu. Detta är något som Inversion of Control containers löser och det sparar vi till ett annat inlägg!