Werken aan Legacy Codebases (of het leven van een aannemer) (Nederlands (Dutch))

Werken aan Legacy Codebases (of het leven van een aannemer)

Comments

NOTE: Apart from English (and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.

Wednesday, 06 November 2024

//

Less than a minute

Inleiding

Als freelance ontwikkelaar is een van de vaardigheden die je snel moet leren hoe je effectief kunt werken aan bestaande codebases. Ik heb geluk gehad met het bouwen van een aantal van--krab systemen; dit is een JOY als een ervaren ontwikkelaar maar het is niet altijd het geval.

De uitdagingen

Legacy systemen hebben belangrijke uitdagingen; vooral wanneer de belangrijkste ontwikkelaars / architecten (als je geluk hebt genoeg om ze te hebben) zijn gegaan.

Documentatie

Dit wordt vaak over het hoofd gezien, vooral in kleinere bedrijven. In het algemeen heb je 4 belangrijke soorten documentatie nodig:

  1. Nieuwe gidsen voor ontwikkelaars dus hoe voer je het project uit lokaal (meer hierover in een minuut), welke overwegingen zijn er (als je bijvoorbeeld een ander kader nodig hebt dan de huidige, vooral waar met Node jammer genoeg).
  2. Implementatiedocumenten in deze dagen wanneer CI/CD wordt gezien als de gouden standaard van implementatie wordt vaak over het hoofd gezien dat je moet weten hoe je het systeem handmatig in te zetten. Dit is vooral waar als je werkt aan een systeem dat al een tijdje bestaat en veel handmatige stappen heeft.
  3. ProbleemoplossingsproceduresWat doe je als het systeem uitvalt? Wie bel je? Wat zijn de belangrijkste dingen om te controleren? Dit wordt vaak over het hoofd gezien, maar is CRUCIAL in een productiesysteem.
  4. Architectural / System-Design Docs; hoe werkt het systeem? Wat zijn de belangrijkste componenten? Wat zijn de belangrijkste afhankelijkheden? Zie dit als je roadmap bij het leren van een nieuw systeem. Het geeft een overzicht op hoog niveau van hoe het systeem werkt dat kritisch kan zijn (vooral in grotere, gedistribueerde systemen). Dit moet bevatten welke broncode repositories worden gebruikt, welke CI/CD systemen worden gebruikt, welke databases worden gebruikt voor elk element van de toepassing. Dit kan alles omvatten van een eenvoudig diagram tot een volledig UML-diagram van elk onderdeel van het systeem. Bijvoorbeeld in een React Application zou dit meestal een diagram van de componenten en hoe ze interactie met elkaar en elke backend diensten. In een.NET Core applicatie zou dit een diagram van de services bevatten en hoe ze met elkaar omgaan (en de front end & andere backend systemen) en mogelijk ASP.NET Views en welke diensten ze kunnen gebruiken.

Documentatie is een van de dingen die we als ontwikkelaars vaak haten doen (het is NIET code) maar het is cruciaal. Zoals je kunt zien I LOVE Markdown, met de likes van Mermaid en PlantUML kunt u een aantal echt mooie diagrammen en stroomschema's die kunnen worden opgenomen in uw documentatie.

Het moet LOPEND zijn; ontwikkelaars praten vaak over bit-rot; waar de afhankelijkheden van een project verouderd / ronduit beveiligingsrisico's worden. Dit geldt ook voor documentatie; als het niet actueel is is het niet nuttig.

Er zijn verschillende niveaus van documentatie, maar in het algemeen wanneer u een code wijzigt waarnaar in een document wordt verwezen, moet u dat document bijwerken.

Lokaal draaien van het systeem

Dit is vaak een uitdaging, vooral als het systeem al een tijdje bestaat. Je moet weten welke versie van Node /.NET etc., welke versie van de database, welke versie van het kader etc. Dit wordt vaak over het hoofd gezien, maar is CRUCIAL om snel op te staan en te draaien.

Ik heb ontwikkelaars vaak zien zeggen dat dit niet relevant is in deze dagen van cloudsystemen en grote gedistribueerde toepassingen, maar ik ben het oneens; je moet het systeem lokaal kunnen draaien om problemen snel en effectief te debuggen.

  1. Profilering - dit lijkt een 'advanced developer only' vaardigheid te zijn geworden, maar het is cruciaal om je code te kunnen profileren om te zien waar de knelpunten zijn. Dit is vooral waar in een legacy systeem waar u misschien niet de luxe van het kunnen herschrijven van het systeem vanaf nul. Hulpmiddelen zoals dotTrace en dotGeheugenHier zijn ze van onschatbare waarde. Vooral in ASP.NET toepassingen; de grootste problemen zijn over het algemeen 'leaks' in het systeem; geheugenlekken, verbindingslekken etc. Terwijl uw app lijkt te draaien FINE voor een beetje je plotseling vindt het crashen / het gebruik van al het geheugen op de server.
  2. Het vinden van problemen in de debugger - Vind het leuk of niet de dagen van Response.Write Classic ASP is voorbij. Voor een zelfs bescheiden complexe toepassing (vooral degene die je niet hebt geschreven) is het cruciaal om 'door te stappen' code. Om een verzoek te volgen vanaf het begin door middel van de dienst om te identificeren wat er kan gebeuren, welke uitzonderingen niet kunnen worden gevangen etc.
  3. Loggen - Nogmaals vaak over het hoofd gezien (sorry maar geen ASP.NET Core uitzondering filter aan de bovenkant van de stack is niet genoeg). Terug verwijzend naar mijn vorige post, logging is een cruciaal onderdeel van het werken in code LOKAAL. Vergeet niet dat u gebruik kunt maken van klant logging types (bijvoorbeeld met behulp van de Brongenerators loggen) in ASP.NET Core. U kunt dan aangeven welke gebeurtenistypes moeten worden aangemeld en welke niet. Dit is cruciaal in een legacy systeem waar u misschien niet de luxe van het kunnen herschrijven van het systeem vanaf nul. Voor Application Insights wilt u wellicht User Journeys en andere functies; echter wees bewust Dit wordt snel duur. als u LogInformation voor elk verzoek. U kunt een aangepaste Telemetrie Processor gebruiken om verzoeken te filteren die u niet wilt aanmelden.
  4. Testen - Te vaak zie ik ontwikkelaars 'testen in preprod' of denken dat Unit Test dan inchecken is ENOugh in termen van testen. De RARELY IS, er is veel waarde in beide met behulp van een hulpmiddel zoals Resharper / NCrunch om automatisch unit tests uit te voeren; echter vergeet niet Unit Tests zijn gewoon dat; ze testen een 'eenheid' van code. Je moet zicht behouden in de manier waarop het systeem werkt in concert met andere componenten. Hier komen integratietests binnen; zij testen hoe het systeem als geheel functioneert. U kunt gebruik maken van een hulpmiddel als SpecFlow om deze tests in een menselijk leesbaar formaat te schrijven. Nogmaals; cruciaal in een legacy systeem waar u misschien niet de luxe van het kunnen herschrijven van het systeem vanaf nul.

In elk project werk ik aan de eerste stap is het krijgen van het systeem (of een groot deel ervan) lokaal draaien. Door het zien van de code, het uitvoeren van de code, het debuggen van de code kunt u een gevoel voor hoe het systeem werkt.

De Codebase

In elk systeem is dit uw bron van waarheidHet maakt niet uit wat de dokters zeggen, wat anderen je vertellen over hoe het zou moeten werken, dit is hoe het werkt.

Een Legacy Codebase navigeren

Deze vaak uitdagende, het is als het vinden van uw weg in een nieuwe stad zonder routekaart. Gelukkig in toepassingen heb je een ingang (een pagina laden / een front end API call etc.) Kies een punt en begin daar.

Gebruik wat je nodig hebt om ermee te communiceren, of het nu PostMan, Rider's HttpClient of zelfs een webpagina is. Haak je debugger in, bel en volg het. Spoel en herhaal voor elk deel van het systeem.

Refactoring

Over het algemeen laat je dit tot je het systeem begrijpt. Het is altijd verleidelijk om 'het weg te gooien en opnieuw te beginnen' maar weerstaan deze verleiding. Speciaal voor een draaiend systeem Het werkt. reconstructie / zelfs refactoring van een systeem is een groot risico. Ja, het is FUN maar voor elke regel code die je verandert riskeer je nieuwe snd spannende bugs te introduceren.

Net als al het andere (vooral bij contracteren) moet je het werk dat je op een systeem uitvoert rechtvaardigen. Ofwel moet deze rechtvaardiging worden gericht op een van de volgende:

  1. Prestaties - het systeem is traag en moet worden versneld (wees voorzichtig, wat U langzaam vindt kan zijn hoe het systeem is ontworpen om te werken). Een deel snel roken kan problemen verder in het systeem introduceren. Ga je de databaseserver'vermoorden', als je te veel verzoeken doet, heb je dan een mechanisme dat geen cascading uitzonderingen veroorzaakt?
  2. Veiligheid - het systeem is onzeker en moet beveiligd worden. Dit is een lastige; vooral in een legacy systeem. Met bit-rot kunt u merken dat het systeem gebruik maakt van oude versies van bibliotheken die beveiligingsproblemen hebben gekend. Dit is een goede rechtvaardiging voor werk; maar wees je ervan bewust dat je mogelijk een LOT van het systeem moet refactoreren om het up-to-date te krijgen; opnieuw leidend tot de 'nieuwe bugs' kwestie.
  3. Behoudbaarheid - het systeem is moeilijk te onderhouden en moet gemakkelijker onderhouden worden. In het algemeen wordt dit een hoop werk; rechtvaardigt de huidige levensduur van de codebase dit? Als je meer tijd besteedt aan het maken van deze wijzigingen om de onderhoudbaarheid te verbeteren dan je ooit zou sparen voor de klant dan is het het niet waard (en opnieuw, veranderde code == nieuwe bugs).
  4. Gebruikerservaring - Over het algemeen geef ik prioriteit aan deze kwesties. Voor een gebruiker Het maakt niet uit of je code 1% beter is; zij zijn degenen die betalen voor het werk dat je uiteindelijk doet. Als je hun ervaring beter kunt maken dan het in het algemeen waard is. Wees je er echter van bewust dat dit een'slipperige helling' van veranderingen kan zijn; je kunt merken dat je een LOT van het systeem aan het veranderen bent om een kleine verandering te maken voor de gebruiker.

Het bedrijf van het werken op Legacy Systems

Dit wordt vaak over het hoofd gezien, vooral door ontwikkelaars. Je moet in staat zijn om het werk dat je doet op een systeem te rechtvaardigen. Dit is vooral waar in een contracterende omgeving waar je per uur betaald wordt. Uiteindelijk is het niet jouw code en niet jouw geld. De Why you're make a change is vaak belangrijker dan de verandering zelf.

Ik werk nu al meer dan tien jaar als aannemer, het is niet EASY; als aannemer elk uur van uw tijd is een 'kosten' voor de klant. U moet verplaatsen waarde toe te voegen aan het systeem dan u kosten. Als je dat niet bent, ben je snel op zoek naar een nieuw contract.

Als ontwikkelaars, hebben we de neiging om slechte zakenmensen te zijn we zijn gefocust op 'perfectie' bij elke beurt. In werkelijkheid hoef je geen systeem 'perfect' te maken (ik zou beweren dat zoiets niet bestaat); je hoeft alleen maar waarde te leveren aan de klant.

Dit houdt in dat op langere termijn moet worden gezorgd voor: nieuw code is onderhoudbaar en kostenefficiënt om te draaien. In legacy systemen is dit veel moeilijker. Je moet vaak waden door een moeras, angstig dat als je het systeem leert je niet veel waarde bieden. I'm not making any changes Denk je dat... I'm just learning the system. Dit is een misvatting; je leert het systeem om het beter te maken. Je leert het systeem om het efficiënter te maken. Je leert het systeem om het onderhoudender te maken. Als een klant deze stap niet kan accepteren, dan moet je heel voorzichtig zijn met hoe je dit communiceert (of op zoek bent naar een nieuw contract).

Het volk

Nogmaals vaak over het hoofd gezien, een groot deel van de tijd dat je wordt gebracht als een aannemer omdat een sleutel persoon is vertrokken (raak niet betrokken in de politiek van deze; het is niet uw zorg). Je moet kunnen werken met de mensen die er zijn om de doelstellingen van het project te bereiken. In een contract heb je over het algemeen de voorwaarden van je engagement uitgewerkt (in mijn huidige contract is het'verbeter de betrouwbaarheid en verminder de lopende kosten'); focus hierop. Als je niet zeker weet wat dit betekent dan ASK.

Houd in gedachten wie uw directe contact is; vooral in de eerste paar maanden. Hou ze op de hoogte (je zult waarschijnlijk geen nieuwe functies hebben om over op te scheppen als je opgezwollen wordt over hoe het systeem werkt). Ik stuur over het algemeen een samenvatting e-mail elke week / twee weken naar mijn directe contact; dit is een goede manier om hen op de hoogte te houden van wat je doet en wat je vindt.

Vergeet niet, dit is de persoon die uw factuur zal goedkeuren; er moet geen verrassingen op factuurtijd. Zodra je regelmatig begint met het controleren van code is dit minder een probleem; je hebt een record van precies wat je deed en de impact die het had. Tot die tijd moet je ze op de hoogte houden. Ze moeten weten wat je gedaan hebt en waarom ze je ervoor moeten betalen.

Betrouwbaarheid

Nogmaals, terug naar de legacy code; als je een verandering in het algemeen moet je het implementeren.Zelfs de beste van ons zal FUCK DIT up van tijd tot tijd, vooral in legacy code systemen zal er iets Je kon het niet weten. Als je klaar bent. Dit gaat terug naar loggen - als je een staging server hebt, laat het dan een LOT loggen (maar voor een korte periode behouden) dan kun je bij het implementeren naar DIT meer informatie verzamelen over wat mislukt is.

Hoe goed je ook bent, hoeveel lokale testen je ook gedaan hebt... we zijn allemaal mensen. Dit is een belangrijk onderdeel van de 'niet inzetten op een vrijdag' regel; verwacht een implementatie om een nieuw probleem op een systeem te veroorzaken. Wees bereid om te werken tot het opgelost is. Als je niet weet waarom het mislukt is, voeg dan meer tests toe om het probleem te reproduceren en meer logging om ervoor te zorgen dat je soortgelijke problemen in de toekomst opvat.

Speciaal voor productiesystemen kan uw staging systeem niet 1:1 zijn (vooral als het belasting betreft), gereedschap zoals k6 kan u helpen bij het simuleren van belasting (nog beter lokaal waar u de juiste profilering kunt doen zoals eerder vermeld).

Implementatie

Wederom vaak over het hoofd gezien in de ijver voor CI/CD is de Why van deze. Simpel, je zult het verknallen. Het hebben van een zeer snelle en efficiënte manier om een systeem in te zetten betekent dat wanneer u het DO break kunt u het ook sneller repareren. Als uw CI code beoordeling systeem betekent dat het duurt 2 dagen om een PR samengevoegd dan is dat de snelste u redelijk fi een systeem. Als uw CD-systeem betekent dat u het draaiende systeem uit te schakelen; wen aan LANGe nachten.

Een efficiënt mechanisme om code vast te stellen en in te zetten is essentieel voor een efficiënte ontwikkelingspijplijn. Als het langer duurt om een fix te implementeren dan het duurde om die fix in code te vinden en implementeren dan ben je minder waarschijnlijk om dingen te repareren.

'Fixing Legacy Apps'

Ik zet dit in citaten omdat dit een probleem is; voor legacy toepassingen (vooral wanneer grootschalige herwerken is buiten de grenzen) is er twee belangrijke benaderingen.

  • Patches uitvoeren

Dit is het proces van simpelweg vast te stellen bestaande code; opnieuw ervoor zorgen dat u grondig te testen en hebben processen op zijn plaats om terug / snel opnieuw in te zetten eventuele fixes. Ik zal niet liegen dat dit soort ontwikkeling zelden FUN is omdat je waarschijnlijk nog steeds door het moeras van de bestaande codebase waden. Echter, het is een noodzakelijk kwaad in veel gevallen.

Zoals gewoonlijk moet u ervoor zorgen dat u enige vorm van test om de huidige code uit te voeren hebben; idealiter moet het ook testen op falen voor het probleem dat u probeert op te lossen voordat u de oplossing te maken . Ze IDYLL voor dit is om een eenheid test die gericht is op het gebied van code die u nodig hebt om op te lossen, maar dit is vaak buiten het bereik van het werk voor grote, gedistribueerde systemen.

Ik zou meestal gebruik maken van een systeem van tests in deze volgorde van voorkeur:

  1. Unit Tests - opnieuw deze hebben de voorkeur omdat u deze kunt richten om alleen de code waar u aan werkt te oefenen. Echter, in een legacy systeem zijn deze vaak niet aanwezig & zeer moeilijk te retrofitten (bijvoorbeeld in een systeem met veel externe oproepen / dat is rommelig in hoe het constructeert; niet het gebruik van DI bijvoorbeeld).
  2. Integratie Tests - Dit is een overbelaste term omdat het alles kan dekken van een eenheid test die door meerdere lagen code (deze worden het best vermeden) aan het gebruik van de likes van de uitstekende Verifiëren door zelfs tot Selenium testen. In het algemeen wil je het systeem als geheel testen; maar wees je ervan bewust dat deze tests langzaam en broos kunnen zijn. Het gebruik van Verify kan vaak een geweldige benadering zijn voor legacy systemen omdat je tenminste'verifiëren' dat je het API-oppervlak van het systeem niet breekt.
  3. Handmatige Tests - Elke ontwikkelaar moet proberen en uitvoeren handmatige testen voor elke code checkin. Dit zorgt er alleen maar voor dat wat je verwacht dat de 'gebruiker' (dit kan een werkelijke gebruiker of een ander onderdeel van het systeem interactie met uw code) te zien is wat ze eigenlijk zien. Dit kan zo eenvoudig zijn als het lokaal draaien van het systeem en het controleren van de output van een pagina of zo complex als het uitvoeren van een volledige reeks testen op een staging server.
  • Skinning van de uien Voor het werken aan legacy systemen heb je over het algemeen niet de luxe van een compleet herwerk. Hier gebruik ik de 'onion skinning' benadering.

Om u in staat te stellen PARTS van een systeem te upgraden kunt u componenten identificeren die van een bestaande monoliet kunnen worden opgesplitst in een microservice (voor een bepaalde waarde van'micro'). Dit kan een geweldige manier zijn om een systeem te moderniseren zonder het risico van een volledige herwerking. Gemeenschappelijke voorbeelden kunnen zijn het splitsen van API-eindpunten in nieuwe projecten die meer bijgewerkte elementen gebruiken. De terreur van DRY kan hier echter in het spel komen. Een slecht gestructureerde oplossing heeft vaak veel 'helper' of'service' componenten die echt in verschillende projecten zouden moeten zitten (of zelfs in nuget pakketten voor meer wereldwijd hergebruik).

Ik zal deze aanpak verder behandelen in een toekomstig artikel omdat het een belangrijk element is van hoe ik werk op legacy systemen & niet duidelijk voor veel ontwikkelaars.

Betaald krijgen

Nu we dit allemaal hebben, komt het lastige probleem van de betaling. Ik heb een algemene regel:

Eventuele betalingsproblemen die ik op zoek ben om verder te gaan

Als ze te laat betalen; hangt af van uw contract maar op LEAST binnen 30 dagen maar over het algemeen dichter bij 7; dit is een slecht teken. Als er quibbles over uw factuur (nickle-and-dimeing) na te denken over de vraag of het bedrijf in staat is om te betalen voor uw diensten op een permanente basis.

Als je je werk hebt gedaan, moet je tijdig betaald worden. Het maakt niet uit hoeveel je ervan geniet; als een slechte klant je kan exploiteren zullen ze dat doen. Het is het nooit waard.

Wees eerlijk; alleen kosten voor de tijd die je eigenlijk werkte; zorg ervoor dat het duidelijk is wat je deed en waarom je het deed.

Ik heb teams van ontwikkelaars geleid en ik ben ontwikkelaar geweest, ik ben aannemer geweest en ik ben klant geweest. Ik heb dit allemaal gezien en ik kan het je vertellen, als je niet op tijd betaald wordt dan moet je verder gaan. Aan de flip-side als je een aannemer (of een VTE) die niet levert dan moet je dit snel aanpakken. Iedereen heeft persoonlijke worstelingen, maar vooral in een contractomgeving moet je waarde leveren of niet opladen voor tijd wanneer je dat niet bent.

Zoals voor tarief; vindt u uw niveau; persoonlijk reken ik meer voor projecten waar ik meer verantwoordelijkheid heb (of die er niet leuk uitzien). Ik reken minder voor projecten waar ik een nieuwe technologie leer of voor startups. Ik heb ook minder dagen gewerkt maar hield mijn tempo stabiel. Maar accepteer geen low-ball tarief; je bent een professional en je zou als zodanig betaald moeten worden.

Conclusie

Nou, dat is het. Ik ben vrij vandaag en morgen voor mijn oma's begrafenis en eerlijk gezegd in paniek een beetje dat ik een HUGE legacy systeem te leren, dus ik dacht ik uit te geven mijn gedachten over wat werken op deze systemen is als & de uitdagingen.

logo

©2024 Scott Galloway