
Detta Àr en översÀttningsartikel . Men först en liten inledning. Hur blir man zombies? Vi har alla varit dÀr nÀr man vill dra upp en vÀn eller kollega till sin nivÄ, men det funkar inte. Och det handlar inte sÄ mycket om dig som om dem: pÄ ena sidan vÀger en normal lön, uppgifter och sÄ vidare, pÄ den andra sidan vÀger behovet av att tÀnka. Att tÀnka Àr obehagligt och smÀrtsamt. De ger snabbt upp och fortsÀtter skriva kod utan att riktigt anvÀnda sin hjÀrna. Du förstÄr hur mycket energi det krÀvs för att övervinna barriÀren av inlÀrd hjÀlplöshet, och sÄ gör man helt enkelt inte det. SÄ blir de zombies som verkar kunna botas, men som ingen verkar vilja hjÀlpa.
NĂ€r jag sĂ„g att (ja, just den personen frĂ„n lĂ€roböckerna) och hĂ„ller en frĂ„gestund istĂ€llet för en förelĂ€sning, blev jag lite skeptisk. Som en bakgrund Ă€r Leslie en vĂ€rldsberömd forskare, författare till grundlĂ€ggande arbeten inom distribuerad databehandling, och kanske kĂ€nner ni honom via bokstĂ€verna La i ordet LaTeX â "Lamport TeX". Den andra oroande faktorn Ă€r hans krav: alla som kommer mĂ„ste (helt gratis) lyssna pĂ„ ett par av hans förelĂ€sningar i förvĂ€g, tĂ€nka ut minst en frĂ„ga och bara dĂ„ komma. Jag bestĂ€mde mig för att se vad Lamport pratar om â och det Ă€r fantastiskt! Det Ă€r precis den sak, den magiska lĂ€nken-tablett för att bota zombitillstĂ„ndet. Jag varnar: texten kan förarga dem som Ă€lskar överflexibla metoder och ogillar att testa det skrivna.
Efter introduktionen börjar sjÀlva översÀttningen av seminariet. Trevlig lÀsning!
Oavsett vilken uppgift du tar dig an, mÄste du alltid gÄ igenom tre steg:
- klargöra vilket mÄl du vill uppnÄ;
- bestÀmma hur du ska nÄ ditt mÄl;
- komma till ditt mÄl.
Detta gÀller Àven programmering. NÀr vi skriver kod behöver vi:
- klargöra vad programmet ska göra;
- bestÀmma hur det ska utföra sin uppgift;
- skriva motsvarande kod.
Det sista steget Àr sjÀlvklart mycket viktigt, men jag kommer inte att prata om det idag. IstÀllet kommer vi att diskutera de första tvÄ. Dessa Àr nÄgot som varje programmerare genomför innan de börjar arbeta. Man sÀtter sig inte ner för att skriva om man inte har bestÀmt vad man faktiskt skriver: en webblÀsare eller en databas. En tydlig bild av mÄlet mÄste alltid finnas. Och man tÀnker igenom vad programmet ska göra, istÀllet för att skriva huller om buller i hopp om att koden pÄ nÄgot sÀtt ska förvandlas till en webblÀsare.
Hur exakt sker denna förberedande planering av koden? Hur mycket tid bör vi lĂ€gga pĂ„ detta? Allt beror pĂ„ hur komplex problemet vi löser Ă€r. LĂ„t oss anta att vi vill skriva ett felfritt distribuerat system. I det fallet bör vi tĂ€nka igenom allt noggrant innan vi sĂ€tter oss för att koda. Men om vi bara behöver öka en heltalsvariabel med 1? Vid första anblicken verkar detta trivialt, och inga övervĂ€ganden behövs, men sedan kommer vi ihĂ„g att överflöd kan intrĂ€ffa. DĂ€rför, för att förstĂ„ om det Ă€r ett enkelt eller komplext problem â mĂ„ste man tĂ€nka efter först.
Om man i förvÀg tÀnker igenom potentiella lösningar pÄ problemet kan man undvika misstag. Men för detta krÀvs det att ditt tÀnkande Àr klart. För att uppnÄ detta behöver man skriva ner sina tankar. Jag gillar verkligen citatet av Dick Gindin: 'NÀr du skriver, visar naturen dig hur slarvigt ditt tÀnkande Àr'. Om du inte skriver, verkar det bara som om du tÀnker. Och man bör skriva ner sina tankar i form av specifikationer.
Specifikationer uppfyller mĂ„nga funktioner, sĂ€rskilt i stora projekt. Men jag kommer att prata om bara en av dem: de hjĂ€lper oss att tĂ€nka klart. Att tĂ€nka klart Ă€r mycket viktigt och ganska svĂ„rt, sĂ„ vi behöver all hjĂ€lp vi kan fĂ„ hĂ€r. PĂ„ vilket sprĂ„k ska vi skriva specifikationerna? Det Ă€r alltid den första frĂ„gan för programmerare: vilket sprĂ„k ska vi anvĂ€nda? Det finns inget rĂ€tt svar pĂ„ detta: problemen vi löser Ă€r för mĂ„nga och olika. För vissa Ă€r TLA+ anvĂ€ndbart â ett specifikationssprĂ„k som jag har utvecklat. För andra Ă€r det lĂ€ttare att anvĂ€nda kinesiska. Det beror helt pĂ„ situationen.
En annan viktig frÄga Àr: hur ska vi uppnÄ klarare tÀnkande? Svaret: vi mÄste tÀnka som forskare. Det Àr ett sÀtt att tÀnka som har visat sig vara mycket effektivt under de senaste 500 Ären. Inom vetenskapen bygger vi matematiska modeller av verkligheten. Astronomi var kanske den första riktiga vetenskapen. I den matematiska modellen som anvÀnds inom astronomi framstÀlls himlakroppar som punkter med massa, position och rörelse, Àven om de i verkligheten Àr extremt komplexa objekt med berg och hav, tidvatten och ebb. Denna modell, precis som alla andra, Àr skapad för att lösa specifika problem. Den Àr utmÀrkt för att avgöra vart teleskopet ska riktas om vi behöver hitta en planet. Men om du vill förutsÀga vÀdret pÄ denna planet, Àr denna modell inte tillrÀcklig.
Matematiken lÄter oss bestÀmma egenskaperna hos modellen. Och vetenskapen visar hur dessa egenskaper relaterar till verkligheten. LÄt oss prata om vÄr vetenskap, datavetenskap. Verkligheten vi arbetar med Àr berÀkningssystem av olika slag: processorer, spelkonsoler, datorer som kör program och sÄ vidare. Jag kommer att prata om att köra ett program pÄ en dator, men i stort sett gÀller alla dessa slutsatser för alla berÀkningssystem. Inom vÄr vetenskap anvÀnder vi mÄnga olika modeller: Turingmaskinen, delvis ordnade mÀngder av hÀndelser och mÄnga andra.
Vad Ă€r ett program? Det Ă€r vilken kod som helst som kan ses som sjĂ€lvstĂ€ndig. Anta att vi behöver skriva en webblĂ€sare. Vi utför tre uppgifter: vi designar programmets presentation för anvĂ€ndaren, skriver sedan en hög-nivĂ„ schema för programmet, och slutligen skriver vi koden. Under skrivningen av koden inser vi att vi behöver skriva ett verktyg för textformatering. HĂ€r igen mĂ„ste vi lösa tre uppgifter: faststĂ€lla vilken text detta verktyg ska returnera; vĂ€lja en algoritm för formatering; skriva koden. Denna uppgift har sin egen deluppgift: att korrekt infoga bindestreck i orden. Denna deluppgift löser vi ocksĂ„ i tre steg â som vi ser upprepas pĂ„ mĂ„nga nivĂ„er.
LĂ„t oss titta nĂ€rmare pĂ„ det första steget: vilken uppgift programmet löser. HĂ€r modellerar vi oftast programmet som en funktion som tar vissa indata och ger vissa utdata. Inom matematiken beskrivs en funktion vanligtvis som en ordnad mĂ€ngd par. Till exempel beskrivs funktionen att ta kvadraten av naturliga tal som mĂ€ngden {, , , , âŠ}. FunktionsomrĂ„det för en sĂ„dan funktion Ă€r mĂ€ngden av de första elementen i varje par, det vill sĂ€ga naturliga tal. För att definiera en funktion behöver vi ange dess funktionsomrĂ„de och formel.
Men funktioner inom matematik Ă€r inte detsamma som funktioner i programmeringssprĂ„k. Matematiken Ă€r betydligt enklare. Eftersom jag inte har tid för komplexa exempel, lĂ„t oss titta pĂ„ ett enkelt: en funktion i C-sprĂ„ket eller en statisk metod i Java som returnerar den största gemensamma delaren av tvĂ„ heltal. I specifikationen av denna metod skriver vi: berĂ€knar GCD(M,N) för argumenten M och N, dĂ€r GCD(M,N) â en funktion vars funktionsomrĂ„de Ă€r mĂ€ngden av par av heltal, och returvĂ€rdet Ă€r det största heltalet som Ă€r delbart med M och N. Hur relaterar denna modell till verkligheten? Modellen arbetar med heltal, medan vi i C eller Java har 32-bitars. intDenna modell gör att vi kan avgöra om algoritmen Ă€r korrekt GCD, men den förhindrar inte överflödesfel. För detta skulle en mer komplex modell krĂ€vas, vilket det inte finns tid för.
LÄt oss tala om begrÀnsningarna hos funktionen som en modell. Vissa program (till exempel operativsystem) syftar inte bara till att returnera ett visst vÀrde för vissa argument, de kan köras kontinuerligt. Dessutom lÀmpar sig funktionen som modell dÄligt för det andra steget: planering av hur uppgiften ska lösas. Snabbsortering och bubbel-sortering berÀknar samma funktion, men det Àr helt olika algoritmer. DÀrför anvÀnder jag en annan modell för att beskriva sÀttet att nÄ programmets mÄl, lÄt oss kalla den den standardiserade beteendemodellen. Programmet representeras hÀr som en mÀngd av alla tillÄtna beteenden, var och en av dem Àr en sekvens av tillstÄnd, och ett tillstÄnd Àr en tilldelning av vÀrden till variabler.
LÄt oss se hur det andra steget i Euklides algoritm kommer att se ut. Vi behöver berÀkna GCD(M, N). Vi initierar M som x, och N som y, och drar sedan bort den mindre av dessa variabler frÄn den större tills de Àr lika. Till exempel, om M = 12, och N = 18, kan vi beskriva följande beteende:
[x = 12, y = 18] â [x = 12, y = 6] â [x = 6, y = 6]
Och om M = 0 och N = 0? ĐĐŸĐ»Ń ĐŽĐ”Đ»ĐžŃŃŃ ĐœĐ° ĐČŃĐ” ŃĐžŃла, ĐżĐŸŃŃĐŸĐŒŃ ĐœĐ°ĐžĐ±ĐŸĐ»ŃŃĐ”ĐłĐŸ ЎДлОŃĐ”Đ»Ń ĐČ ŃŃĐŸĐŒ ŃĐ»ŃŃаД ĐœĐ”Ń. Đ ŃŃĐŸĐč ŃĐžŃŃаŃОО ĐœĐ°ĐŒ ĐœŃĐ¶ĐœĐŸ ĐČĐ”ŃĐœŃŃŃŃŃ Đș пДŃĐČĐŸĐŒŃ ŃĐ°ĐłŃ Đž ŃĐżŃĐŸŃĐžŃŃ: ĐŽĐ”ĐčŃŃĐČĐžŃДлŃĐœĐŸ лО ĐœĐ°ĐŒ ĐœŃĐ¶ĐœĐŸ ĐČŃŃĐžŃĐ»ŃŃŃ ĐĐĐ ĐŽĐ»Ń ĐœĐ”ĐżĐŸĐ»ĐŸĐ¶ĐžŃДлŃĐœŃŃ
ŃĐžŃДл? ĐŃлО ĐČ ŃŃĐŸĐŒ ĐœĐ”Ń ĐœĐ”ĐŸĐ±Ń
ĐŸĐŽĐžĐŒĐŸŃŃĐž, ŃĐŸ ĐœŃĐ¶ĐœĐŸ ĐżŃĐŸŃŃĐŸ ĐžĐ·ĐŒĐ”ĐœĐžŃŃ ŃпДŃĐžŃĐžĐșаŃĐžŃ.
HÀr Àr det vÀrt att göra en liten avstickare om produktivitet. Den mÀts ofta i antalet kodrader som skrivs per dag. Men ditt arbete Àr betydligt mer vÀrdefullt om du har blivit av med ett visst antal rader, eftersom du fÄr mindre plats för buggar. Och att bli av med kod Àr lÀttast just i det första steget. Det Àr fullt möjligt att du helt enkelt inte behöver alla de funktioner som du försöker implementera. Det snabbaste sÀttet att förenkla programmet och spara tid Àr att inte göra saker som inte bör göras. Det andra steget har den nÀst största potentialen för tidsbesparing. Om du mÀter produktivitet i antal skrivna rader, sÄ kommer planeringen av hur uppgiften ska utföras att göra dig mindre produktiv, eftersom du kan lösa samma uppgift med mindre kod. Jag kan inte ge exakt statistik hÀr, eftersom jag inte har nÄgot sÀtt att rÀkna det antal rader som jag inte skrev tack vare att jag lade tid pÄ specifikationen, det vill sÀga pÄ det första och andra steget. Och det gÄr inte att experimentera med detta, eftersom vi inte har rÀtt att utföra det första steget i experimentet, uppgiften Àr definierad i förvÀg.
I informella specifikationer Àr det lÀtt att förbise mÄnga svÄrigheter. Det Àr inget svÄrt med att skriva strikta specifikationer för funktioner, det kommer jag inte att diskutera. IstÀllet kommer vi att prata om att skriva strikta specifikationer för standardbeteendemodeller. Det finns en sats som sÀger att vilket beteende som helst kan beskrivas med hjÀlp av sÀkerhetsegenskaper (safety) och livaktighetsegenskaper (liveness). SÀkerhet betyder att inget dÄligt kommer att hÀnda, programmet kommer inte att ge felaktiga svar. Robusthet innebÀr att nÄgot bra kommer att hÀnda förr eller senare, det vill sÀga programmet kommer förr eller senare att ge rÀtt svar. I allmÀnhet Àr sÀkerhet en viktigare indikator, eftersom fel oftast uppstÄr hÀr. DÀrför kommer jag att spara tid genom att inte prata om robusthet, Àven om det sjÀlvklart ocksÄ Àr viktigt.
Vi uppnÄr sÀkerhet genom att först skriva ner mÄnga möjliga initiala tillstÄnd. Och för det andra relationerna med alla möjliga efterföljande tillstÄnd för varje tillstÄnd. Vi ska bete oss som forskare och definiera tillstÄnden matematiskt. Setet av initiala tillstÄnd beskrivs med en formel, till exempel i fallet med Euklides algoritm: (x = M) ⧠(y = N). För vissa vÀrden M och N finns det bara ett initialt tillstÄnd. Relationerna med nÀsta tillstÄnd beskrivs med en formel dÀr variablerna för nÀsta tillstÄnd skrivs med ett streck, och det aktuella tillstÄndet utan streck. I fallet med Euklides algoritm kommer vi att hantera en disjunktion av tvÄ formler, dÀr den ena x Àr det största vÀrdet, och den andra y:

I det första fallet Àr det nya vÀrdet y lika med det gamla vÀrdet pÄ y, och det nya vÀrdet pÄ x fÄr vi genom att subtrahera den mindre variabeln frÄn den större. I det andra fallet gör vi tvÀrtom.
LÄt oss ÄtergÄ till Euklides algoritm. Anta Äterigen att M = 12, N = 18. Detta definierar det unika initiala tillstÄndet, (x = 12) ⧠(y = 18). Sedan sÀtter vi in dessa vÀrden i formeln ovan och fÄr:

HĂ€r Ă€r den enda möjliga lösningen: x' = 18 - 12 â§ y' = 12, och vi fĂ„r beteendet: [x = 12, y = 18]. PĂ„ samma sĂ€tt kan vi beskriva alla tillstĂ„nd i vĂ„rt beteende: [x = 12, y = 18] â [x = 12, y = 6] â [x = 6, y = 6].
I det sista tillstĂ„ndet [x = 6, y = 6] kommer bĂ„da delarna av uttrycket att vara falska, dĂ€rför finns det inget nĂ€sta tillstĂ„nd. SĂ„ vi har en fullstĂ€ndig specifikation av det andra steget â som vi ser Ă€r det helt vanlig matematik, som hos ingenjörer och forskare, och inte konstig som inom datavetenskap.
Dessa tvÄ formler kan kombineras till en enda formel för tidslogik. Den Àr elegant och lÀtt att förklara, men det finns ingen tid för det just nu. Tidslogik kan behövas för egenskapen livlighet, men den Àr inte nödvÀndig för sÀkerhet. Tidslogik som sÄdan tilltalar inte, det Àr inte helt vanlig matematik, men i fallet med livlighet utgör den ett nödvÀndigt ont.
I Euklides algoritm för varje vÀrde x och y finns unika vÀrden x' och y', som gör att förhÄllandet med nÀsta tillstÄnd Àr sant. Med andra ord Àr Euklides algoritm deterministisk. För att modellera en icke-deterministisk algoritm mÄste det nuvarande tillstÄndet ha flera möjliga framtida tillstÄnd, och varje vÀrde av variabeln utan streck mÄste ha flera vÀrden av variabeln med streck, vid vilka förhÄllandet med nÀsta tillstÄnd Àr sant. Detta Àr inte svÄrt att göra, men jag kommer inte att ge exempel just nu.
För att skapa ett fungerande verktyg behövs formell matematik. Hur gör man en specifikation formell? För detta behöver vi ett formellt sprÄk, till exempel, . Specifikationen av Euklides algoritm skulle se ut sÄ hÀr pÄ detta sprÄk:

Symbolen för likhet med en triangel betyder att vÀrdet till vÀnster om tecknet definieras som lika med vÀrdet till höger om tecknet. I huvudsak Àr en specifikation en definition, i vÄrt fall tvÄ definitioner. Till specifikationen i TLA+ mÄste man lÀgga till deklarationer och viss syntax, som pÄ bilden ovan. I ASCII skulle det se ut sÄ hÀr:

Som vi ser Àr ingenting komplicerat. Specifikationen i TLA+ kan verifieras, det vill sÀga alla möjliga beteenden kan granskas i en liten modell. I vÄrt fall kommer denna modell att vara specifika vÀrden M och N. Detta Àr ett mycket effektivt och enkelt sÀtt att verifiera pÄ, som helt och hÄllet utförs automatiskt. Dessutom kan man skriva formella bevis för sanningen och verifiera dem mekaniskt, men det krÀver mycket tid, dÀrför görs det sÀllan.
Den största nackdelen med TLA+ Ă€r att det Ă€r matematik, och programmerare och datavetare Ă€r rĂ€dda för matematik. Vid första anblick lĂ„ter detta som ett skĂ€mt, men tyvĂ€rr sĂ€ger jag detta helt seriöst. Min kollega berĂ€ttade just för mig hur han försökte förklara TLA+ för flera utvecklare. SĂ„ fort formlerna dök upp pĂ„ skĂ€rmen fick de genast glasartade ögon. SĂ„ om TLA+ skrĂ€mmer, kan man anvĂ€nda , som Ă€r en slags leksprĂ„k för programmering. Uttrycken i PlusCal kan vara vad som helst som TLA+ uttrycker, det vill sĂ€ga, i stort sett vilket matematiskt uttryck som helst. Dessutom har PlusCal syntax för icke-deterministiska algoritmer. Tack vare att man kan uttrycka vilket TLA+-uttryck som helst i PlusCal, Ă€r den betydligt mer uttrycksfull Ă€n nĂ„got verkligt programmeringssprĂ„k. Vidare kompileras PlusCal till en lĂ€ttlĂ€st specifikation av TLA+. Detta innebĂ€r givetvis inte att en komplex PlusCal-specifikation blir enkel i TLA+ â det finns bara en uppenbar överensstĂ€mmelse mellan dem, ingen extra komplexitet framtrĂ€der. Slutligen kan den specifikationen kontrolleras med TLA+ verktyg. Sammanfattningsvis kan PlusCal hjĂ€lpa till att övervinna rĂ€dslan för matematik, det Ă€r lĂ€tt att förstĂ„ Ă€ven för programmerare och datavetare. Tidigare publicerade jag under en tid (ungefĂ€r 10 Ă„r) algoritmer pĂ„ det.
Möjligen kan nĂ„gon invĂ€nda att TLA+ och PlusCal Ă€r matematik, och matematik fungerar bara pĂ„ pĂ„hittade exempel. I praktiken behövs ett verkligt sprĂ„k med typer, procedurer, objekt och sĂ„ vidare. SĂ„ Ă€r det inte. HĂ€r Ă€r vad Chris Newcomb, som arbetat pĂ„ Amazon, skriver: âVi anvĂ€nde TLA+ i tio stora projekt, och i varje fall bidrog dess anvĂ€ndning betydligt till utvecklingen, eftersom vi kunde fĂ„nga farliga buggar innan de kom till produktion, och för att det gav oss förstĂ„elsen och tryggheten som behövdes för aggressiva optimeringar av prestanda utan att pĂ„verka programmets sanningsenlighetâ. Man hör ofta att anvĂ€ndning av formella metoder ger ineffektiv kod â i praktiken Ă€r det dock precis tvĂ€rtom. Dessutom finns det en uppfattning om att det Ă€r omöjligt att övertyga chefer om behovet av formella metoder, Ă€ven nĂ€r programmerare Ă€r övertygade om deras nyttighet. Och Newcomb skriver: Managerna uppmuntrar nu pĂ„ alla sĂ€tt att skriva specifikationer pĂ„ TLA+, och avsĂ€tter sĂ€rskild tid för detta.. SĂ„ nĂ€r managerna ser att TLA+ fungerar, tar de gladeligen till sig det. Chris Newcomb skrev detta för ungefĂ€r sex mĂ„nader sedan (i oktober 2014), och sĂ„vitt jag vet anvĂ€nds TLA+ nu i 14 projekt, inte 10. Ett annat exempel rör designen av XBox 360. En praktikant kom till Charles Ticker och skrev en specifikation för minnessystemet. Tack vare denna specifikation upptĂ€cktes en bugg som annars inte skulle ha mĂ€rkts, och som skulle ha fĂ„tt varje XBox 360 att krascha efter fyra timmars anvĂ€ndning. Ingenjörer frĂ„n IBM bekrĂ€ftade att deras tester inte skulle ha upptĂ€ckt denna bugg.
Du kan lÀsa mer om TLA+ pÄ internet, men nu lÄt oss prata om informella specifikationer. Vi skriver sÀllan program som berÀknar det minsta gemensamma multipel och liknande. Mycket oftare skriver vi program som ett verktyg för strukturell utskrift (pretty-printer), som jag skrev för TLA+. Efter den enklaste bearbetningen skulle koden pÄ TLA+ se ut sÄ hÀr:

Men i det givna exemplet ville anvÀndaren förmodligen att konjunktions- och likhetstecknen skulle vara justerade. SÄ det korrekta formatet skulle se ut sÄ hÀr:

LÄt oss titta pÄ ett annat exempel:

HÀr var dÀremot justeringen av likhetstecken, additions- och multiplikationstecken i kÀllan slumpmÀssig, sÄ den enklaste bearbetningen rÀcker gott. Generellt finns det ingen exakt matematisk definition av korrekt formatering, eftersom "korrekt" i detta fall betyder "sÄsom anvÀndaren önskar", och det Àr matematiskt omöjligt att definiera.
Det verkar som att om vi inte har en definition av sanningsenlighet, Ă€r specifikationen vĂ€rdelös. Men sĂ„ Ă€r det inte. Om vi inte vet exakt vad programmet ska göra, betyder det inte att vi inte behöver tĂ€nka pĂ„ dess funktion â tvĂ€rtom, vi bör lĂ€gga Ă€nnu mer tid pĂ„ detta. Specifikationen Ă€r sĂ€rskilt viktig hĂ€r. Det Ă€r omöjligt att definiera det optimala programmet för strukturell utskrift, men det betyder inte att vi inte ska arbeta med det överhuvudtaget; att skriva kod som en ström av medvetande Ă€r inte rĂ€tt metod. Slutligen skrev jag en specifikation med sex regler med definitioner i form av kommentarer i Java-filen. HĂ€r Ă€r ett exempel pĂ„ en av reglerna: en left-comment-token Ă€r LeftComment som Ă€r anpassat till sin överordnande token. Denna regel Ă€r skriven pĂ„, lĂ„t oss sĂ€ga, matematisk engelska: LeftComment anpassat, left-comment och överordnad token â termer med definitioner. SĂ„ hĂ€r beskriver matematiker matematik: de skriver definitioner av termer och baserat pĂ„ dem â regler. Fördelen med en sĂ„dan specifikation Ă€r att det Ă€r betydligt enklare att förstĂ„ och felsöka sex regler Ă€n 850 rader kod. Jag mĂ„ste sĂ€ga att det var inte lĂ€tt att skriva dessa regler, det tog ganska mycket tid att felsöka dem. Speciellt för detta syfte skrev jag en kod som meddelade vilken regel som anvĂ€ndes. Tack vare att jag testade dessa sex regler med flera exempel behövde jag inte felsöka 850 rader kod, och buggarna visade sig vara ganska lĂ€tta att hitta. I Java finns det utmĂ€rkta verktyg för detta. Om jag bara hade skrivit koden skulle det ha tagit betydligt mer tid, och formatet skulle ha blivit av sĂ€mre kvalitet.
Varför kunde man inte anvĂ€nda en formell specifikation? Ă ena sidan Ă€r korrektheten i detta fall inte sĂ„ viktig. Strukturell utskrift kommer definitivt att ogillas av nĂ„gon, sĂ„ jag behövde inte strĂ€va efter att fĂ„ det att fungera korrekt i alla ovanliga situationer. Ănnu viktigare Ă€r att jag inte hade adekvata verktyg. Ett verktyg för att kontrollera TLA+-modeller Ă€r hĂ€r vĂ€rdelöst, sĂ„ jag skulle behöva skriva exempel manuellt.
Den angivna specifikationen har drag som Àr gemensamma för alla specifikationer. Den Àr pÄ en högre nivÄ Àn kod. Den kan implementeras pÄ vilket sprÄk som helst. För att skriva den Àr verktyg eller metoder onödiga. Ingen programmeringskurs kommer att hjÀlpa dig skriva denna specifikation. Och det finns inga verktyg som skulle kunna göra denna specifikation onödig, sÄvida du inte skriver ett sprÄk speciellt för att skriva program för strukturell utskrift pÄ TLA+. Slutligen sÀger denna specifikation ingenting om hur vi faktiskt kommer att skriva kod, den anger bara vad denna kod gör. Vi skriver specifikationen för att hjÀlpa oss tÀnka igenom problemet innan vi börjar tÀnka pÄ koden.
Men denna specifikation har ocksÄ egenskaper som skiljer den frÄn andra specifikationer. 95 % av andra specifikationer Àr betydligt kortare och enklare:

Vidare Ă€r denna specifikation en uppsĂ€ttning regler. I allmĂ€nhet Ă€r detta ett tecken pĂ„ en dĂ„lig specifikation. Att förstĂ„ konsekvenserna av en uppsĂ€ttning regler Ă€r ganska svĂ„rt, och det Ă€r dĂ€rför jag har fĂ„tt spendera mycket tid pĂ„ att debugga dem. ĂndĂ„ sĂ„ fann jag inget bĂ€ttre sĂ€tt i det hĂ€r fallet.
Det Ă€r vĂ€rt att sĂ€ga nĂ„gra ord om program som körs kontinuerligt. Som regel arbetar de parallellt, till exempel operativsystem eller distribuerade system. Att förstĂ„ dem i huvudet eller pĂ„ papper kan mycket fĂ„, och jag rĂ€knar inte mig sjĂ€lv bland dem, Ă€ven om det en gĂ„ng var möjligt för mig. DĂ€rför behövs verktyg som kan kontrollera vĂ„rt arbete â till exempel TLA+ eller PlusCal.
Varför behövde jag skriva en specifikation, om jag redan visste vad koden skulle göra? Egentligen trodde jag bara att jag visste det. Dessutom, med en specifikation behöver en utomstÄende person inte lÀngre gÄ in i koden för att förstÄ vad den gör. Jag har en regel: det ska inte finnas nÄgra allmÀnna regler. Denna regel har dock ett undantag, den Àr den enda allmÀnna regeln som jag följer: specifikationen för vad koden gör ska informera mÀnniskor om allt de behöver veta nÀr de anvÀnder denna kod.
SÄ vad behöver programmerare veta om tÀnkande? Först och frÀmst, samma som alla andra: om du inte skriver, sÄ verkar det bara som om du tÀnker. Dessutom mÄste man tÀnka innan man kodar, vilket betyder att man mÄste skriva innan man kodar. Specifikationen Àr det vi skriver innan vi börjar koda. Specifikationen behövs för all kod som kan anvÀndas eller Àndras av nÄgon annan. Och denna "nÄgon annan" kan mycket vÀl vara kodens skapare en mÄnad efter att den skrivits. Specifikationer behövs för stora program och system, för klasser, för metoder och ibland Àven för komplexa delar av enskilda metoder. Vad behöver man skriva om koden? Man bör beskriva vad den gör, det vill sÀga det som kan vara anvÀndbart för alla som anvÀnder denna kod. Ibland kan det ocksÄ vara nödvÀndigt att ange hur precis koden nÄr sitt mÄl. Om vi har gÄtt igenom den metoden under algoritmkurser kallar vi det för en algoritm. Om det Àr nÄgot mer speciellt och nytt kallar vi det för högnivÄdesign. Det finns ingen formell skillnad hÀr: bÄda Àr abstrakta modeller av programmet.
Hur ska man skriva en kodspecifikation? Det viktigaste: den bör vara ett steg högre Àn sjÀlva koden. Den bör beskriva tillstÄnd och beteenden. Den mÄste vara sÄ strikt som uppgiften krÀver. Om du skriver en specifikation för hur en uppgift ska implementeras kan den skrivas i pseudokod eller med PlusCal. Att lÀra sig skriva specifikationer bör göras pÄ formella specifikationer. Det kommer att ge dig de nödvÀndiga fÀrdigheterna som ocksÄ hjÀlper med informella specifikationer. Men hur lÀr man sig skriva formella specifikationer? NÀr vi lÀrde oss programmering skrev vi program och felsökte dem. Detsamma gÀller hÀr: du mÄste skriva en specifikation, testa den med ett modellkontrollverktyg och rÀtta till eventuella fel. TLA+ kanske inte Àr det bÀsta sprÄket för formella specifikationer, och för dina specifika behov Àr det troligt att ett annat sprÄk passar bÀttre. Fördelen med TLA+ Àr att det lÀr ut matematiskt tÀnkande pÄ ett utmÀrkt sÀtt.
Hur kopplar man samman specifikationen och koden? Genom kommentarer som kopplar matematiska koncept till deras implementation. Om du arbetar med grafer kommer du pÄ programnivÄ att ha arrayer av noder och arrayer av kopplingar. DÀrför mÄste du skriva ner hur grafen konkret implementeras med dessa programmeringsstrukturer.
Det Ă€r viktigt att notera att inget av det som sagts ovan rör sjĂ€lva kodskrivningsprocessen. NĂ€r du skriver kod, det vill sĂ€ga utför det tredje steget, behöver du ocksĂ„ tĂ€nka och planera programmet. Om en deluppgift visar sig vara komplex eller otydlig, Ă€r det nödvĂ€ndigt att skriva en specifikation för den. Men jag pratar inte om sjĂ€lva koden hĂ€r. Du kan anvĂ€nda vilket programmeringssprĂ„k eller metodologi som helst, det handlar inte om dem. Dessutom befriar inget av det som sagts ovan frĂ„n behovet av att testa och debugga koden. Ăven om den abstrakta modellen Ă€r korrekt skriven kan det finnas buggar i dess implementation.
Skrivande av specifikationer Ă€r ett extra steg i kodningsprocessen. Tack vare det kan mĂ„nga fel upptĂ€ckas med mindre anstrĂ€ngning â vi vet detta frĂ„n erfarenheten av programmerare hos Amazon. Med specifikationer blir programkvaliteten högre. SĂ„ varför klarar vi oss sĂ„ ofta utan dem? För att det Ă€r svĂ„rt att skriva. Och det Ă€r svĂ„rt att skriva eftersom det krĂ€ver eftertanke, och att tĂ€nka Ă€r ocksĂ„ svĂ„rt. Det Ă€r alltid enklare att lĂ„tsas tĂ€nka. HĂ€r kan man dra en parallell med löpning â ju mindre du springer, desto lĂ„ngsammare springer du. Du behöver trĂ€na dina muskler och öva pĂ„ skrivandet. Praktik Ă€r nödvĂ€ndig.
Specifikationen kan vara felaktig. Du kan ha gjort ett misstag nÄgonstans, eller kraven kan ha förÀndrats, eller det kan ha blivit nödvÀndigt att göra förbÀttringar. All kod som nÄgon anvÀnder mÄste Àndras, sÄ förr eller senare kommer specifikationen att sluta överensstÀmma med programmet. I idealfallet bör man i sÄ fall skriva en ny specifikation och helt skriva om koden. Vi vet mycket vÀl att ingen gör sÄ. I praktiken patchar vi koden och kanske uppdaterar specifikationen. Men om detta oundvikligen hÀnder förr eller senare, varför ska vi dÄ skriva specifikationer överhuvudtaget? För det första, för den person som kommer att redigera din kod Àr varje överflödigt ord i specifikationen guld vÀrd, och den personen kan mycket vÀl vara du sjÀlv. Jag klandrar mig ofta för bristande specifikationer nÀr jag redigerar min kod. Och jag skriver fler specifikationer Àn kod. DÀrför bör du alltid uppdatera specifikationen nÀr du redigerar koden. För det andra, med varje redigering blir koden sÀmre, den blir allt svÄrare att lÀsa och underhÄlla. Detta Àr en ökning av entropin. Men om du inte börjar med en specifikation, sÄ kommer varje rad som skrivs att vara en redigering, och koden kommer frÄn början att bli otymplig och svÄrlÀst.
Som Eisenhower sa , ingen strid har vunnits enligt planen, och ingen strid har vunnits utan plan. Och han visste en del om strider. Det finns en Äsikt att skriva specifikationer Àr en slöseri med tid. Ibland Àr det verkligen sÄ, och uppgiften Àr sÄ enkel att den inte krÀver nÄgon djupare eftertanke. Men man mÄste alltid komma ihÄg att nÀr nÄgon rekommenderar att du inte ska skriva specifikationer, sÄ rekommenderar de att du inte ska tÀnka. Och detta bör man tÀnka pÄ varje gÄng. Att tÀnka igenom en uppgift garanterar inte att du inte gör misstag. Som vi vet har ingen uppfunnit ett magiskt spö, och programmering Àr en komplex uppgift. Men om du inte tÀnker igenom uppgiften, kommer du garanterat att göra misstag.
Du kan lÀsa mer om TLA+ och PlusCal pÄ en sÀrskild webbplats, som du kan nÄ frÄn min hemsida . Det var allt för mig, tack för uppmÀrksamheten.
Jag pÄminner om att detta Àr en översÀttning. NÀr du skriver kommentarer, kom ihÄg att författaren inte kommer att lÀsa dem. Om du verkligen vill kommunicera med författaren sÄ kommer han att vara pÄ konferensen Hydra 2019, som Àger rum den 11-12 juli 2019 i Sankt Petersburg. Biljetter kan köpas .
KĂ€lla: habr.com
