Solutions, projects en mappen structuur

Laatst had ik met een collega een discussie over hoe de structuur van onze code repository dient te zijn. Op dat moment kon ik niet zo snel beantwoorden waarom ik voor- danwel tegenstander van een bepaalde indeling ben, dus heb ik er nog eens over nagedacht.

In dit geval gaat het om verschillende Visual Studio Solutions (.sln) en hun C++ projecten (.vcxproj). Als ik een indeling zou moeten maken, zijn mijn afwegingen als volgt.

Ownership en containment

Solution

Een solution bevat projecten waarvan hij al dan niet owner is. Bij een solution als MyApplication.sln, verwacht ik een project MyApplication.vcxproj. De solution is owner van dit project, het hoofdproject. Het project kan daarnaast nog dependencies hebben op andere projecten. Deze dependencies zijn ofwel specifiek voor dit project, ofwel generiek en herbruikbaar. De solution bevat alle projecten waarvan de projecten waar hij eigenaar van is direct of indirect afhankelijk zijn. D.w.z. MyApplication is afhankelijk van MyApplicationLib, welke op haar beurt weer afhankelijk is van GenericLib. De solution bevat alle drie deze projecten. Dat lijkt heel voor de hand liggend, maar het komt nogal eens voor dat een project afhankelijk is van een library die niet in de solution is opgenomen, waardoor een linker error optreedt tenzij je de dependency handmatig vantevoren los bouwt. Niet fraai.

MyApplication

De solution is tevens owner van projecten die specifiek zijn voor MyApplication. In dit geval is de solution owner van MyApplication, MyApplicationLib en MyAppliationUnitTests. Generieke, herbruikbare projecten waar meerdere andere projecten gebruik van maken, zijn geen eigendom van deze solution. In dit geval is de solution geen owner van GenericLib.

Een project heeft in mijn optiek exact 1 owner. Deze owner is tevens de owner van de testprojecten. Wanneer je een project aanpast, dient dit te gebeuren vanuit de solution die daar owner van is, daar deze alle informatie bevat (testprojecten, voorbeeldapplicaties) om deze wijziging zorgvuldig te maken.

Omgekeerd bevat een solution nooit de testprojecten van projecten waar hij geen owner van is. Wanneer je voor project GenericLib en zijn testproject GenericLibUnitTests een solution hebt, is het niet nodig om in de MyApplication solution nogmaals GenericLibUnitTests mee te nemen.

MyApplication_GenericLibUnitTests

Deze tests worden namelijk al als onderdeel van de eigen solution uitgevoerd. Ze ook nog opnemen in MyApplication is redundant en leidt enkel tot vertraging in de build en tests van MyApplication.

GenericLib

Project

Een project bevat verschillende bestanden. Het project bevat alle en slechts die bestanden waar hij eigenaar van is. Dit zijn alle bestanden die het project nodig heeft om het project en haar tests te kunnen compileren en gebruiken.

Een bestand, heeft, evenals een project, in mijn optiek maar 1 owner en is derhalve slechts in 1 project aanwezig. Wanneer een bestand eigendom is van meerdere projecten, schendt dat de begrenzing tussen projecten. In zo’n geval zijn er twee opties: de beide projecten samenvoegen, omdat zij kennelijk niet op zichzelf staan, of de betreffende bestanden afsplitsen en inrichten in een nieuw project, waar beide oorspronkelijke projecten een afhankelijkheid op hebben.

Ownership

  • Een project is eigendom van exact 1 solution.
  • Wanneer een solution eigenaar is van een project, is deze solution tevens eigenaar van de testprojecten die tests voor dit project bevatten
  • Een solution bevat alle en slechts die testprojecten waarvan hij eigenaar is.
  • Een bestand is eigendom van exact 1 project.

Containment

  • Een solution bevat alle projecten waarvan hij owner is.
  • Een solution bevat alle projecten waarvan de projecten die hij bezit direct of indirect afhankelijk zijn
  • Een solution bevat geen andere projecten dan voorgenoemde.
  • Een project bevat alle en slechts die bestanden waarvan hij owner is.

Mappenstructuur

De structuur op disk zou in mijn optiek voorgenoemde verbanden tot uitdrukking moeten brengen:

  • De broncode bestanden zijn binnen een project in dezelfde structuur aanwezig als op disk. Op deze manier is zoeken van een bestand op disk eenvoudig. Mede hierom ben ik niet zo’n fan van ‘filters’ in Visual Studio en zet ik liefst ‘Show All Files’ aan.
  • In de map waarin een project zich bevindt en in de mappen daaronder staan alle en slechts die broncode bestanden waarvan dit project eigenaar is.
  • De map waarin de solution zich bevindt, bevat alle en slechts die projecten waar de solution owner van is.

Daarnaast heb ik zelf nog de voorkeur om elk project in een directory te plaatsen met een gelijke naam als dat project, en elke solution tevens in een map met een gelijke naam als deze solution.

tree

Documentatie

Dan nog een vraag: Waar laat je documentatie? Ik heb op dit moment een lichte voorkeur voor het plaatsen van documentatie in een aparte tree, naast je source code, met dezelfde mappenstructuur als je solutions en projecten.

Zowel developers als anderen voor wie de code niet direct relevant is (gebruikers, management, consultants, developers die een product ontwikkelen wat van jouw project afhangt), moeten in staat zijn documentatie snel en gemakkelijk te vinden. Voor zowel handgeschreven als autogegenereerde documentatie gaat denk ik dit argument op: Iemand die niets in de code te zoeken heeft, wil niet door een code base spitten en zoekt in termen van high-level concepten (informatie over een module, feature of applicatie). Als developer heb ik documentatie echter graag in dezelfde structuur als mijn code. Wat hier wel duidelijk uit wordt, is dat niet de code de structuur dicteert, maar de mensen: Iedereen die iets moet kunnen opzoeken in de code base danwel documentatie moet daarbij zo veel mogelijk geholpen worden door de structuur.

doc

Natuurlijk kan documentatie ook ondergebracht worden op een wiki of intranet. Ook daar zou ik geneigd zijn dezelfde structuur aan te houden als in de code base wordt gehanteerd.

Conclusie

Dit is hoe ik het zou doen en waarom. De meeste van deze keuzes worden impliciet door Visual Studio al voor je gemaakt wanneer je een nieuwe solution aanmaakt. Het komt echter voor dat code later pas wordt ingericht in projecten en solutions. Hoewel het niet altijd eenvoudig is een bestaande structuur aan te passen, zou ik er voor pleiten om naar deze indeling toe te werken en deze consequent toe te passen. Op die manier is voor elke developer, met name voor iemand die nieuw aanschuift in je team, duidelijk welke structuur hij/zij dient te handhaven in solutions en projecten en komen ownership en containment eenduidig tot uitdrukking in zowel je solutions als je directory structuur.

0 Replies to “Solutions, projects en mappen structuur”