Afhankelijkheden en hardcoded paden naar netwerkschijven

Het verbaast me zeer dat ik niet meer artikelen kan vinden over dit onderwerp.

Ik kan me haast niet indenken dat ik de enige software engineer ben die dependency management van de vorm “Het staat ergens op de K: schijf” tegenkomt. En toch, een online zoektocht brengt me enkel naar een artikel van Sonatype wat vervolgens hun Nexus repository manager aanprijst.

In ons geval gebruiken we environment variabelen voor al onze builds… dacht ik althans. Vorige week kwam ik een project tegen wat hier vanaf week: Er werd expliciet een tool op de K: schijf aangeroepen en er werd gelinked tegen libraries op die schijf. Dat niet alleen, er werden geen environment variabelen gebruikt, maar een hardcoded pad naar de netwerkschijf was opgenomen in het build script en de VS project instellingen.

Ik liep hier tegenaan toen ik een build configuration voor dit project wilde toevoegen aan TeamCity. De build faalde omdat ik onze TeamCity server geen toegang heb gegeven tot onze netwerkschijven. En waarom zou ik? Onze netwerk schijf bevat een hoop dingen, de meesten hebben niets te maken met het builden van onze sochtware. Ik zou het niet nodig vinden dat iemand of iets wat daar niet hoeft te zijn, toegang krijgt. IK heb de TeamCity build configurations zo ingericht dat alle dependencies in D:\Dependencies op de build server staan en heb de environment variabelen ook dusdanig ingesteld. Wanneer een dependency wordt toegevoegd aan een project, voeg ik deze toe aan D:\Dependencies en stel ik de environment variabelen van de projecten/builds in. Ik gebruik dezelfde aanpak op mijn lokale machine overigens, maar dat terzijde.

Maargoed, ik kon dit project dus niet builden. Dit is het eerste project in velen wat niet buildde en ik kwam er dus achter dat het toegang zocht tot de netwerkschijf, waar onze build servers geen toegang toe hebben. Kunnen we de netwerkschijf niet gebruiken? Is dat zo erg dan?

Build artifacts

Gebruik van netwerkschijven om build artifacts op te plaatsen ben ik eerder tegengekomen en ik denk niet dat dat zo’n probleem is. Bij gebruik van TeamCity, kan ik specificeren dat een build artifacts creeert. Vervolgens stellen we een additionele build step in die deze artifacts naar een netwerkschijf kopieert, geen probleem. Maar, en dit is het mogelijke probleem en meteen ook de oplossing: Als de netwerkschijf onbereikbaar is, kan de build nog steeds worden uitgevoerd en de artifacts kunnen handmatig uit TeamCity worden gedownload. Er iets om op terug te vallen.

Build dependencies

Echter, als het op build dependencies aankomt, kunnen problemen de hele build blokkeren. Bijvoorbeeld, wat als de netwerkschijf onbereikbaar is of het netwerk eruit ligt? Als zowel je continuous integration server als je ontwikkelaars niet kunnen werken op hun lokale machines, omdat compileren een verbinding met de netwerkschijf vereist, komt ontwikkeling tot stilstand wanneer de netwerkschijf of het netwerk er uit liggen.

Zelfs als de netwerkschijf wel benaderd kan worden, kan het zijn dat het niet mogelijk is twee builds tegelijk te draaien. Dat betekent dat als meerdere ontwikkelaars het project lokaal willen builden, wellicht parallel met een continuous integration server, er conflicten op kunnen treden en ze elkaar blokkeren.

Why risk that?

Hardcoded paden

Hardcoded paden naar build dependencies betekent dat je de dependency effectief hebt vastgesnoerd op deze locatie. Je kunt hem niet verplaatsen, tenzij je handmatig al je projecten nagaat en hun paden weer aanpast. Ik heb situaties gezien waarbij een tool zich op locatie PAD/NAAR/TOOL/1.03 bevond, maar de tool in deze map versie 2.5 was! De ontwikkelaar verwijderde bij een update van de tool alles uit map “1.03” en verplaatste de nieuwe versie hierheen.

Ik zie geen reden om hardcoded paden te prefereren boven environment variabelen.

Conclusie

Het punt wat ik wil maken: beperk de locatie van dependencies tot je versiebeheersysteem en lokale schijf. Gebruik netwerk variabelen om ervoor te zorgen dat het verplaatsen van dependencies (of upgraden ervan) een simpele procedure is. En wijk niet van deze aanpak af tenzij je een hele, hele goede reden hebt waarom het hardcode van een pad naar een netwerkschijf benodigd is en de voorkeur heeft boven het gebruiken van een environment variabele of relatief pad in je versiebeheersysteem.

Ik ben een paar ontwikkelaars tegengekomen die me een beetje gek aanstaren en zeggen “Waarom maak je je druk over zoiets onbenulligs?”. En misschien hebben ze een punt, ik maak me nogal druk om de kleine dingen(*). Aan de andere kant, veel kleine dingen maken een grote. “Wat doet het ertoe als dit ene project hardcoded paden naar een netwerkschijf heeft?” zou weleens zoveel kunnen betekenen als “Wij hebben geen richtlijnen over hoe de structuur van onze repository en onze dependencies moet zijn”. Als je projecten hardcoded paden hebben naar god-weet-waar, dan kun je het woord “management” gerust wegstrepen uit “dependency management”. Dat niet alleen, het betekent ook dat je in de problemen raakt zodra iemand besluit wijzigingen te maken aan het netwerk. (Denk: Laten we deze netwerkschijf alleen toegankelijk maken voor administratie en een nieuwe schijf maken voor de ontwikkelaars”. Ik geef er de voorkeur aan dit soort dingen meteen aan te pakken. Ik heb de ontwikkelaar van het betreffende project gevraagd een environment variabele te gebruiken, zodat alle dependencies van alle build configurations van onze continuous integration server op dezelfde manier worden beheerd.

(*) Zoals: Een web applicatie die standalone kan worden gedraaid hoort niet de suffix ‘Lib’ te hebben, het is geen library.