Folklore om programmerare och ingenjörer (del 1)

Folklore om programmerare och ingenjörer (del 1)

Detta är ett urval av berättelser från Internet om hur buggar ibland har helt otroliga manifestationer. Du kanske har något att berätta också.

Bilallergi mot vaniljglass

En berättelse för ingenjörer som förstår att det uppenbara inte alltid är svaret, och att oavsett hur långsökta fakta kan tyckas så är de fortfarande fakta. Pontiac Division av General Motors Corporation fick ett klagomål:

Det här är andra gången jag skriver till dig, och jag klandrar dig inte för att du inte svarar, för det låter galet. Vår familj har en tradition att äta glass varje kväll efter middagen. Glassorterna ändras varje gång och efter middagen väljer hela familjen vilken glass som ska köpas, varefter jag går till affären. Jag köpte nyligen en ny Pontiac och sedan dess har mina resor för att köpa glass blivit ett problem. Du förstår, varje gång jag köper vaniljglass och kommer tillbaka från affären startar inte bilen. Tar jag med någon annan glass startar bilen utan problem. Jag vill ställa en seriös fråga, hur dumt det än låter: "Vad är det med Pontiac som gör att den inte startar när jag tar med vaniljglass, utan startar lätt när jag tar med en annan smak av glass?"

Som du kan föreställa dig var divisionspresidenten skeptisk till brevet. Men för säkerhets skull skickade jag en ingenjör för att kolla. Han blev förvånad över att han möttes av en rik, välutbildad man som bodde i ett vackert område. De kom överens om att träffas direkt efter middagen så att de två kunde gå till affären och äta glass. Den kvällen var det vanilj, och när de kom tillbaka till bilen ville den inte starta.

Ingenjören kom tre kvällar till. Första gången glassen var choklad. Bilen startade. Andra gången blev det jordgubbsglass. Bilen startade. Den tredje kvällen bad han att få ta vanilj. Bilen startade inte.

Resonerande rationellt vägrade ingenjören att tro att bilen var allergisk mot vaniljglass. Därför kom jag överens med ägaren av bilen att han skulle fortsätta sina besök tills han hittat en lösning på problemet. Och på vägen började han göra anteckningar: han skrev ner all information, tid på dygnet, typ av bensin, tid för ankomst och retur från affären, etc.

Ingenjören insåg snart att ägaren av bilen spenderade mindre tid på att köpa vaniljglass. Anledningen var layouten på varorna i butiken. Vaniljglass var populärast och förvarades i en separat frys längst fram i butiken för att göra den lättare att hitta. Och alla andra sorter fanns längst bak i butiken, och det tog mycket mer tid att hitta rätt sort och betala.

Nu var frågan till ingenjören: varför startade inte bilen om det hade gått mindre tid sedan det ögonblick då motorn stängdes av? Eftersom problemet var tiden, inte vaniljglass, hittade ingenjören snabbt svaret: det var ett gaslås. Det inträffade varje kväll, men när bilägaren ägnade mer tid åt att leta efter glass lyckades motorn svalna tillräckligt och startade lätt. Och när mannen köpte vaniljglass var motorn fortfarande för varm och gaslåset hann inte lösas upp.

Moral: Även helt galna problem är ibland verkliga.

Krasch Bandicoot

Det är smärtsamt att uppleva detta. Som programmerare vänjer man sig vid att skylla på sin kod först, tvåa, tredje... och någonstans på tiotusendelen skyller man på kompilatorn. Och längre ner på listan skyller du redan på utrustningen.

Här är min historia om hårdvarufelet.

Till spelet Crash Bandicoot skrev jag kod för att ladda och spara på ett minneskort. För en sådan självgod spelutvecklare var det som en promenad i parken: jag trodde att arbetet skulle ta flera dagar. Det slutade dock med att jag felsökte koden i sex veckor. Längs vägen löste jag andra problem, men med några dagars mellanrum återvände jag till den här koden i några timmar. Det var vånda.

Symptomet såg ut så här: när du sparar spelets nuvarande genomgång och kommer åt minneskortet går allt nästan alltid bra... Men ibland tar läs- eller skrivoperationen timeouts utan uppenbar anledning. En kort inspelning skadar ofta minneskortet. När en spelare försöker rädda misslyckas han inte bara med att rädda, utan förstör också kartan. Skit.

Efter ett tag började vår producent på Sony, Connie Bus, få panik. Vi kunde inte skicka spelet med denna bugg, och sex veckor senare förstod jag inte vad som orsakade problemet. Genom Connie kontaktade vi andra PS1-utvecklare: har någon stött på något liknande? Nej. Ingen hade problem med minneskortet.

När du inte har några idéer för felsökning är det enda tillvägagångssättet som återstår att "dela och erövra": ta bort mer och mer kod från det felaktiga programmet tills det finns ett relativt litet fragment kvar som fortfarande orsakar problemet. Det vill säga att man skär av programmet bit för bit tills den del som innehåller buggen finns kvar.

Men grejen är att det är väldigt svårt att skära ut bitar ur ett videospel. Hur kör man det om man tog bort koden som emulerar gravitationen? Eller rita karaktärer?

Därför måste vi ersätta hela moduler med stubbar som låtsas göra något användbart, men i själva verket göra något väldigt enkelt som inte kan innehålla fel. Vi måste skriva sådana kryckor för att spelet åtminstone ska fungera. Detta är en långsam och smärtsam process.

Kort sagt, jag gjorde det. Jag tog bort fler och fler kodbitar tills jag fick den initiala koden som konfigurerar systemet för att köra spelet, initierar renderingshårdvaran osv. Naturligtvis kunde jag i det här skedet inte skapa en spara och ladda meny, eftersom jag skulle behöva skapa en stubb för all grafikkod. Men jag kunde låtsas vara en användare som använder den (osynliga) spara och ladda skärmen och be om att spara och sedan skriva till minneskortet.

Detta lämnade mig med en liten bit kod som fortfarande hade ovanstående problem - men det hände fortfarande slumpmässigt! Oftast fungerade allt bra, men då och då blev det fel. Jag tog bort nästan all spelkod, men buggen levde fortfarande. Detta var förbryllande: den återstående koden gjorde faktiskt ingenting.

Någon gång, förmodligen runt tre på morgonen, slog jag mig en tanke. Läs- och skrivoperationer (inmatning/utgång) involverar exakta exekveringstider. När du arbetar med en hårddisk, minneskort eller Bluetooth-modul gör lågnivåkoden som ansvarar för läsning och skrivning det i enlighet med klockpulser.

Med hjälp av en klocka synkroniseras en enhet som inte är direkt ansluten till processorn med koden som exekveras på processorn. Klockan bestämmer baudhastigheten – hastigheten med vilken data överförs. Om det finns förvirring med timings, då är antingen hårdvaran eller mjukvaran, eller båda, också förvirrade. Och detta är mycket dåligt, eftersom data kan skadas.

Vad händer om något i vår kod förvirrar tiderna? Jag kollade allt relaterat till detta i testprogramkoden och märkte att vi ställde in den programmerbara timern i PS1 till 1 kHz (1000 tick per sekund). Detta är ganska mycket; som standard, när konsolen startar, körs den på 100 Hz. Och de flesta spel använder denna frekvens.

Andy, spelutvecklaren, ställde in timern på 1 kHz så att rörelser skulle beräknas mer exakt. Andy tenderar att gå överbord, och om vi efterliknar gravitationen gör vi det så exakt som möjligt!

Men vad händer om att snabba upp timern på något sätt påverkade programmets övergripande timing, och därmed klockan som reglerar överföringshastigheten för minneskortet?

Jag kommenterade timerkoden. Felet uppstod inte igen. Men det betyder inte att vi fixade det, eftersom felet inträffade slumpmässigt. Tänk om jag bara hade tur?

Några dagar senare experimenterade jag igen med testprogrammet. Felet återkom inte. Jag gick tillbaka till spelets fullständiga kodbas och modifierade koden för att spara och ladda så att den programmerbara timern skulle återställas till sitt ursprungliga värde (100Hz) innan jag fick åtkomst till minneskortet, och sedan återställas till 1kHz. Det var inga fler krascher.

Men varför hände detta?

Jag återvände till testprogrammet igen. Jag försökte hitta något mönster i förekomsten av ett fel med en 1 kHz timer. Så småningom märkte jag att felet uppstår när någon spelar med en PS1-kontroller. Eftersom jag sällan skulle göra detta själv - varför skulle jag behöva en kontroller när jag testar spara och ladda kod? – Jag märkte inte ens det här beroendet. Men en dag väntade en av våra artister på att jag skulle testa färdigt – jag bannade nog i det ögonblicket – och snurrade nervöst på kontrollern i händerna. Ett fel har uppstått. "Vänta, va?!" Nåväl, gör det igen!"

När jag insåg att dessa två händelser var sammankopplade kunde jag enkelt återskapa felet: jag började spela in på minneskortet, flyttade kontrollern och förstörde minneskortet. För mig såg det ut som ett hårdvarufel.

Jag kom till Connie och berättade för henne om min upptäckt. Hon vidarebefordrade informationen till en av ingenjörerna som designade PS1. "Omöjligt", svarade han, "det kan inte vara ett hårdvaruproblem." Jag bad Connie att ordna ett samtal för oss.

Ingenjören ringde mig och vi bråkade på hans brutna engelska och min (extremt) trasiga japanska. Till slut sa jag: "Låt mig bara skicka mitt 30 rader testprogram där flytt av styrenheten orsakar en bugg." Han höll med. Sa att det var slöseri med tid och att han var fruktansvärt upptagen med att arbeta med ett nytt projekt, men skulle ge efter för att vi var en väldigt viktig utvecklare för Sony. Jag städade upp mitt testprogram och skickade det till honom.

Nästa kväll (vi var i Los Angeles och han var i Tokyo) ringde han mig och bad om ursäkt. Det var ett hårdvaruproblem.

Jag vet inte exakt vad felet var, men vad jag hörde på Sonys huvudkontor, om du ställde in timern på ett tillräckligt högt värde, störde det komponenter på moderkortet i närheten av timerkristallen. En av dem var en överföringshastighetsregulator för minneskortet, som också ställde in överföringshastigheten för regulatorerna. Jag är ingen ingenjör, så jag kan ha förstört något.

Men poängen är att det var störningar mellan komponenterna på moderkortet. Och när data överfördes samtidigt genom kontrollerporten och minneskortsporten med en timer som körs på 1 kHz, gick bitar förlorade, data gick förlorade och kortet skadades.

Dåliga kor

På 1980-talet skrev min mentor Sergei mjukvara för SM-1800, en sovjetisk klon av PDP-11. Denna mikrodator har precis installerats på en järnvägsstation nära Sverdlovsk, ett viktigt transportnav i Sovjetunionen. Det nya systemet utformades för att dirigera vagnar och godstrafik. Men den innehöll en irriterande bugg som ledde till slumpmässiga krascher och krascher. Fall inträffade alltid när någon gick hem på kvällen. Men trots en noggrann undersökning dagen efter fungerade datorn korrekt i alla manuella och automatiska tester. Detta indikerar vanligtvis ett tävlingstillstånd eller någon annan tävlingsfel som inträffar under vissa förhållanden. Sergei var trött på samtal sent på natten och bestämde sig för att gå till botten med det och först och främst förstå vilka förhållanden på rangergården som ledde till datorhaveriet.

Först samlade han statistik över alla oförklarade fall och skapade en graf efter datum och tid. Mönstret var tydligt. Efter att ha observerat några dagar till insåg Sergei att han lätt kunde förutsäga tidpunkten för framtida systemfel.

Han fick snart veta att störningar bara inträffade när stationen sorterade tåglaster med boskap från norra Ukraina och västra Ryssland på väg till ett närliggande slakteri. Detta i sig var märkligt, eftersom slakteriet försörjdes från gårdar belägna mycket närmare, i Kazakstan.

Kärnkraftverket i Tjernobyl exploderade 1986 och radioaktivt nedfall gjorde de omgivande områdena obeboeliga. Stora områden i norra Ukraina, Vitryssland och västra Ryssland var förorenade. Sergei misstänkte höga nivåer av strålning i de ankommande vagnarna och utvecklade en metod för att testa denna teori. Befolkningen förbjöds att ha dosimetrar, så Sergei registrerade sig med flera militärer vid järnvägsstationen. Efter flera drinkar vodka lyckades han övertyga en soldat att mäta strålningsnivån i en av de misstänkta vagnarna. Det visade sig att nivån var flera gånger högre än normala värden.

Inte nog med att boskapen avgav mycket strålning, dess nivå var så hög att det ledde till slumpmässiga förluster av bitar i minnet på SM-1800, som låg i en byggnad intill stationen.

Det rådde matbrist i Sovjetunionen, och myndigheterna beslutade att blanda Tjernobyl-kött med kött från andra regioner i landet. Detta gjorde det möjligt att minska den totala nivån av radioaktivitet utan att förlora värdefulla resurser. Efter att ha lärt sig om detta fyllde Sergei omedelbart i dokument för emigration. Och datorkrascharna slutade av sig själva när strålningsnivån minskade med tiden.

Genom rören

En gång i tiden skapade Movietech Solutions mjukvara för biografer, designad för bokföring, biljettförsäljning och allmän förvaltning. DOS-versionen av flaggskeppsappen var ganska populär bland små och medelstora biografkedjor i Nordamerika. Så det är inte förvånande att när en Windows 95-version tillkännagavs, integrerad med de senaste pekskärmarna och självbetjäningskiosker, och utrustad med alla möjliga rapporteringsverktyg, blev den också snabbt populär. Oftast gick uppdateringen utan problem. Den lokala IT-personalen installerade ny utrustning, migrerade data och verksamheten fortsatte. Förutom när det inte varade. När detta hände skickade företaget ut James, med smeknamnet "The Cleaner".

Även om smeknamnet antyder en elak typ, är städaren bara en kombination av instruktör, installatör och jack-of-all-trades. James skulle tillbringa några dagar på kundens plats för att sätta ihop alla komponenter och sedan tillbringa ytterligare ett par dagar med att lära personalen hur man använder det nya systemet, lösa eventuella hårdvaruproblem som uppstod och i huvudsak hjälpa programvaran genom dess linda.

Därför är det inte förvånande att James under dessa hektiska tider anlände till kontoret på morgonen och innan han hann fram till sitt skrivbord möttes han av chefen, fylld med koffein utöver det vanliga.

"Jag är rädd att du måste åka till Annapolis, Nova Scotia, så snart som möjligt." Hela deras system gick ner, och efter en natts arbete med deras ingenjörer kan vi inte lista ut vad som hände. Det verkar som att nätverket har misslyckats på servern. Men först efter att systemet hade varit igång i flera minuter.

– De återgick inte till det gamla systemet? – James svarade helt seriöst, även om han mentalt spärrade upp ögonen av förvåning.

— Exakt: deras IT-specialist "ändrade prioriteringar" och bestämde sig för att lämna med sin gamla server. James, de installerade systemet på sex platser och betalade precis för premiumsupport, och deras verksamhet drivs nu som det var på 1950-talet.

James rätade upp sig något.

- Det är en annan sak. Okej, låt oss börja.

När han kom till Annapolis var det första han gjorde att hitta kundens första teater som hade problem. På kartan tagen på flygplatsen såg allt hyfsat ut, men området runt den önskade adressen såg misstänkt ut. Inte ghetto, men påminner om film noir. När James parkerade vid trottoarkanten i centrum kom en prostituerad fram till honom. Med tanke på storleken på Annapolis var det troligen den enda i hela staden. Hennes utseende förde omedelbart tankarna till den berömda karaktären som erbjöd sex för pengar på den stora skärmen. Nej, inte om Julia Roberts, utan om Jon Voight [anspelning på filmen "Midnight Cowboy" - ca. körfält].

Efter att ha skickat iväg den prostituerade gick James på bio. Omgivningen hade blivit bättre, men det gav ändå intrycket av att vara nedgånget. Inte för att James var alltför orolig. Han har varit på eländiga platser förut. Och det här var Kanada, där till och med rånare är artiga nog att säga "tack" efter att ha tagit din plånbok.

Sidoingången till biografen låg i en fuktig gränd. James gick till dörren och knackade på. Snart knarrade det och öppnade sig något.

-Är du städare? – en hes röst kom inifrån.

– Ja, det är jag... Jag kom för att fixa allt.

James gick in i biolobbyn. Personalen hade tydligen inget annat val och började dela ut pappersbiljetter till besökare. Detta gjorde den finansiella rapporteringen svår, än mindre intressanta detaljer. Men personalen hälsade James med lättnad och tog honom omedelbart till serverrummet.

Vid första anblicken var allt bra. James loggade in på servern och kollade de vanliga misstänkta platserna. Inga problem. Men av stor försiktighet stängde James ner servern, bytte ut nätverkskortet och rullade tillbaka systemet. Hon började genast arbeta för fullt. Personalen började sälja biljetter igen.

James ringde Mark och informerade honom om situationen. Det är inte svårt att föreställa sig att James kanske vill stanna kvar och se om något oväntat händer. Han gick ner för trappan och började fråga de anställda vad som hände. Uppenbarligen har systemet slutat fungera. De stängde av och på, allt fungerade. Men efter 10 minuter föll systemet av.

Just i detta ögonblick hände något liknande. Plötsligt började biljettsystemet kasta fel. Personalen suckade och tog tag i pappersbiljetterna och James skyndade till serverrummet. Allt såg bra ut med servern.

Då kom en av de anställda in.

– Systemet fungerar igen.

James var förbryllad eftersom han inte hade gjort någonting. Mer exakt, inget som skulle få systemet att fungera. Han loggade ut, tog upp sin telefon och ringde företagets supportlinje. Snart kom samma anställd in i serverrummet.

– Systemet ligger nere.

James tittade på servern. Ett intressant och välbekant mönster av flerfärgade former dansade på skärmen - kaotiskt vridande och sammanflätade rör. Vi har alla sett den här skärmsläckaren någon gång. Den var vackert återgiven och bokstavligen hypnotiserande.


James tryckte på en knapp och mönstret försvann. Han skyndade till biljettkassan och mötte på vägen en anställd som återvände till honom.

– Systemet fungerar igen.

Om du kan göra en mental facepalm, är det precis vad James gjorde. Skärmsläckare. Den använder OpenGL. Och därför, under drift, förbrukar den alla resurser från serverprocessorn. Som ett resultat avslutas varje anrop till servern med en timeout.

James återvände till serverrummet, loggade in och bytte ut skärmsläckaren mot de vackra rören med en tom skärm. Det vill säga, istället för en skärmsläckare som förbrukar 100 % av processorresurserna, installerade jag en annan som inte förbrukar resurser. Sedan väntade jag 10 minuter för att kolla min gissning.

När James kom till nästa biograf undrade han hur han skulle förklara för sin chef att han precis flugit 800 mil för att stänga av skärmsläckaren.

Krasch under en viss fas av månen

Sann historia. En dag uppstod ett programvarufel som berodde på månens fas. Det fanns en liten rutin som ofta användes i olika MIT-program för att beräkna approximationen till månens sanna fas. GLS byggde in denna rutin i ett LISP-program som, när man skrev en fil, skulle mata ut en rad med en tidsstämpel på nästan 80 tecken. Det var mycket sällsynt att den första raden i ett meddelande blev för lång och ledde till nästa rad. Och när programmet senare läste den här filen förbannade den. Längden på den första raden berodde på det exakta datumet och tiden, samt längden på fasspecifikationen vid den tidpunkt då tidsstämpeln skrevs ut. Det vill säga, buggen var bokstavligen beroende av månens fas!

Första pappersupplagan Jargongfil (Steele-1983) innehöll ett exempel på en sådan rad som ledde till det beskrivna felet, men sättaren "fixade" det. Detta har sedan dess beskrivits som en "månfasbugg".

Var dock försiktig med antaganden. För några år sedan stötte ingenjörer från CERN (European Centre for Nuclear Research) på fel i experiment som utfördes vid Large Electron-Positron Collider. Eftersom datorer aktivt bearbetar den enorma mängden data som genereras av den här enheten innan de visar resultatet för forskare, spekulerade många att programvaran på något sätt var känslig för månens fas. Flera desperata ingenjörer kom till botten med sanningen. Felet uppstod på grund av en liten förändring i geometrin hos den 27 km långa ringen på grund av jordens deformation under månens passage! Den här historien har kommit in i fysikens folklore som "Newtons hämnd på partikelfysik" och ett exempel på sambandet mellan fysikens enklaste och äldsta lagar och de mest avancerade vetenskapliga koncepten.

Att spola toaletten stoppar tåget

Det bästa hårdvarufelet jag någonsin hört talas om var på ett höghastighetståg i Frankrike. Felet ledde till nödbromsning av tåget, men bara om det fanns passagerare ombord. I varje sådant fall togs tåget ur drift, kontrollerades, men ingenting hittades. Sedan skickades han tillbaka till linjen, och han kraschade omedelbart.

Under en av kontrollerna gick en ingenjör som färdades på tåget på toaletten. Han tvättade snart bort, BOM! Nödstopp.

Ingenjören kontaktade föraren och frågade:

– Vad gjorde du precis innan du bromsade?

- Jo, jag saktade ner på nedstigningen...

Detta var konstigt, för under normal drift saktar tåget ner på nedförsbackar dussintals gånger. Tåget gick vidare och vid nästa nedstigning varnade föraren:

– Jag ska sakta ner.

Inget hände.

— Vad gjorde du under den senaste inbromsningen? - frågade föraren.

- Tja... jag var på toaletten...

– Jaha, gå då på toaletten och gör som du gjorde när vi går ner igen!

Ingenjören gick till toaletten och när föraren varnade: "Jag saktar ner" spolade han vattnet. Självklart stannade tåget direkt.

Nu kunde de reproducera problemet och behövde hitta orsaken.

Efter två minuter märkte de att motorbromsfjärrkontrollkabeln (tåget hade en motor i varje ände) var lossad från väggen i elskåpet och låg på reläet som styrde toalettens kontaktsolenoid... När reläet var påslagen skapade det störningar i bromskabeln och systemskyddet mot fel inkluderade helt enkelt nödbromsning.

Porten som hatade FORTRAN

För några månader sedan märkte vi att nätverksanslutningarna på fastlandet [detta var på Hawaii] blev väldigt, väldigt långsamma. Detta kan pågå i 10-15 minuter och sedan plötsligt inträffa igen. Efter en tid, klagade min kollega till mig att nätverksanslutningar på fastlandet i allmänhet fungerar inte. Han hade någon FORTRAN-kod som behövde kopieras till en maskin på fastlandet, men det kunde den inte eftersom "nätverket inte höll upp tillräckligt länge för att FTP-uppladdningen skulle slutföras."

Ja, det visade sig att nätverksfel uppstod när en kollega försökte FTP en fil med källkod i FORTRAN till en maskin på fastlandet. Vi försökte arkivera filen: sedan kopierades den smidigt (men målmaskinen hade ingen uppackare, så problemet löstes inte). Till sist "delade vi" FORTRAN-koden i mycket små bitar och skickade dem en i taget. De flesta fragmenten kopierades utan problem, men några stycken gick inte igenom, eller passerade efter talrik Försök.

När vi undersökte de problematiska avsnitten upptäckte vi att de hade något gemensamt: de innehöll alla kommentarsblock som började och slutade med rader bestående av stort C (som en kollega föredrog att kommentera i FORTRAN). Vi mailade nätverksexperter på fastlandet och bad om hjälp. Naturligtvis ville de se prover på våra filer som inte gick att överföra via FTP... men våra brev nådde dem inte. Till slut kom vi fram till en enkel beskrivahur icke-överförbara filer ser ut. Det fungerade :) [Vågar jag lägga till ett exempel på en av de problematiska FORTRAN-kommentarerna här? Förmodligen inte värt det!]

Till slut lyckades vi lista ut det. En ny gateway installerades nyligen mellan vår del av campus och fastlandsnätet. Det hade ENORMA svårigheter att överföra paket som innehöll upprepade bitar av versaler C! Bara ett fåtal av dessa paket kan ta upp alla gatewayresurser och hindra de flesta andra paket från att komma igenom. Vi klagade till gatewaytillverkaren... och de svarade: "Åh, ja, du står inför en bugg med upprepad C! Vi vet redan om honom." Vi löste så småningom problemet genom att köpa en ny gateway från en annan tillverkare (till den förres försvar kan oförmågan att överföra FORTRAN-program vara en fördel för vissa!).

Svåra tider

För några år sedan, när jag arbetade med att skapa ett ETL-system i Perl för att minska kostnaderna för kliniska fas 40-prövningar, behövde jag bearbeta cirka 000 1 datum. Två av dem klarade inte provet. Detta störde mig inte så mycket eftersom dessa datum togs från klienttillhandahållen data som ofta var, ska vi säga, överraskande. Men när jag kollade de ursprungliga uppgifterna visade det sig att dessa datum var 2011 januari 1 och 2007 januari 30. Jag trodde att buggen fanns i programmet jag precis hade skrivit, men det visade sig att det redan var XNUMX år gammal. Detta kan låta mystiskt för dem som inte är bekanta med mjukvarans ekosystem. På grund av ett annat företags långvariga beslut att tjäna pengar, betalade min klient mig för att fixa en bugg som ett företag hade introducerat av misstag och det andra med avsikt. För att du ska förstå vad jag pratar om måste jag prata om företaget som lade till funktionen som slutade med att bli en bugg, samt några andra intressanta händelser som bidrog till den mystiska buggen jag fixade.

På den gamla goda tiden återställde Apple-datorer ibland spontant sitt datum till 1 januari 1904. Anledningen var enkel: den använde en batteridriven "systemklocka" för att hålla reda på datum och tid. Vad hände när batteriet tog slut? Datorer började spåra datumet med antalet sekunder sedan början av en epok. Med epok menade vi referensdatumet för originalet, och för Macintosh-datorer var det 1 januari 1904. Och efter att batteriet dog återställdes det aktuella datumet till det angivna. Men varför hände detta?

Tidigare använde Apple 32 bitar för att lagra antalet sekunder sedan det ursprungliga datumet. En bit kan lagra ett av två värden - 1 eller 0. Två bitar kan lagra ett av fyra värden: 00, 01, 10, 11. Tre bitar - ett värde av åtta: 000, 001, 010, 011, 100 , 101, 110, 111, etc. Och 32 kunde lagra ett av 232 värden, det vill säga 4 294 967 296 sekunder. För Apple-datum var detta ungefär 136 år, så äldre Mac-datorer kan inte hantera datum efter 2040. Och om systembatteriet dör, återställs datumet till 0 sekunder sedan epokens början, och du måste manuellt ställa in datumet varje gång du slår på datorn (eller tills du köper ett nytt batteri).

Apples beslut att lagra datum som sekunder sedan epoken innebar dock att vi inte kunde hantera datum före epoken, vilket fick långtgående konsekvenser, som vi ska se. Apple introducerade en funktion, inte en bugg. Detta innebar bland annat att Macintosh-operativsystemet var immunt mot "millenniebuggen" (vilket inte gick att säga om många Mac-program som hade sina egna datumsystem för att kringgå restriktioner).

Varsågod. Vi använde Lotus 1-2-3, IBMs "killer application" som hjälpte till att starta PC-revolutionen, även om Apples datorer hade VisiCalc, vilket gjorde persondatorn till en framgång. I rättvisans namn, om 1-2-3 inte hade dykt upp hade PC-datorer knappast tagit fart, och persondatorernas historia kunde ha utvecklats väldigt annorlunda. Lotus 1-2-3 behandlade felaktigt 1900 som ett skottår. När Microsoft släppte sitt första kalkylblad, Multiplan, tog det en liten del av marknaden. Och när de lanserade Excel-projektet bestämde de sig för att inte bara kopiera namnschemat för rader och kolumner från Lotus 1-2-3, utan också att säkerställa buggkompatibilitet genom att medvetet behandla 1900 som ett skottår. Detta problem finns fortfarande idag. Det vill säga i 1-2-3 var detta en bugg, men i Excel var det ett medvetet beslut som säkerställde att alla 1-2-3 användare kunde importera sina tabeller till Excel utan att ändra data, även om det var felaktigt.

Men det fanns ett annat problem. Först släppte Microsoft Excel för Macintosh, som inte kände igen datum före 1 januari 1904. Och i Excel ansågs 1 januari 1900 vara början på eran. Därför gjorde utvecklarna en förändring så att deras program kände igen typen av era och lagrade data inom sig i enlighet med den önskade eran. Microsoft skrev till och med en förklarande artikel om detta. Och detta beslut ledde till min bugg.

Mitt ETL-system fick Excel-kalkylblad från kunder som skapades på Windows, men som även kunde skapas på en Mac. Därför kan början av eran i tabellen vara antingen 1 januari 1900 eller 1 januari 1904. Hur får man reda på det? Excel-filformatet visar den nödvändiga informationen, men parsern jag använde visade den inte (nu gör den det), och antog att du känner till epok för en specifik tabell. Jag kunde förmodligen ha ägnat mer tid åt att förstå det binära Excel-formatet och skicka en patch till parserförfattaren, men jag hade mycket mer att göra för klienten, så jag skrev snabbt en heuristik för att bestämma epok. Hon var enkel.

I Excel kan datumet 5 juli 1998 representeras i formatet "07-05-98" (onyttigt amerikanskt system), "5 juli 98", "5 juli 1998", "5 juli 98" eller något annat format, ett annat värdelöst format (ironiskt nog var ett av formaten som min version av Excel inte erbjöd ISO 8601). Men i tabellen lagrades det oformaterade datumet som antingen "35981" för epok-1900 eller "34519" för epok-1904 (siffrorna representerar antalet dagar sedan epoken). Jag använde helt enkelt en enkel parser för att extrahera året från det formaterade datumet och använde sedan Excel-parsern för att extrahera året från det oformaterade datumet. Om båda värdena skilde sig med 4 år, visste jag att jag använde ett system med epok-1904.

Varför använde jag inte bara formaterade datum? Eftersom 5 juli 1998 kan formateras som "juli 98" med månadsdagen förlorad. Vi fick tabeller från så många företag som skapade dem på så många olika sätt att det var upp till oss (i det här fallet mig) att räkna ut datumen. Dessutom, om Excel får det rätt, så borde vi det också!

Samtidigt stötte jag på 39082. Låt mig påminna dig om att Lotus 1-2-3 ansåg 1900 vara ett skottår, och detta upprepades troget i Excel. Och eftersom detta lades till en dag till år 1900, kan många datumberäkningsfunktioner vara fel för just den dagen. Det vill säga, 39082 kunde ha varit 1 januari 2011 (på Mac) eller 31 december 2006 (på Windows). Om min "year parser" extraherade år 2011 från det formaterade värdet, så är allt bra. Men eftersom Excel-parsern inte vet vilken epok som används, är den som standard epok-1900 och återgår till år 2006. Min ansökan såg att skillnaden var 5 år, ansåg att det var ett fel, loggade det och returnerade ett oformaterat värde.

För att komma runt detta skrev jag detta (pseudokod):

diff = formatted_year - parsed_year
if 0 == diff
    assume 1900 date system
if 4 == diff
    assume 1904 date system
if 5 == diff and month is December and day is 31
    assume 1904 date system

Och sedan analyserades alla 40 000 datum korrekt.

Mitt i stora utskriftsjobb

I början av 1980-talet arbetade min far på Storage Technology, en numera nedlagd division som skapade bandenheter och pneumatiska system för höghastighetsbandmatning.

De designade om enheterna så att de kunde ha en central "A"-enhet ansluten till sju "B"-enheter, och det lilla operativsystemet i RAM som styrde "A"-enheten kunde delegera läs- och skrivoperationer till alla "B"-enheter.

Varje gång enhet "A" startades, var det nödvändigt att sätta in en diskett i den kringutrustning som var ansluten till "A" för att ladda operativsystemet i dess minne. Det var extremt primitivt: datorkraft tillhandahölls av en 8-bitars mikrokontroller.

Målgruppen för sådan utrustning var företag med mycket stora datalager – banker, detaljhandelskedjor etc. – som behövde skriva ut många adressetiketter eller kontoutdrag.

En klient hade problem. Mitt under ett utskriftsjobb kan en speciell enhet "A" sluta fungera, vilket gör att hela jobbet stannar. För att återställa enhetens funktion var personalen tvungen att starta om allt. Och om detta hände mitt i en sextimmarsuppgift, gick en enorm mängd dyr datortid förlorad och schemat för hela operationen stördes.

Tekniker skickades från Storage Technologies. Men trots deras bästa ansträngningar kunde de inte reproducera felet under testförhållanden: det verkade inträffa mitt i stora utskriftsjobb. Problemet var inte hårdvaran, de bytte ut allt de kunde: RAM, mikrokontroller, diskettenhet, alla tänkbara delar av bandenheten - problemet kvarstod.

Sedan ringde teknikerna till högkvarteret och ringde experten.

Experten tog en stol och en kopp kaffe, satte sig i datorrummet – på den tiden fanns det rum som var avsedda för datorer – och såg på hur personalen köade ett stort utskriftsjobb. Experten väntade på att ett misslyckande skulle inträffa – och det gjorde den. Alla tittade på Experten, men han hade ingen aning om varför detta hände. Så han beordrade att jobbet skulle köas igen, och all personal och tekniker gick tillbaka till jobbet.

Experten satte sig igen i stolen och började vänta på ett misslyckande. Ungefär sex timmar gick och felet inträffade. Experten hade återigen inga idéer, förutom att allt hände i ett rum fyllt med människor. Han beordrade att uppdraget skulle återupptas, satte sig tillbaka och väntade.

Vid det tredje misslyckandet märkte experten något. Felet uppstod när personal bytte band på en främmande enhet. Dessutom inträffade felet så snart en av de anställda gick igenom en viss kakel på golvet.

Det upphöjda golvet var gjord av aluminiumplattor som lades på en höjd av 6 till 8 tum. Många ledningar från datorer löpte under det upphöjda golvet för att förhindra att någon råkade trampa på en viktig kabel. Plattorna lades mycket tätt för att förhindra att skräp skulle komma under det upphöjda golvet.

Experten insåg att en av plattorna var deformerad. När en anställd klev på dess hörn skavde kanterna på plattan mot de intilliggande plattorna. Plastdelarna som kopplade ihop plattorna skavde också med dem, vilket orsakade statiska mikrourladdningar som skapade radiofrekventa störningar.

Idag är RAM mycket bättre skyddat från radiofrekvensstörningar. Men på de åren var det inte så. Experten insåg att denna störning störde minnet och med det driften av operativsystemet. Han ringde supporttjänsten, beställde nya plattor, installerade dem själv och problemet försvann.

Det är högvatten!

Historien utspelade sig i ett serverrum, på fjärde eller femte våningen i ett kontor i Portsmouth (tror jag), i hamnområdet.

En dag kraschade Unix-servern med huvuddatabasen. De startade om honom, men han fortsatte glatt att falla om och om igen. Vi bestämde oss för att ringa någon från supporttjänsten.

Supportkillen... Jag tror att han hette Mark, men det spelar ingen roll... Jag tror inte att jag känner honom. Det spelar ingen roll, egentligen. Låt oss hålla fast vid Mark, okej? Bra.

Så några timmar senare kom Mark (det är inte långt från Leeds till Portsmouth, du vet), slog på servern och allt fungerade utan problem. Typiskt jäkla support, klienten blir väldigt upprörd över det. Mark tittar igenom loggfilerna och hittar inget otrevligt. Så Mark sätter sig på tåget igen (eller vilket transportsätt han än kom med, det kunde ha varit en halt ko för allt jag vet... i alla fall, det spelar ingen roll, okej?) och beger sig tillbaka till Leeds, efter att ha slösat bort. dagen.

Samma kväll kraschar servern igen. Historien är densamma... servern reser sig inte. Mark försöker hjälpa till på distans, men klienten kan inte starta servern.

Ännu ett tåg, buss, citronmaräng eller något annat skit, och Mark är tillbaka i Portsmouth. Titta, servern startar utan problem! Mirakel. Mark ägnar flera timmar åt att kontrollera att allt är i sin ordning med operativsystemet eller mjukvaran och ger sig av mot Leeds.

Runt mitt på dagen kraschar servern (ta det lugnt!). Den här gången verkar det rimligt att ta in maskinvarusupportpersonal för att ersätta servern. Men nej, efter ca 10 timmar faller det också.

Situationen upprepade sig i flera dagar. Servern fungerar, kraschar efter ca 10 timmar och startar inte under de kommande 2 timmarna. De kollade kylning, minnesläckor, de kollade allt, men hittade ingenting. Sedan upphörde kraschen.

Veckan gick bekymmerslöst... alla var nöjda. Glad tills allt börjar igen. Bilden är densamma. 10 timmars arbete, 2-3 timmars stillestånd...

Och så sa någon (jag tror att de sa till mig att den här personen inte hade något med IT att göra):

"Det är tidvattnet!"

Utropet möttes av tomma blickar, och någons hand tvekade förmodligen vid säkerhetsanropsknappen.

"Det slutar fungera med tidvattnet."

Detta verkar vara ett helt främmande koncept för IT-supportarbetare, som sannolikt inte kommer att läsa Tide Yearbook när de sätter sig ner för kaffe. De förklarade att detta inte kunde relateras till tidvattnet på något sätt, eftersom servern hade fungerat i en vecka utan fel.

"Förra veckan var tidvattnet lågt, men den här veckan är det högt."

Lite terminologi för de som inte har yachtlicens. Tidvatten beror på månens cykel. Och när jorden roterar skapar solens och månens gravitationskraft en flodvåg var 12,5:e timme. I början av den 12,5 timmar långa cykeln är det högvatten, i mitten av cykeln är det ebb och i slutet är det högvatten igen. Men i takt med att månens omloppsbana förändras, så förändras också skillnaden mellan låg- och högvatten. När månen är mellan solen och jorden eller på motsatt sida av jorden (fullmåne eller ingen måne), får vi Syzygyn tidvatten - det högsta högvatten och det lägsta lågvatten. Vid halvmåne får vi kvadraturtidvatten - det lägsta tidvattnet. Skillnaden mellan de två ytterligheterna minskar kraftigt. Måncykeln varar i 28 dagar: syzygian - kvadratur - syzygian - kvadratur.

När teknikerna fick förklarat vad tidvattenkrafterna innebar, tänkte de direkt att de behövde ringa polisen. Och ganska logiskt. Men det visade sig att killen hade rätt. Två veckor tidigare låg en jagare förtöjd inte långt från kontoret. Varje gång tidvattnet höjde det till en viss höjd hamnade fartygets radarstolpe i nivå med serverrummets golv. Och radarn (eller elektronisk krigsföringsutrustning, eller någon annan militär leksak) skapade kaos i datorerna.

Flyguppdrag för raketen

Jag fick i uppdrag att porta ett stort (cirka 400 tusen rader) raketuppskjutningssystem för kontroll och övervakning till nya versioner av operativsystemet, kompilatorn och språket. Närmare bestämt, från Solaris 2.5.1 till Solaris 7, och från Verdix Ada Development System (VADS), skrivet i Ada 83, till Rational Apex Ada-systemet, skrivet i Ada 95. VADS köptes av Rational, och dess produkt var föråldrad, även om Rational försökte implementera kompatibla versioner av VADS-specifika paket för att underlätta övergången till Apex-kompilatorn.

Tre personer hjälpte mig att bara få koden sammanställd rent. Det tog två veckor. Och sedan jobbade jag på egen hand för att få systemet att fungera. Kort sagt, det var den sämsta arkitekturen och implementeringen av ett mjukvarusystem som jag hade stött på, så det tog ytterligare två månader att slutföra porten. Systemet lämnades sedan in för testning, vilket tog ytterligare flera månader. Jag korrigerade omedelbart de buggar som hittades under testningen, men antalet minskade snabbt (källkoden var ett produktionssystem, så dess funktionalitet fungerade ganska tillförlitligt, jag var bara tvungen att ta bort de buggar som uppstod under anpassningen till den nya kompilatorn). Så småningom, när allt fungerade som det skulle, förflyttades jag till ett annat projekt.

Och på fredagen före Thanksgiving ringde telefonen.

Raketuppskjutningen var tänkt att testas om cirka tre veckor, och under laboratorietester av nedräkningen blockerades kommandosekvensen. I verkligheten skulle detta avbryta testet, och om blockeringen inträffade inom några sekunder efter att motorn startat, skulle flera oåterkalleliga åtgärder inträffa i hjälpsystemen, vilket skulle kräva en lång - och dyr - beredskap av raketen. Det skulle inte ha börjat, men många människor skulle ha blivit väldigt upprörda över förlorad tid och mycket, mycket pengar. Låt inte någon berätta för dig att försvarsdepartementet spenderar pengar hänsynslöst – jag har aldrig träffat en kontraktschef som inte satte budgeten först eller två, följt av schema.

Under tidigare månader hade den här nedräkningsutmaningen körts hundratals gånger i många varianter, med bara några få mindre hicka. Så sannolikheten för att detta skulle inträffa var mycket låg, men dess konsekvenser var mycket betydande. Multiplicera båda dessa faktorer, och du kommer att förstå att nyheterna förutspådde en förstörd semestervecka för mig och dussintals ingenjörer och chefer.

Och uppmärksamhet ägnades åt mig som den person som portade systemet.

Som med de flesta säkerhetskritiska system loggades många parametrar, så det var ganska enkelt att identifiera de få rader kod som kördes innan systemet kraschade. Och naturligtvis var det absolut inget ovanligt med dem, samma uttryck hade framgångsrikt utförts bokstavligen tusentals gånger under samma körning.

Vi kallade in personerna från Apex till Rational eftersom det var de som utvecklade kompilatorn och några av rutinerna de utvecklade kallades i den misstänkta koden. De (och alla andra) var imponerade av att det fanns ett behov av att gå till roten av ett problem av bokstavligen nationell betydelse.

Eftersom det inte fanns något intressant i tidskrifterna bestämde vi oss för att försöka reproducera problemet i ett lokalt laboratorium. Detta var inte en lätt uppgift eftersom händelsen inträffade ungefär en gång per 1000 körningar. En misstänkt orsak var att ett anrop till en leverantörsutvecklad mutex-funktion (en del av VADS-migreringspaketet) Unlock ledde inte till upplåsning. Bearbetningstråden som kallade funktionen behandlade hjärtslagsmeddelanden, som nominellt anlände varje sekund. Vi höjde frekvensen till 10 Hz, det vill säga 10 gånger per sekund, och började springa. Cirka en timme senare låste sig systemet. I loggen såg vi att sekvensen av inspelade meddelanden var densamma som under det misslyckade testet. Vi gjorde flera löpningar till, systemet blockerades konsekvent 45-90 minuter efter starten, och varje gång innehöll loggen samma rutt. Även om vi tekniskt körde olika kod - meddelandefrekvensen var annorlunda - var systemets beteende detsamma, så vi var övertygade om att detta belastningsscenario orsakade samma problem.

Nu behövde vi ta reda på var exakt blockeringen inträffade i sekvensen av uttryck.

Denna implementering av systemet använde Ada-uppgiftssystemet och använde det otroligt dåligt. Tasks är en samtidigt körbar konstruktion på hög nivå i Ada, ungefär som exekveringstrådar, bara inbyggda i själva språket. När två uppgifter behöver kommunicera, "ställer de in ett möte", utbyter nödvändiga data och stoppar sedan mötet och återgår till sina oberoende avrättningar. Systemet implementerades dock annorlunda. Efter att en måluppgift var rendezvous möttes den måluppgiften med en annan uppgift, som sedan möttes med en tredje uppgift, och så vidare tills en viss bearbetning var klar. Efter detta avslutades alla dessa möten och varje uppgift fick återgå till sin utförande. Det vill säga, vi hade att göra med det dyraste funktionsanropssystemet i världen, som stoppade hela "multitasking"-processen medan det bearbetade en del av indata. Och innan detta ledde inte till problem bara för att genomströmningen var mycket låg.

Jag beskrev denna uppgiftsmekanism eftersom när ett möte begärdes eller förväntades slutföras, kunde en "uppgiftsväxling" inträffa. Det vill säga, processorn kan börja bearbeta en annan uppgift som är redo att utföras. Det visar sig att när en uppgift är redo att träffas med en annan uppgift, kan en helt annan uppgift börja utföras, och så småningom återgår kontrollen till den första mötesplatsen. Och andra händelser kan inträffa som gör att uppgiften byter; en sådan händelse är ett anrop till en systemfunktion, som att skriva ut eller köra en mutex.

För att förstå vilken kodrad som orsakade problemet behövde jag hitta ett sätt att registrera framsteg genom en sekvens av satser utan att utlösa en uppgiftsväxel, vilket skulle förhindra att en krasch inträffade. Så jag kunde inte utnyttja det Put_Line()för att undvika att utföra I/O-operationer. Jag skulle kunna ställa in en räknarvariabel eller något liknande, men hur kan jag se dess värde om jag inte kan visa den på skärmen?

Vid granskning av loggen visade det sig också att trots frysningen i behandlingen av hjärtslagsmeddelanden, som blockerade alla I/O-operationer i processen och förhindrade annan bearbetning från att utföras, fortsatte andra oberoende uppgifter att utföras. Det vill säga att arbetet inte blockerades helt, bara en (kritisk) kedja av uppgifter.

Detta var ledtråden som behövdes för att utvärdera det blockerande uttrycket.

Jag gjorde ett Ada-paket som innehöll en uppgift, en uppräknad typ och en global variabel av den typen. Otal bokstaver var bundna till specifika uttryck för den problematiska sekvensen (t.ex. Incrementing_Buffer_Index, Locking_Mutex, Mutex_Unlocked), och infogade sedan tilldelningsuttryck i den som tilldelade motsvarande uppräkning till en global variabel. Eftersom objektkoden för allt detta helt enkelt lagrade en konstant i minnet, var uppgiftsbyte som ett resultat av dess exekvering extremt osannolikt. Vi var i första hand misstänksamma mot uttryck som kunde byta uppgiften, eftersom blockeringen inträffade vid körning snarare än att återvända när uppgiften byttes tillbaka (av flera skäl).

Spårningsuppgiften kördes helt enkelt i en slinga och kontrollerade med jämna mellanrum för att se om värdet på den globala variabeln hade ändrats. Med varje ändring sparades värdet i en fil. Sedan en kort väntan och en ny kontroll. Jag skrev variabeln till filen eftersom uppgiften endast kördes när systemet valde den för exekvering när uppgiften byttes i problemområdet. Vad som än hände i den här uppgiften skulle inte påverka andra, orelaterade blockerade uppgifter.

Det förväntades att när systemet nådde punkten att exekvera den problematiska koden, skulle den globala variabeln återställas när man flyttade till varje nästa uttryck. Då kommer något att hända som får uppgiften att växla, och eftersom dess exekveringsfrekvens (10 Hz) är lägre än övervakningsuppgiftens, kan monitorn fånga värdet på den globala variabeln och skriva det. I en normal situation kunde jag få en upprepad sekvens av en delmängd av uppräkningar: de sista värdena av variabeln vid tidpunkten för uppgiftsbytet. När den hängs ska den globala variabeln inte längre ändras, och det senast skrivna värdet kommer att indikera vilket uttryck som inte fullbordades.

Jag körde koden med spårning. Han frös. Och övervakningen fungerade som en klocka.

Loggen innehöll den förväntade sekvensen, som avbröts av ett värde som indikerar att en mutex hade anropats Unlock, och uppgiften är inte slutförd - som är fallet med tusentals tidigare samtal.

Apex-ingenjörer analyserade febrilt sin kod vid denna tidpunkt och hittade en plats i mutexen där, teoretiskt, ett lås kunde uppstå. Men sannolikheten var mycket låg, eftersom endast ett visst sekvens av händelser som inträffade vid en viss tidpunkt kunde leda till blockering. Murphys lag, killar, det är Murphys lag.

För att skydda den bit av kod jag behövde, ersatte jag mutex-funktionsanropen (byggda ovanpå OS-mutex-funktionaliteten) med ett litet inbyggt Ada mutex-paket för att kontrollera mutex-åtkomst till den biten.

Jag infogade den i koden och körde testet. Sju timmar senare fungerade koden fortfarande.

Min kod skickades till Rational, där de kompilerade den, plockade isär den och kontrollerade att den inte använde samma tillvägagångssätt som användes i de problematiska mutex-funktionerna.

Det här var den mest fullsatta kodgenomgången i min karriär 🙂 Det var ett tiotal ingenjörer och chefer i rummet med mig, ytterligare tio personer var på ett konferenssamtal - och alla undersökte cirka 20 rader kod.

Koden granskades, nya körbara filer sammanställdes och skickades in för formell regressionstestning. Ett par veckor senare lyckades nedräkningstestet och raketen lyfte.

Okej, det är väl och bra, men vad är poängen med historien?

Det var ett helt vidrigt problem. Hundratusentals rader kod, parallell exekvering, över ett dussin interagerande processer, dålig arkitektur och dålig implementering, gränssnitt för inbyggda system och miljontals spenderade dollar. Ingen press, eller hur.

Jag var inte den enda som arbetade med det här problemet, även om jag var i rampljuset när jag gjorde porteringen. Men även om jag gjorde det, betyder det inte att jag förstod alla hundratusentals rader kod, eller ens skummade dem. Koden och loggarna analyserades av ingenjörer över hela landet, men när de berättade för mig sina hypoteser om orsakerna till felet tog det mig bara en halv minut att motbevisa dem. Och när jag blev ombedd att analysera teorier skulle jag vidarebefordra det till någon annan, för det var uppenbart för mig att dessa ingenjörer gick åt fel håll. Låter förmätet? Ja, det är sant, men jag förkastade hypoteserna och förfrågningarna av en annan anledning.

Jag förstod problemets natur. Jag visste inte exakt var det hände eller varför, men jag visste vad som hände.

Genom åren har jag samlat på mig mycket kunskap och erfarenhet. Jag var en av pionjärerna med att använda Ada och förstod dess fördelar och nackdelar. Jag vet hur Ada runtime-bibliotek hanterar uppgifter och hanterar parallell exekvering. Och jag förstår lågnivåprogrammering på nivån minne, register och assembler. Jag har med andra ord djup kunskap inom mitt område. Och jag använde dem för att hitta orsaken till problemet. Jag arbetade inte bara runt buggen, jag förstod hur man hittade den i en mycket känslig körtidsmiljö.

Sådana historier om kamp med kod är inte särskilt intressanta för dem som inte är bekanta med egenskaperna och förutsättningarna för en sådan kamp. Men dessa berättelser hjälper oss att förstå vad som krävs för att lösa riktigt svåra problem.

För att lösa riktigt svåra problem behöver du vara mer än bara en programmerare. Du måste förstå kodens "öde", hur den interagerar med sin omgivning och hur själva miljön fungerar.

Och så får du din egen förstörda semestervecka.

Att fortsätta

Källa: will.com

Lägg en kommentar