Fremkomst af kode 2019 og hvordan jeg lærte at elske fortrolighed

Som en årlig tradition for mig tog jeg en kniv ved programmets udfordring med advent af kode i hele december. Det har altid været en mulighed for mig at enten teste mig selv for at prøve, hvad jeg havde lært gennem året.

I en del af 2019 på mit tidligere arbejde brugte vi et PowerShell-script til at bygge og implementere det program, vi arbejdede på. Nogle af dens funktioner var arv, da jeg kom med, da du nu kan køre flere projekter samtidig i Visual Studio direkte. Ét funktionalitet, som det havde, var at implementere til en instans, som kvalitetssikringsteamet kunne evaluere, og et problem med det er, at det vil prøve at skrive over det allerede kørende eksempel og en fejl delvist. Make-shift-løsningen, da jeg tiltrådte, var bare at manuelt slette filerne i mappen QA-instans (forsøg flere gange på filer var stadig i brug) og derefter prøve igen. En hurtig og lidt hacky fix, som jeg foreslog og implementerede, var bare at prøve igen den del af scriptet, indtil det med succes fungerede, hvilket syntes at forenkle vores arbejde ret.

Dette var den første smag af PowerShell, jeg virkelig havde oplevet. Bagefter gjorde jeg virkelig ikke så meget; Jeg introducerede lige en variabel og en hvorfor for at bestemme, om alle filer med succes blev offentliggjort, og væk gik jeg. Jeg vidste imidlertid, at jeg overhovedet ikke vidste meget om PowerShell, og at jeg skulle lære at bruge det bedre i fremtiden.

Spol frem til december; advent af kodedag 1 var ude, og jeg var klar til at prøve mig selv på en ny måde ved at forsøge at gennemføre så mange udfordringer som muligt ved hjælp af PowerShell. Den første udfordring syntes enkel nok; udfør en handling på hvert nummer på en liste, og tilføj dem alle sammen. Jeg vidste, at jeg kunne gøre dette næsten trivielt på ethvert andet sprog, men fordi PowerShell var ny for mig, var jeg nødt til at starte fra bunden.

For det første havde jeg brug for at oprette et slags miljø. For den første dag vidste jeg virkelig ikke, hvad mere jeg havde brug for, så min codebase var simpelthen to manuskripter; en for hver del af den første dags udfordring.

Min kode var enkel nok, da jeg lærte om Get-Content, hvordan man laver en funktion og hvordan man i det mindste repræsenterer værdien på skærmen, skønt jeg ikke fuldt ud forstod, hvorledes det at angive $ TotalMass i slutningen virkelig påvirkede det samlede programmets tilstand. Alt, hvad jeg vidste, var, at jeg i det mindste dyppede mine tæer i PowerShell, og jeg var klar til at fortsætte med at lære nye ting.

Jeg ville også introducere enhedstestning i mit arbejde. Det var sandsynligvis overdrevent i starten, men jeg tror, ​​at beslutningen om at begynde at tilføje test så tidligt var sandsynligvis til det bedre, da det førte mig til at skabe løsninger, der havde til formål at passe til testene. Heldigvis havde mange af udfordringerne eksempler, der effektivt var test. For denne første dag var testen kun på et par isolerede tal og ikke en fuld liste over dem, så jeg forsøgte at erstatte argumenter i scriptet, så du kunne specificere enten en fil eller bare et enkelt nummer.

Enter Pester: muligvis det enkleste og overraskende kraftfulde testværktøj, jeg nogensinde har været vidne til. Denne PowerShell-baserede testsuite giver dig mulighed for at skrive meget enkle testtilfælde ved blot at pipppe output fra et program til en speciel metode, der sammenligner resultatet. Da det fungerer gennem rørføring, kan du effektivt skrive ved hjælp af ethvert sprog eller værktøj, og så længe det udsendes, kan du bare sammenligne, at det matcher dit forventede resultat. Jeg satte op ganske mange og bundede det hele til GitHubs nye Actions-funktion for effektivt at integrere CI i mit lager. Igen er det sandsynligvis overdreven overvejelse af, at dette er et enkeltpersonlager, som ikke vil blive arbejdet på efter denne måned, men det var en god mulighed for at støde på nogle værktøjer, som jeg muligvis vil bruge i fremtiden.

Dag 2 var dog lidt af en kurvebold, det var et program, der måtte fortolke denne bytecode (eller intcode, som de nævnte det, fordi teknisk set var værdierne repræsenteret som heltal) -program. For denne ene, var jeg nødt til at beskæftige sig med, mens løkker og arrays, begge var lidt ustabile. Pludselig skulle jeg nu bare bruge almindelig .NET-funktionalitet oven på min ellers PowerShell-kode. For eksempel havde jeg brug for at læse input som en enkelt streng og opdele det på hvert komma, og den nemmeste måde at gøre det på var nøjagtigt den samme syntaks som at gøre det i C #.

Men det var dag 3, at jeg begyndte at blive lidt bekymret over, hvordan jeg nærmede mig PowerShell-koden. Til denne udfordring fik du stierne til to ledninger som en liste over retninger og afstande, og du var nødt til at bestemme det nærmeste skæringspunkt. Min øjeblikkelige tilgang var at oprette en funktion, der bestemte, hvor alle skæringspunkterne var, og derefter en funktion, der, givet en sti, beregner hvor lang tid på tværs af den sti, hvor krydset var.

Det var på dette tidspunkt, at jeg indså, at PowerShell var meget anderledes end hvad jeg oprindeligt troede, at det var. Jeg vidste, at jeg ville genbruge denne metode til at finde skæringspunkterne til begge stier, så jeg vidste, at jeg kunne generalisere den til en funktion med et argument, hvor du passerer stien i. Det, jeg ville returnere, var det heltal af trin det tog at nå et givet punkt. Men min funktion returnerede ikke noget, og senere kom dele af koden i panik, fordi de ikke kunne arbejde med et nul. Jeg gik tilbage til den funktion og tilføjede nogle trykte udsagn, så jeg vidste, hvad det gjorde. I stedet returnerede min funktion nu en boolsk. Ikke nyttigt, men det var nysgerrig opførsel. Det, der var underligt, var, at funktionen så ud til at beregne værdien korrekt, men den kunne ikke korrekt returnere den. Tilføjelse af udskrivningssedler ændrede, hvad funktionen returnerede. Efter nogen lang søgning fandt jeg ud af, at problemet var, at funktioner ikke vender tilbage så meget, som de rør ud. Dette forklarede, hvorfor de trykte udsagn brød det, men det forklarede ikke, hvorfor min værdi ikke vendte tilbage. Jeg er stadig ikke 100% sikker på, hvorfor det ikke returnerede, hvad jeg ville have det, men det blev meget frustrerende at fortsætte med at arbejde med det, især da jeg ville følge med på de daglige udfordringer.

Uden andet at gætte, besluttede jeg bare at skrive en løsning i C #, som har været mit goto-sprog i ganske lidt nu. Løsningen kom naturligt til mig, da det næsten var præcis, hvad jeg havde tænkt på før. Faktisk blev min løsning til første del næsten udelukkende gjort med simpel LINQ-funktionalitet; få alle koordinater, der er dækket af begge stier, krydse dem og find minimumsværdien. For at afslutte det, migrerede jeg arbejdet i de foregående dage (hvilket var meget enkelt uanset) og implementerede testen igen ved hjælp af Xunit.

Hvad siger dette skridt om mig selv for at se introspektivt? Et naivt svar ville være, at jeg tog den lette vej ud og ikke ønskede at udfordre mig selv mere, selvom jeg helt sikkert kunne argumentere for, at nogle af de senere dage (især dag 18 med nøgledør-labyrinten) var meget vanskelige uanset at bruge et sprog, jeg var vant til. Jeg synes, at en mindre beskyldende måde at se på dette er, at jeg indså, at udfordringen, jeg oplevede, var mere semantisk og specifik og mindre teknisk og programmatisk. Jeg prøvede ikke at løse problemet, så meget jeg kæmpede med værktøjssættet, jeg var nødt til at sætte det i handling. Hvis jeg i stedet ville begrænse mig til sidstnævnte, ville jeg have skiftet alt til C, hvor jeg ikke kan stole på lette værktøjer som dynamisk skalering af arrays eller hashsets.

Og bestemt følte jeg, at bevægelse mod C # var et godt skridt bare på grund af omfanget af senere udfordringer. Den intcode-tolk blev ved med at udvikle sig hver anden dag, og mange udfordringer ville effektivt give et program, som du skulle arbejde omkring for at finde en løsning. De udfordringer, der krævede, at du kørte flere på samme tid, var ret interessante, især da hver tolk havde brug for at håndtere input og output. Jeg implementerede dette med tråde og lambdas, hvilket bekvemt betød, at jeg havde en generel klasse for disse intcode-problemer fra dag 9 og fremefter, og alt hvad jeg havde brug for var at manipulere, hvordan I / O arbejdede omkring det. Det betød også, at jeg let kunne målrette mod specifikke funktioner til test, hvis jeg ville (selvom jeg var overrasket over, at de fleste af problemerne ikke havde så mange eksempler senere).

Dette bør dog ikke betragtes som en rip på PowerShell; det har bestemt givet mig en anstændig smag på, hvad jeg kan og ikke kan gøre med det, og hvornår jeg skal bruge det. Jeg er glad for, at jeg havde en dedikeret klasse til at fortolke det tilbagevendende intcode-problem i stedet for at skulle manuelt bruge det hver gang, eller på en eller anden måde henvise til det på et fælles sted. Jeg synes, det ville være meget fint at bruge PowerShell til mindre opgaver, som ikke skal skaleres, og især på Windows-systemer, hvor du ikke bare let kan installere Python eller sådan. Pester er også temmelig pæn, og jeg ville ikke have noget imod at skrive prøver til den underlige ting på noget andet sprog.

Men teoretisk set kunne du sandsynligvis gøre alt, hvad du ville i PowerShell. Det, der irriterede mig ved det, var, at jeg effektivt refererede til .NET-biblioteker direkte i stedet for at være i stand til at skrive rene PowerShell-ting. Det føltes mere naturligt at bare hoppe skib og skrive rent på ét sprog i stedet for en blanding af begge i dette scenarie. Og i sidste ende følte jeg, at det var mere vigtigt at lære, hvordan man løser udfordrende problemer med nye algoritmer snarere end at smide nye værktøjer i blandingen.