156 punten
Working @ Delta-N as ALM/Team Foundation Server Specialist
24 mei 2011
Artikel: 7 november 2011

Omgaan met Generieke Libraries in Team Foundation Server

 634 views - Geen download beschikbaar


Rene van Osnabrugge

Een belangrijk onderdeel van Visual Studio Team Foundation Server (TFS) is het uitgebreide Source Control Systeem. In tegenstelling tot wat veel mensen nog steeds denken, is dit geen opvolger of nieuwe versie van MS Visual SourceSafe (VSS). Het TFS Versie Controle Systeem (VCS) is volledig gebaseerd op SQL Server en heeft vele nieuwe features t.o.v. het "oude" SourceSafe. Een vraag die ik vaak krijg bij TFS implementaties of analyses is: "Hoe ga ik om met generieke libraries in TFS VCS?". In dit artikel wil ik deze vraag beantwoorden. De vraag komt veelal voort uit het feit dat er naast de vele features die er zijn bijgekomen, ook twee features zijn die TFS niet heeft. Dit zijn Sharing en Pinning. In de volgende paragraaf zal ik deze twee begrippen even kort toelichten.


 

Sharing & Pinning

Binnen VSS biedt Sharing de mogelijkheid om bestanden te delen over verschillende projecten heen. Bijvoorbeeld een generieke class library wordt gedeeld naar meerdere projecten. Alle wijzigingen vinden plaats op dezelfde bestanden, terwijl het in de structuur onderdeel "lijkt" te zijn van een project.

Sharing is in TFS VCS als feature niet aanwezig. De filosofie hierachter is dat het potentieel "gevaarlijk" is om gebruik te maken van dezelfde bestanden in verschillende projecten of teams. Als een ontwikkelaar code verandert in Project A kan er onverwacht wat omvallen in Project B. In TFS VCS zijn andere mogelijkheden bedacht, zoals workspaces en Branching en Merging. Deze begrippen worden verderop in het artikel nader toegelicht.

Door middel van Pinning kun je een versie van een bestand vast zetten ("pinnen") in VSS. Alle gebruikers die dit bestand uitchecken, krijgen dan niet de laatste versie maar de versie die is "gepinned". Dit wordt nogal eens gebruikt om de "work in progress" versie wel onder Source Control te houden, maar niet uit te leveren aan collega's.

Pinning is in TFS VCS ook niet als feature beschikbaar. Hiervoor zijn o.a. branching en merging en shelving in de plaats gekomen. Shelving geeft de gebruiker de mogelijkheid om bestanden op de server op te slaan op een aparte locatie. Andere gebruikers krijgen deze versie dus niet als zij de laatste versie ophalen. Met branching en merging is het mogelijk om een heel project of feature geïsoleerd te houden van de rest van de code.

 

Workspaces, Branching en Merging

Voordat ik begin aan het uitleggen van de verschillende methoden om generieke libraries binnen het project beschikbaar te maken, wil ik eerst een aantal termen toelichten die zeer belangrijk zijn in de te bespreken methoden.

Workspaces
In TFS VCS wordt een workspace gebruikt om een mapping aan te leggen tussen de server locatie (vaak aangeduid met $locatie) en de fysieke locatie op de PC van de gebruiker. Deze mapping staat opgeslagen op de server. Doordat deze mapping bestaat, weet de server of de file die lokaal staat nieuwer of ouder is dan de file die in Source Control staat. Hierdoor voorkomt TFS VCS dat bestanden over de lijn worden gestuurd die de gebruiker al lokaal heeft staan.
Een workspace in TFS VSC is bijna hetzelfde als een workfolder in Visual SourceSafe, er zijn echter een aantal verschillen:

  • Een workspace kan meerdere lokale folders bevatten
  • Er kunnen meerdere workspaces zijn die naar de zelfde server folder wijzen

Schematisch kan dit als volgt worden weergegeven;

Figuur 1: Schematische weergave workspaces

In TFS ziet deze mapping er als volgt uit

Figuur 2: Mapping workspaces in TFS

In Figuur 2 wordt een workspace gedefinieerd. Een workspace wordt uniek gekenmerkt door een naam, een eigenaar, een server en een computernaam.

In de tabel "Working folders" worden mappings gemaakt tussen server locaties en lokale folders. Veelal zal dit een eenvoudige mapping zijn ($ProjectX -> c:\Work\ProjectX), maar dit kunnen ook gecombineerde mappings zijn. In Figuur 2 is een lokale workfolder opgebouwd door mappings te maken naar verschillende locaties in TFS VCS. Lokaal staat alles netjes gegroepeerd, maar op de server staat het geïsoleerd in het eigen Team Project.

Workspaces blijven altijd geïsoleerd. Wijzigingen die worden aangebracht in de ene workspace kunnen alleen door middel van "Get Latest Version" worden overgehaald naar een andere workspace. In Figuur 3 staat een schermprint van het Pending Changes Window. Alle bestanden die binnen een workspace worden gewijzigd, toegevoegd of verwijderd, worden als Pending Change gekenmerkt.

Figuur 3: Pending changes binnen een workspace

Het is aan te raden om voor ieder project een aparte workspace aan te maken. Zo voorkom je dat wijzigingen van verschillende projecten door elkaar heen gaan lopen.

 

Branching & Merging

Branching betekent letterlijk aftakken. In het geval van Source Control betekent het dit ook, het aftakken van een folder. Er zijn verschillende strategieën voor het branchen. Het meest gangbare scenario is de "Branching for Release" strategie.

Hierbij wordt een aftakking gemaakt van de stabiele versie zodra deze klaar is voor release. Ontwikkelaars werken door op de development branch. Eventuele hotfixes kunnen op de release branch worden gemaakt. Zodra de wijzigingen zijn doorgevoerd kunnen de wijzigingen van de release branch worden teruggezet naar de main en development branch (als dit nodig is). Dit terugbrengen naar de oorspronkelijke branch heet mergen.

Figuur 4: Branch for Release strategie

In de meest simpele vorm is branchen het "slim" kopiëren van code naar een andere locatie. De relatie naar het origineel blijft altijd behouden en wijzigingen kunnen dus relatief eenvoudig heen en weer worden gebracht.

Voor meer informatie over Branching en Merging en alle verschillende strategieën is deze link erg nuttig. http://tfsbranchingguideiii.codeplex.com/

 

First class branches (FCC)

In TFS 2005/2008 was een branch eigenlijk een folder.In TFS 2010 is een branch een zogenaamde "First Class Citizen" (FCC) geworden. Dit betekent dat deze branches (FCC branches) iets andere eigenschappen hebben dan folders en dat de branches kunnen worden gevisualiseerd.

Ten eerste kan de relatie tussen de verschillende branches worden gevisualiseerd door TFS en ten tweede kunnen wijzigingen, die gemaakt zijn in een branch en gemerged zijn naar een andere branch, met deze FCC branches eenvoudiger worden gevolgd.

Figuur 5:Track Changeset

In bovenstaande figuur is te zien dat de DEV1_0 en RELEASE_1_0 branch beide afstammen van de MAIN branch. Door een checkin te traceren is te zien dat er 2 checkins op de de DEV1_0 branch zijn gemerged naar de MAIN branch. Deze wijzigingen zijn echter nog niet doorgevoerd in de RELEASE_1_0 branch.

Het nadeel van FCC branches is dat deze niet "genest" kunnen zijn in andere branches. Met andere woorden, een FCC branch kan geen sub-branches hebben.

Bij het aanmaken van een branch kan worden aangegeven of er een FCC branch of een "ouderwetse" branch moet worden aangemaakt.

In het branch venster wordt hiervoor een optie getoond.

Figuur 6: First Class Branch optie

Wanneer het vinkje uit wordt gezet wordt er een "ouderwetse" branch van gemaakt. De relaties met andere branches zijn dan alleen te raadplegen door properties op te vragen van de betreffende branch.

Wees dus alert op waar de branch gemaakt wordt zodat de herkomst van code altijd terug te leiden is.

Figuur 7: Branch visualisatie

 

Drie mogelijke oplossingen

Om terug te komen op de hoofdvraag van het artikel, "Hoe ga ik om met generieke libraries in TFS VCS?", zijn er 3 methoden toepasbaar. De keuze voor een methode is een keuze die, naast persoonlijke voorkeur, afhangt van een aantal belangrijke criteria;

  1. Vinden er veel veranderingen plaats in de generieke libraries gedurende de ontwikkeling van een project?
  2. Worden de wijzigingen door een vast persoon of een aantal vaste personen gedaan?
  3. Zijn er vaste release data voor de generieke libraries? Worden de generieke libraries ook gereleased en krijgen deze een versienummer?
  4. Moeten wijzigingen direct voor iedereen (ook op andere projecten) beschikbaar zijn?
  5. Werken projecten op een vaste versie van de Generieke Libraries?
  6. Is het belangrijk dat de Branch/Merge werkzaamheden tot een minimum worden beperkt?
  7. Moet het mogelijk zijn dat projectleden zelf bepalen wanneer de generieke Libraries worden geupdate.
  8. Is build snelheid belangrijk tijdens ontwikkelen?
  9. Is de structuur ingeregeld op server?
  10. Grafische visualisatie van branches en changes?

Na beoordeling van bovenstaande criteria kan er één van de onderstaande oplossingrichtingen worden gekozen.

  • Generieke libraries als gecompileerde assemblies
  • Generieke libraries als branch in je project
  • Generieke libraries in je project d.m.v. een workspace template

 

Generieke libraries als gecompileerde assemblies

Dit alternatief is niet uniek voor TFS VCS. Dit kan ook met de oude SourceSafe. Hoe voor de hand liggend het ook lijkt, generieke libraries in een assembly compileren en deze gebruiken in projecten is voor vrij statische libraries een zeer goede methode.

Werkwijze
Op de TFS is er een Team Project aangemaakt speciaal bedoeld voor de generieke libraries. Dit project heeft zijn eigen eigenaar en zijn eigen release strategie. Een voorbeeld hoe de structuur in TFS VCS eruit zou kunnen zien volgt hieronder:

Figuur 8: Structuur TFS VCS

Omdat er een apart Team Project is aangemaakt, kunnen nieuwe wensen, bugs etc. op dit Team Project als Work Item worden aangemaakt. De eigenaar van de generieke libraries zorgt voor een verdeling van het werk onder de "Generieke Library Ontwikkelaars".

De "Generieke Library Ontwikkelaars" ontwikkelen op de DEV Branch. Als zij wijzigingen doorvoeren komen deze via een Merge actie in de STABLE Branch. Als alle wijzigingen zijn getest wordt de STABLE Branch gemerged met de RELEASE Branch.

Figuur 9: Build Definitie

Op de RELEASE Branch staat een release build gedefinieerd. Deze wordt door de eigenaar handmatig aangezet. Aan het einde van de build kunnen de assemblies op een gedeelde netwerklocatie neergezet worden, of kan er een mail worden rondgestuurd dat er een nieuwe release van de generieke libraries beschikbaar is.

Samenvatting
Het gebruik van generieke libraries als gecompileerde assemblies is een goed alternatief wanneer deze deze door externe partijen en/of andere ontwikkelaars ontwikkeld worden, of wanneer weinig wijzigingen op plaatsvinden. Wanneer er veel wijzigingen zijn zorgt dit voor veel overhead.

Gebruik dit alternatief niet als er veel wijzigingen plaatsvinden op de generieke libraries die worden vereist door een specifiek project. Dit zorgt voor veel overhead.

 

Generieke libraries als branch in het project

Een methode die erg veel flexibiliteit biedt is het aanmaken van een speciale branch in het te ontwikkelen project. Deze methode is vooral geschikt als er aan meerdere projecten tegelijk wordt gewerkt (die gebruik maken van generieke libraries) en als de generieke libraries aan veel verandering onderhevig zijn.

Zeker als er wordt begonnen met het opzetten van generieke libraries, wordt er veel code toegevoegd en gewijzigd in de generieke library projecten. Als er wordt gekozen voor gecompileerde assemblies, kan dit vertragend werken binnen een project. Ontwikkelaars werken vaak tegelijk aan de library en aan het project.

Als er meerdere projecten gaande zijn, is het vaak niet wenselijk dat generieke code wordt aangepast ten behoeve van een project. Dit kan namelijk leiden tot fouten en build errors in een ander project. Om toch direct aan de generieke libraries te kunnen werken, zonder het risico dat andere code hierdoor omvalt, kan branching worden ingezet.

Werkwijze
Net zoals het alternatief met de gecompileerde assemblies is er voor de Generieke Libraries een apart Team Project aangemaakt. De wens is nu echter dat ontwikkelaars kunnen werken aan de libraries binnen hun Visual Studio solution en zonder direct andere projecten te beïnvloeden. Schematisch kan deze structuur er alst volgt uit;

Figuur 10: Branch/Merge structuur

Er zijn twee projecten op de TFS aangemaakt. Eén voor de "Generic Libraries" en één voor "ProjectX". Deze hebben allebei dezelfde Branching en Merging strategie. Namelijk dat er van een stabiele branch wordt ontwikkeld en gereleased.

Als extra toevoeging wordt de Development Branch van de GenericLibraries nogmaals gebranched naar ProjectX. Dit heeft als doel dat Project X nu de generieke libraries in het project kan gebruiken, maar dat wijzigingen gecontroleerd kunnen worden doorgezet naar de Generieke Libraries repository (door Merging).

Figuur 11: Branch maken

Het vinkje "Convert source and target folders to branches (enables visualizations)" moet uit!! staan. Dit voorkomt dat er een First Class branch wordt aangemaakt waar "child" branches niet zijn toegestaan.

In Source Control (of Windows Verkenner) ziet dit er dan als volgt uit.

Figuur 12: Source Control Explorer

Binnen de Visual Studio Solution van ProjectX wordt nu het gebranchede GenericLibraries project toegevoegd.

Figuur 13: Generieke Libraries als onderdeel van Solution

Wijzigingen die worden gemaakt op de "Generic Libraries" gelden alleen voor de "Generic Libraries" binnen "ProjectX". Omdat het een branch betreft kan er echter altijd worden terug gemerged naar het originele Generic Libraries project.

Om de wijzigingen terug te mergen naar het origineel kun je in Source Control kiezen voor "Merge". Zorg er wel voor dat de actieve workspace degene van de generieke Libraries is. De wijzigingen die worden gemerged, worden namelijk op de lokale bestanden gedaan. Als de actieve workspace niet de merge locatie in zich heeft, wordt een melding gegeven dat er een workspace mapping moet worden gemaakt. De wijzigingen kunnen dan niet worden gemaakt.

Figuur 14: Merge initieren

Als er geen conflicten zijn worden de wijzigingen gemerged. Dit gebeurt in eerste instantie alleen lokaal dus er moet nog worden ingecheckt voordat dit definitief wordt.

Door een vergelijking te doen op het laatste bestand in TFS VCS en de gemergede versie zijn de verschillen duidelijk.

Figuur 15: Verschillen bekijken 

Samenvatting
Zodra meerdere projecten tegelijk gebruik maken van de generieke libraries kan isolatie een vereiste zijn. Wijzigingen die worden gedaan voor het ene project zijn niet altijd (direct) wenselijk voor het andere project. Generieke libraries als branch in een project bieden hiervoor een elegante oplossing.

Het nadeel is dat er overhead ontstaat doordat de generieke libraries bij tijd en wijle ook gemerged moeten worden.

Een tweede nadeel is dat met de komst van TFS 2010 en First Class Branches de ondersteuning van TFS niet optimaal is voor dit scenario.

 

Workspace op de client

Zoals in het begin van het artikel is uitgelegd is een workspace een mapping tussen een map op de Team Foundation Server en een map op de client. Een map op de client kan mappen op meerdere server mappen. Dit wordt grafisch weergegeven in Figuur 1.

Als er regelmatig wijzigingen worden gedaan in de generieke assemblies en als het nodig is dat deze wijzigingen direct zichtbaar zijn in andere projecten, is de workspace op de client een goede methode.

In het kort komt deze methode er op neer, dat de inhoud van één lokale map wijst naar meerdere server mappen. Bij het ophalen van een laatste versie worden dan uit verschillende Team Projecten de laatste sources opgehaald. Wijzigingen hierop worden ook direct naar het juiste project gestuurd.

Werkwijze
De werkwijze voor deze methode is vergelijkbaar met de werkwijze voor branching. Er is nog steeds een apart Team Project voor Generieke Libraries en een apart Team Project voor ProjectX. De combinatie van folders die we bij Branching op de Server hebben gedaan door middel van branching gaan we nu toepassen op de client door middel van een Workspace mapping.

Iedere deelnemer aan ProjectX dient deze Workspace mapping te hebben. Onderstaand figuur geeft aan hoe dit eruit komt te zien.

Figuur 16: Workspace Mapping

De folder c:\work\ProjectX wordt opgebouwd uit verschillende folders vanuit verschillende Team Projecten.

Zodra er wijzigingen plaatsvinden in deze workspace worden deze automatisch op het juiste Team Project ingecheckt. Andere gebruikers op andere projecten (met een zelfde soort Workspace mapping) halen door middel van een Get Latest Version alle wijzigingen op.

Het aanmaken van de workspace moet op iedere client gebeuren. Dit kan best een tijdrovend karwei zijn en het is foutgevoelig. Immers, een verkeerde mapping kan leiden tot verwijzigngen die niet kloppen en projecten die niet builden. In de PowerTools voor VS 2010 ( http://visualstudiogallery.msdn.microsoft.com/c255a1e4-04ba-4f68-8f4e-cd473d6b971f ) is een tool gekomen die dit probleem voor een groot deel oplost. Workspace templates

Door middel van een Workspace template kan de mapping door een persoon worden vastgesteld. Vervolgens kunnen gebruikers aan de hand van dit template hun lokale mapping doen.

Dit ziet er als volgt uit.

De Project Administrator maakt een nieuw Workspace template aan.

Figuur 17: Nieuw Workspace template

Nadat de Project Administrator de mapping heeft aangemaakt kan een Team lid kiezen voor "Create Workspace"

Figuur 18: Create Workspace

Figuur 19: Create Workspace formulier

De code wordt nu in de structuur van de workspace template opgehaald in de lokale folder.

Samenvatting
Zodra er sprake is van een klein ontwikkelteam dat veel werk verricht op de generieke libraries is de workspace variant een geschikte oplossing. Er is geen overhead voor branching en Merging. Wijzigingen zijn direct beschikbaar in andere projecten zodra er Get Latest Version wordt gedaan. Dit kan een voordeel zijn maar ook een nadeel.

Bijkomend nadeel is dat gebruikers ondanks het bestaan van Workspace Templates handmatig een eigen workspace mapping moeten maken.

 

Conclusie

Dit artikel heeft drie methoden belicht om generieke libraries in een project te ontsluiten. Alle methoden hebben hun eigen voor- en nadelen. De mogelijkheden van TFS VCS zijn in ieder geval ruimschoots voldoende om de verschillende methoden toe te passen. De beschreven scenario's zijn slechts een greep uit de mogelijkheden. De scenario's kunnen uiteraard ook gecombineerd worden om zo een optimale combinatie te krijgen.

De beslis criteria van het begin van het artikel zijn hieronder in een matrix gezet. Deze matrix geeft aan welke methode het meest geschikt is. De volgorde van belangrijkheid van de criteria is willekeurig. Iedere organisatie moet zelf beslissen welke criteria het zwaarst wegen.

 

Over de auteur


Vanaf het begin van zijn carriere in 1999 heeft René zich beziggehouden met Microsoft ontwikkelomgevingen. Hij heeft gewerkt bij verschillende bedrijven in de telecom, bank, mode, overheid en verzekeringssector. Dit allemaal voornamelijk op het gebied van webtechnologie.

Bij ALM Gold Partner Delta-N is René verantwoordelijk voor de Microsoft ALM oplossingen en dus gespecialiseerd in Visual Studio ALM en Team Foundation Server. Hij is met name betrokken bij advies- en implementatie trajecten rondom de Microsoft ontwikkelstraat.

Daarnaast is René spreker en trainer op (Microsoft) seminars en conferenties.