Adveniment del Codi 2019 i Com vaig aprendre a estimar la familiaritat

Com a tradició anual meva, vaig fer un cop de puny en el repte de programació Advent of Code durant tot el desembre. Sempre ha estat una oportunitat per a provar-me per posar a prova el que havia après durant l'any.

Durant una part del 2019 en el meu treball anterior, hem utilitzat un guió de PowerShell per construir i desplegar el programa que estàvem treballant. Una part de la seva funcionalitat era una herència quan em vaig incorporar, ja que ara podeu executar diversos projectes simultàniament a Visual Studio directament. Una de les funcions que tenia es desplegava a una instància per a que l’equip d’assegurament de qualitat l’avalués, i un problema amb ella és que s’intentaria escriure parcialment sobre l’instància i l’error que ja s’executaven. La solució make-shift quan em vaig unir era només eliminar els fitxers de la carpeta d’instància de QA (intentar-ho diverses vegades en fitxers encara en ús), i tornar a intentar-ho. Una solució ràpida i lleugerament pirata que vaig suggerir i implementar va ser tornar a intentar aquella part del guió fins que funcionés amb èxit, cosa que semblava simplificar una mica el nostre treball.

Aquest va ser el primer gust de PowerShell que havia experimentat realment. Enrere, realment no ho vaig fer gaire; Acabo d’introduir una variable i un per què determinar si tots els fitxers es van publicar amb èxit i vaig marxar. Tot i això, sabia que realment no sabia gaire coses sobre PowerShell i que necessitaria aprendre a utilitzar-lo millor en el futur.

Avanç ràpid a desembre; el dia 1 de l'Avenció del Codi s'havia acabat i estava disposat a provar-me d'una manera nova intentant completar el màxim de reptes possibles amb PowerShell. El primer repte semblava prou senzill; feu una operació en cada número d'una llista i afegiu-los. Sabia que podia fer-ho gairebé de manera trivial en qualsevol altre idioma, però com que PowerShell era nou per a mi, vaig haver de començar de zero.

En primer lloc, necessitava establir algun tipus d’ambient. El primer dia, realment, no sabia què necessitava, així que el meu codi basat era simplement dos guions; un per a cada part del repte del primer dia.

El meu codi era prou senzill, ja que vaig aprendre sobre el contingut Get-Content, com fer una funció i com almenys representar el valor a la pantalla, tot i que no entenia totalment com simplement dir que $ TotalMass al final afectava realment el conjunt. estat del programa. Tot el que sabia era que com a mínim vaig inclinar els dits dels peus a PowerShell i estava disposat a continuar aprenent coses noves.

També volia introduir les proves d’unitats en el meu treball. Al principi, probablement va ser excessiu, però crec que la decisió de començar a afegir proves tan aviat va ser probablement millor, ja que em va portar a crear solucions destinades a adaptar-se a les proves. Afortunadament, molts dels reptes tenien exemples que eren efectivament proves. Per a aquest primer dia, la prova només va estar en uns quants números aïllats i no una llista completa, així que vaig intentar substituir els arguments en el guió per tal de poder especificar un fitxer o un sol número.

Enter Pester: possiblement l'eina de prova més simple i sorprenentment que he presenciat. Aquesta suite de proves basada en PowerShell us permet escriure casos de prova molt senzills simplement canalitzant la sortida d'algun programa a un mètode especial que compare el resultat. Com que funciona a través de canonades, podríeu escriure eficaçment amb qualsevol idioma o eina, i sempre que sortís, només podeu comparar que coincideix amb el resultat esperat. Vaig configurar-ne un bon número i ho vaig relacionar a la nova funció d'Accions de GitHub per integrar de manera efectiva CI al meu dipòsit. Un cop més, probablement sigui massa massa, tenint en compte que es tracta d’un dipòsit d’una sola persona en què no es treballarà després d’aquest mes, però que va ser una bona oportunitat per trobar algunes eines que podré utilitzar en el futur.

El dia 2 era una mica de bola de corba, però, era un programa que havia d’interpretar aquest bytecode (o codi postal d’entrada com es referien a ell perquè tècnicament els valors eren representats com a nombres enters). Per a aquest, vaig haver de fer front mentre que els bucles i les matrius, tots dos eren una mica complicats. De sobte ara només havia de fer servir la funcionalitat .NET regular a la part superior del meu codi altament PowerShell. Per exemple, necessitava llegir en entrada com una cadena única, dividir-la en cada coma, i la manera més senzilla de fer-ho era la mateixa sintaxi que ho feia en C #.

Però va ser el dia 3 que em vaig començar a preocupar una mica per la manera com em vaig apropar al codi PowerShell. Per a aquest repte, se us donava els camins de dos fils com a llista d’indicacions i distàncies i havíeu de determinar la intersecció més propera. El meu enfocament immediat era crear una funció que determinés on es trobaven totes les interseccions i, a continuació, una funció que, donada una ruta, calcula quant de temps hi havia la intersecció.

Va ser en aquest moment quan em vaig adonar que PowerShell era molt diferent al que originalment pensava que era. Sabia que estaria reutilitzant aquesta metodologia per trobar les interseccions per als dos camins, així que sabia que podia generalitzar-la a una funció amb un argument on passés el camí. El que volia tornar era el nombre enter de passos. es va trigar a arribar a un punt donat. Tot i això, la meva funció no era tornar cap cosa i les parts posteriors del codi es van veure en pànic perquè no podien funcionar amb un nul. Vaig tornar a aquesta funció i vaig afegir algunes declaracions impreses perquè sabés què feia. En canvi, la meva funció ara va tornar un booleà. No serveix de res, però es tracta d'un comportament curiós. El que era estrany era que la funció semblava calcular el valor correctament, però no es podia tornar correctament. En afegir declaracions d'impressió es va canviar el que va tornar la funció. Després de fer una estona de cerca, vaig descobrir que el problema era que les funcions no tornaven tant com es fan servir les canonades. Això explicava per què es van trencar les declaracions impreses, però no explicava per què el meu valor no tornava. Encara no estic segur del 100% per què no va tornar el que volia, però va ser molt frustrant continuar treballant amb ell, sobretot perquè volia estar al dia dels reptes quotidians.

Sense encertar, vaig decidir escriure una solució en C #, que ha estat el meu llenguatge goto des de fa un temps. La solució em va sortir de forma natural, ja que era gairebé exactament el que abans havia pensat. De fet, la meva solució a la primera part es va fer gairebé completament amb una simple funcionalitat LINQ; obteniu totes les coordenades cobertes per ambdues rutes, intersecteu-les i trobeu el valor mínim. Per acabar-ho de completar, vaig migrar els treballs dels dies anteriors (que eren molt senzills, independentment) i vaig tornar a implementar la prova mitjançant Xunit.

Per mirar introspectivament, què diu aquest moviment de mi mateix? Una resposta ingènua seria que vaig agafar la sortida fàcil i no volia desafiar-me més, tot i que definitivament pogués argumentar que alguns dels dies posteriors (sobretot el dia 18 amb el laberint de les portes de les claus) eren molt difícils sense importar-ne l’ús una llengua a la qual estava acostumat. Crec que una manera menys acusadora de mirar-ho és que em vaig adonar que el repte que estava experimentant era més semàntic i específic i menys tècnic i programàtic. No estava intentant resoldre el problema, ja que lluitava amb el conjunt d’eines que havia de posar en pràctica. Si volgués limitar-me en aquest últim lloc, hauria canviat tot en C, on no puc confiar en eines fàcils com ara matrius o hashsets d’escalació dinàmica.

I, sens dubte, vaig sentir que avançar cap a C # era un gran moviment només per l’abast dels reptes posteriors. L'intèrpret d'intcode es continua desenvolupant cada segon dia i molts reptes donarien efectivament a un programa que hauria de treballar per trobar una solució. Els reptes que necessitava executar múltiples al mateix temps eren força interessants, sobretot perquè cada intèrpret necessitava gestionar l’entrada i la sortida. Vaig implementar-ho amb fils i lambdas, que significava convenientment tenir una classe generalitzada per a aquests problemes d’intcode des del dia 9 en endavant i tot el que havia de fer era manipular com funcionava la E / S al seu voltant. També volia dir que pogués orientar fàcilment funcions específiques per fer proves si volgués (encara que em va sorprendre que la majoria dels problemes no tinguessin molts exemples més endavant).

Tot i això, no s'hauria de considerar com una extracció en PowerShell; sens dubte ha tingut un gust decent pel que puc i no puc fer amb ell, i quan hauria d’utilitzar-lo. M’alegro que tingués una classe dedicada per interpretar aquest problema recurrent d’intcode, en lloc d’haver-lo d’utilitzar manualment cada vegada, o d’alguna manera referir-lo en alguna ubicació comuna. Crec que estaria molt bé utilitzar PowerShell per a tasques més petites que no necessiten escalar, i en particular en sistemes Windows on no es pot instal·lar fàcilment Python o tal. Pester també és molt bo i no m'importaria escriure proves per a qualsevol cosa estranya.

Però teòricament, probablement podríeu fer qualsevol cosa que vulgueu a PowerShell. El que em va preocupar és que feia referència efectivament a les biblioteques .NET en lloc de poder escriure coses purament de PowerShell. Es sentia més natural simplement saltar un vaixell i escriure en un sol idioma en lloc d’una combinació d’ambdós en aquest escenari. I, finalment, en aquest escenari, vaig considerar que era més important aprendre sobre com resoldre problemes desafiants amb nous algorismes en lloc de llançar noves eines a la barreja.