ProgrammēŔana — vairāk nekā kodēŔana

ProgrammēŔana — vairāk nekā kodēŔana

Å is ir tulkojuma raksts Stenforda semināra. Bet pirms tam neliels ievads. Kā veidojas zombiji? Ikviens ir nonācis situācijā, kad vēlas pacelt draugu vai kolēģi lÄ«dz savam lÄ«menim, bet tas neizdodas. Un ā€žneizdodasā€ ne tik daudz tev, cik viņam: uz vienas kausa svara ir normāla alga, uzdevumi un tā tālāk, bet uz otras — nepiecieÅ”amÄ«ba domāt. Domāt ir nepatÄ«kami un sāpÄ«gi. ViņŔ ātri padodas un turpina rakstÄ«t kodu, pilnÄ«gi neieslēdzot prātu. Tu vari iedomāties, cik daudz spēku ir jātērē, lai pārvarētu iemācÄ«tās bezpalÄ«dzÄ«bas barjeru, un tu vienkārÅ”i nedari to. Tā veidojas zombiji, kurus it kā var izārstēt, bet it kā neviens ar to nenodarbojas.

Kad es redzēju, ka Leslijs Lamports (jā-jā, tas pats cilvēks no mācÄ«bu grāmatām) ierodas Krievijā un taisa nevis ziņojumu, bet jautājumu-atbilžu sesiju, es nedaudz norakstÄ«ju. Katrā ziņā, Leslijs — vispasaules pazÄ«stams zinātnieks, pamatu darbu autors izkliedētajā skaitļoÅ”anā, kā arÄ« jÅ«s varat viņu pazÄ«t pēc burtiem La vārdā LaTeX — ā€žLamport TeXā€. Otra satraucoŔā lieta ir viņa prasÄ«ba: ikvienam, kas ieradÄ«sies, jābÅ«t (absolÅ«ti par brÄ«vu) iepriekÅ” noklausÄ«jies pāris viņa ziņojumu, izdomājis vismaz vienu jautājumu un tikai tad ieradies. Nolēmu paskatÄ«ties, ko Lamports vēsta — un tas ir lieliski! Tas ir tieÅ”i tā, maÄ£iskā saite-tablete zombju ārstēŔanai. BrÄ«dināŔu: tekstā varētu bÅ«t nopietni saskarsmē ar tiem, kas ir par superelastÄ«gām metodēm un pret testēŔanu, ko viņi ir rakstÄ«juÅ”i.

Pēc habrokata, principā, sākas semināra tulkojums. PatÄ«kamu lasīŔanu!

Par kuru uzdevumu jūs nolemjat, jums vienmēr jānokārto trīs soļi:

  • nolēmt, kādu mērÄ·i jÅ«s vēlaties sasniegt;
  • izdomāt, kā tieÅ”i jÅ«s sasniegsiet savu mērÄ·i;
  • nonākt pie sava mērÄ·a.

Tas attiecas arÄ« uz programmēŔanu. Kad mēs rakstām kodu, mums ir nepiecieÅ”ams:

  • nolēmt, ko tieÅ”i programmai vajadzētu darÄ«t;
  • noteikt, kā tieÅ”i tai vajadzētu veikt savu uzdevumu;
  • uzrakstÄ«t atbilstoÅ”o kodu.

Pēdējais solis, protams, ir ļoti svarÄ«gs, taču Å”odien par to nerunāŔu. Tā vietā apspriedÄ«sim pirmos divus. Tos veic katrs programmētājs pirms sākt darbu. JÅ«s nesākat rakstÄ«t, ja neesat izdomājis, ko tieÅ”i rakstāt: pārlÅ«kprogrammu vai datu bāzi. Noteiktai izpratnei par mērÄ·i ir jābÅ«t obligāti. Un jums obligāti jāizdomā, ko tieÅ”i programma darÄ«s, nevis jāraksta kaut kādā veidā, cerot, ka kods pats par sevi pārvērtÄ«sies par pārlÅ«kprogrammu.

Kā tieÅ”i notiek Ŕī priekÅ”izpēte koda izstrādei? Cik daudz pūļu mums tam vajadzētu tērēt? Viss ir atkarÄ«gs no tā, cik sarežģītu problēmu mēs risinām. Pieņemsim, ka mēs vēlamies uzrakstÄ«t izturÄ«gu izkliedētu sistēmu. Å ajā gadÄ«jumā mums jāizdomā viss kārtÄ«gi, pirms sēžamies pie koda. Bet, ja mums vienkārÅ”i jāpalielina vesela skaitļa mainÄ«gā vērtÄ«ba par 1? Pirmajā mirklÄ« Å”eit viss Ŕķiet cita lieta, un nav nepiecieÅ”ams domāt, taču pēc tam mēs atceramies, ka var notikt pārsniegums. Tādēļ pat, lai saprastu, vai problēma ir vienkārÅ”a vai sarežģīta — vispirms jāpadomā.

Ja iepriekÅ” padomājat par iespējamiem problēmas risinājumiem, varat izvairÄ«ties no kļūdām. Bet tam ir nepiecieÅ”ams, lai jÅ«su domāŔana bÅ«tu skaidra. Lai to sasniegtu, ir jāvēro savas domas. Man ļoti patÄ«k Dika Gindona citāts: Ā«Kad jÅ«s rakstāt, daba jums parāda, cik nekārtÄ«ga ir jÅ«su domāŔanaĀ». Ja jÅ«s nerakstāt, jums tikai liekas, ka domājat. Un domas jāreÄ£istrē specifikāciju formā.

Specifikācijas veic daudzas funkcijas, jo Ä«paÅ”i lielos projektos. Bet es runāŔu tikai par vienu no tām: tās palÄ«dz mums skaidri domāt. Skaidra domāŔana ir ļoti svarÄ«ga un diezgan grÅ«ta, tāpēc Å”eit mums ir nepiecieÅ”ams jebkāds atbalsts. Kādā valodā mums vajadzētu rakstÄ«t specifikācijas? Tas vienmēr ir pirmais jautājums programmētājiem: kādā valodā mēs rakstÄ«sim. Uz to nav vienas pareizas atbildes: problēmas, kuras mēs risinām, ir pārāk daudzveidÄ«gas. Dažiem noder TLA+ — tas ir specifikāciju valoda, ko es izstrādāju. Citiem ērtāk izmantot Ä·Ä«nieÅ”u valodu. Viss ir atkarÄ«gs no situācijas.

Ir svarÄ«gāks jautājums: kā panākt skaidrāku domāŔanu? Atbilde: mums jādomā kā zinātniekiem. Å Ä« domāŔana ir izcili sevi pierādÄ«jusi pēdējo 500 gadu laikā. Zinātnē mēs veidojam matemātiskās realitātes modeļus. Astronomija, iespējams, bija pirmā zinātne, kurai Å”is vārds patieŔām atbilst. Matemātiskajā modelÄ«, ko izmanto astronomijā, debess Ä·ermeņi tiek attēloti kā punkti ar masu, atraÅ”anās vietu un impulsu, lai gan realitātē tie ir ārkārtÄ«gi sarežģīti objekti ar kalniem un okeāniem, plÅ«diem un paisumiem. Å is modelis, tāpat kā jebkurÅ” cits, ir izveidots, lai risinātu konkrētas problēmas. Tas lieliski piemērots, lai noskaidrotu, kur jāpavērÅ” teleskops, ja jāatrod planēta. Bet, ja vēlaties prognozēt laiku Å”ajā planētā, Å”is modelis nebÅ«s piemērots.

Matemātika ļauj mums noteikt modeļa Ä«paŔības. Bet zinātne parāda, kā Ŕīs Ä«paŔības attiecās uz realitāti. Parunāsim par mÅ«su zinātni, datorzinātni. Realitāte, ar kuru mēs strādājam, ir dažādu veidu aprēķinu sistēmas: procesori, spēļu konsoles, datori, kas izpilda programmas, un tā tālāk. Es runāŔu par programmas izpildi datorā, bet lielākā mērā visi Å”ie secinājumi attiecas uz jebkuru aprēķinu sistēmu. MÅ«su zinātnē mēs izmantojam daudz dažādu modeļu: Tjuringa maŔīnu, daļēji sakārtotas notikumu kopas un daudzus citus.

Kas ir programma? Tā ir jebkāds kods, ko var apsvērt patstāvÄ«gi. Pieņemam, ka mums jāuzraksta pārlÅ«ks. Mēs veicam trÄ«s uzdevumus: projektējam programmas iesniegÅ”anu lietotājam, tad rakstām augstākas pakāpes programmas shēmu un, visbeidzot, rakstām kodu. Rakstot kodu, mēs saprotam, ka mums jāraksta rÄ«ks teksta formatēŔanai. Å eit mums atkal jārisina trÄ«s uzdevumi: noteikt, kāds teksts tiks atgriezts Å”im rÄ«kam; izvēlēties algoritmu formatēŔanai; uzrakstÄ«t kodu. Å im uzdevumam ir sava apakÅ”uzdevums: pareizi ievietot defises vārdos. Å o apakÅ”uzdevumu arÄ« risinām trÄ«s posmos — kā redzam, tie atkārtojas daudzos lÄ«meņos.

Apskatīsim tuvāk pirmo soli: kādu uzdevumu risina programma. Šeit mēs bieži vien modelējam programmu kā funkciju, kas saņem noteiktus ievades datus un dod noteiktus iznākuma datus. Matematikā funkcija parasti tiek aprakstīta kā sakārtots pāru kopums. Piemēram, kvadrāta funkcija dabiskajiem skaitļiem tiek aprakstīta kā kopums {, , , , ...}. Šādas funkcijas definīcijas joma ir pirmo elementu kopums katrā pārī, proti, dabiskie skaitļi. Lai definētu funkciju, mums jānorāda tās definīcijas joma un formula.

Bet matemātikas funkcijas nav tas pats, kas funkcijas programmēŔanas valodās. Matemātika ir daudz vienkārŔāka. Tā kā man nav laika sarežģītiem piemēriem, aplÅ«kosim vienkārÅ”u: funkcija valodā C vai statisks statiskā metode Java, kas atgriež divu veselu skaitļu lielāko kopÄ«go dalÄ«tāju. Å Ä« metode specifikācijā mēs rakstÄ«sim: aprēķina GCD(M,N) argumentiem M un N, kur GCD(M,N) — funkcija, kuras definÄ«cijas joma ir veselu skaitļu pāru kopums, bet atgrieztā vērtÄ«ba ir lielākais vesels skaitlis, kas dala M un N. Kā Å”is modelis attiecās uz realitāti? Modelis strādā ar veseliem skaitļiem, taču C vai Java mēs strādājam ar 32 bitu int. Å is modelis ļauj mums noskaidrot, vai algoritms ir pareizs GCD, bet tas nepieļaus pārsnieguma kļūdas. Tam vajadzētu bÅ«t sarežģītākam modelim, uz kuru nav laika.

Parunāsim par funkcijas ierobežojumiem kā modeli. Dažas programmu (piemēram, operētājsistēmu) darbÄ«bas nevar samazināt lÄ«dz noteiktas vērtÄ«bas atgrieÅ”anai konkrētiem argumentiem, tās var darboties nepārtraukti. Turklāt funkcija kā modelis slikti der otrajam solim: uzdevuma risināŔanas veida plānoÅ”anai. Ātrā ŔķiroÅ”ana un burbuļu ŔķiroÅ”ana aprēķina to paÅ”u funkciju, bet tie ir pilnÄ«gi atŔķirÄ«gi algoritmi. Tādēļ programmas mērÄ·a sasniegÅ”anas veida aprakstīŔanai es izmantoju citu modeli, kuru nosauksim par standarta uzvedÄ«bas modeli. Programmā tas tiek attēlots kā visu atļauto uzvedÄ«bu kopa, no kurām katra, savukārt, ir stāvokļu secÄ«ba, un stāvoklis ir vērtÄ«bu pieŔķirÅ”ana mainÄ«gajiem.

ApskatÄ«sim, kā izskatÄ«sies otrais solis Euklida algoritmam. Mums ir jāsaskaita GCD(M, N). Mēs inicializējam M kā x, bet N kā y, pēc tam atkārtoti atņemam mazāko no Ŕīm mainÄ«gajām no lielākā, lÄ«dz tās kļūst vienādas. Piemēram, ja M = 12, bet N = 18, mēs varam aprakstÄ«t sekojoÅ”o uzvedÄ«bu:

[x = 12, y = 18] → [x = 12, y = 6] → [x = 6, y = 6]

Bet, ja M = 0 un N = 0? ŠŠ¾Š»ŃŒ Š“ŠµŠ»ŠøŃ‚ŃŃ на все числа, ŠæŠ¾ŃŃ‚Š¾Š¼Ńƒ наибольшего Š“ŠµŠ»ŠøŃ‚ŠµŠ»Ń в ŃŃ‚Š¾Š¼ ŃŠ»ŃƒŃ‡Š°Šµ нет. Š’ ŃŃ‚Š¾Š¹ ŃŠøŃ‚ŃƒŠ°Ń†ŠøŠø нам нужно Š²ŠµŃ€Š½ŃƒŃ‚ŃŒŃŃ Šŗ ŠæŠµŃ€Š²Š¾Š¼Ńƒ шагу Šø ŃŠæŃ€Š¾ŃŠøŃ‚ŃŒ: Š“ŠµŠ¹ŃŃ‚Š²ŠøŃ‚ŠµŠ»ŃŒŠ½Š¾ ли нам нужно Š²Ń‹Ń‡ŠøŃŠ»ŃŃ‚ŃŒ ŠŠžŠ” Š“Š»Ń Š½ŠµŠæŠ¾Š»Š¾Š¶ŠøŃ‚ŠµŠ»ŃŒŠ½Ń‹Ń… чисел? Если в ŃŃ‚Š¾Š¼ нет необхоГимости, то нужно просто ŠøŠ·Š¼ŠµŠ½ŠøŃ‚ŃŒ ŃŠæŠµŃ†ŠøŃ„ŠøŠŗŠ°Ń†ŠøŃŽ.

Å eit ir vērts nedaudz atkāpties par produktivitāti. To bieži mēra ar dienā uzrakstÄ«to rindu skaitu. Tomēr jÅ«su darbs ir ievērojami izdevÄ«gāks, ja esat samazinājuÅ”i noteiktu rindu skaitu, jo jums ir mazāk vietas kļūdām. Un no koda ir visvieglāk atbrÄ«voties tieÅ”i pirmajā solÄ«. Ir iespējams, ka jums vispār nav nepiecieÅ”ami visi tie sarežģījumi, kurus mēģināt Ä«stenot. Ātrākais veids, kā vienkārÅ”ot programmu un ietaupÄ«t laiku, ir nedarÄ«t lietas, kuras nevajag darÄ«t. Otrais solis ir otrajā vietā pēc potenciāla laika ietaupīŔanai. Ja jÅ«s mērat produktivitāti ar uzrakstÄ«tajām rindām, tad uzdevuma izpildes veida pārdomāŔana padara jÅ«s mazāk produktÄ«vus, jo jÅ«s varat atrisināt to paÅ”u uzdevumu ar mazāku koda apjomu. PrecÄ«zu statistiku Å”eit nevaru sniegt, jo man nav veida saskaitÄ«t to rindu skaitu, kuras neesmu uzrakstÄ«jis, pateicoties tam, ka pavadÄ«ju laiku specifikācijai, proti, pirmajiem un otrajiem soļiem. Un Å”eit arÄ« nav iespējams veikt eksperimentu, jo eksperimentā mums nav atļauts veikt pirmo soli, uzdevums ir noteikts iepriekÅ”.

Neformālajās specifikācijās ir viegli neievērot daudzas grÅ«tÄ«bas. Nekas sarežģīts nav rakstÄ«t stingras specifikācijas funkcijām, par to es nerunāŔu. Tā vietā mēs runāsim par stingru specifikāciju rakstīŔanu standartizētām uzvedÄ«bas modeļiem. Ir teoria, kas apgalvo, ka jebkura uzvedÄ«bu kopa var tikt aprakstÄ«ta, izmantojot droŔības Ä«paŔību (safety) un dzÄ«votspējas Ä«paŔību (liveness). DroŔība nozÄ«mē, ka nekas slikts nenotiks, programma nesniegs nepareizu atbildi. Ilgmūžība nozÄ«mē, ka agri vai vēlu notiks kaut kas labs, proti, programma agri vai vēlu sniegs pareizu atbildi. Parasti droŔība ir svarÄ«gāks rādÄ«tājs, kļūdas visbiežāk rodas tieÅ”i Å”eit. Tādēļ laika taupīŔanas nolÅ«kos es nerunāŔu par ilgmūžību, lai gan tā arÄ« ir svarÄ«ga.

Mēs panākam droŔību, vispirms nosakot daudz iespējamo sākotnējo stāvokļu. Un, otrs, attiecÄ«bas ar visiem iespējamajiem nākamajiem stāvokļiem katram stāvoklim. UzvedÄ«simies kā zinātnieki un matemātiski definēsim stāvokļus. Sākotnējo stāvokļu kopums tiek aprakstÄ«ts ar formulu, piemēram, Eiropas algoritma gadÄ«jumā: (x = M) ∧ (y = N). Noteiktiem vērtÄ«bām M un N pastāv tikai viens sākotnējais stāvoklis. AttiecÄ«bas ar nākamo stāvokli tiek aprakstÄ«tas ar formulu, kurā nākamā stāvokļa mainÄ«gie tiek rakstÄ«ti ar svÄ«tru, bet paÅ”reizējā stāvokļa — bez svÄ«tras. Eiropas algoritma gadÄ«jumā mums bÅ«s jātiek galā ar divu formulu disjunkciju, kurā vienā no tām x ir augstākais vērtÄ«ba, bet otrajā — y:

ProgrammēŔana — vairāk nekā kodēŔana

Pirmajā gadÄ«jumā jaunā vērtÄ«ba y ir vienāda ar iepriekŔējo y vērtÄ«bu, bet jauno x vērtÄ«bu mēs iegÅ«stam, atņemot no lielākās mainÄ«gās mazāko. Otrajā gadÄ«jumā mēs rÄ«kojamies pretēji.

AtgriezÄ«simies pie Eiropas algoritma. Pieņemam, ka M = 12, N = 18. Tas nosaka vienÄ«go sākotnējo stāvokli, (x = 12) ∧ (y = 18). Tad mēs aizvietojam Ŕīs vērtÄ«bas iepriekÅ” minētajā formulā un iegÅ«stam:

ProgrammēŔana — vairāk nekā kodēŔana

Å eit ir vienÄ«gā iespējamā atrisinājuma: x' = 18 - 12 ∧ y' = 12, un mēs iegÅ«stam uzvedÄ«bu: [x = 12, y = 18]. TieÅ”i tāpat mēs varam aprakstÄ«t visus stāvokļus mÅ«su uzvedÄ«bā: [x = 12, y = 18] → [x = 12, y = 6] → [x = 6, y = 6].

Pēdējā stāvoklÄ« [x = 6, y = 6] abi izteikuma daļu bÅ«s nepatiesi, lÄ«dz ar to tam nav nākamā stāvokļa. Tātad, mēs iegÅ«stam pilnu otrā soļa specifikāciju — kā redzam, tā ir diezgan parasta matemātika, kā pie inženieriem un zinātniekiem, nevis dÄ«vaina, kā datorzinātnēs.

Å os divus formulas var apvienot vienā laika loÄ£ikas formulā. Tā ir eleganta, un ir viegli to izskaidrot, taču Å”obrÄ«d tam nav laika. Laika loÄ£ika mums var bÅ«t nepiecieÅ”ama tikai dzÄ«votspējas Ä«paŔībai, droŔībai tā nav vajadzÄ«ga. Laika loÄ£ika kā tāda nepatÄ«k, tā nav gluži parasta matemātika, bet dzÄ«votspējas gadÄ«jumā tā ir nepiecieÅ”amais ļaunums.

Eiklida algoritmā katrai vērtÄ«bai x un y ir unikālas vērtÄ«bas x' un y', kas padara attiecÄ«bu ar nākamo stāvokli patiesu. Citiem vārdiem sakot, Eiklida algoritms ir deterministiskais. Lai modelētu nedeterministisku algoritmu, ir jānodroÅ”ina, ka paÅ”reizējam stāvoklim ir vairāki iespējamie nākotnes stāvokļi, un ka katrai mainÄ«gās vērtÄ«bai bez svÄ«tras ir vairāki mainÄ«gās vērtÄ«bas ar svÄ«tru, kuru attiecÄ«ba ar nākamo stāvokli ir patiesa. To nav grÅ«ti izdarÄ«t, taču paÅ”laik piemērus sniegt neplānoju.

Lai izveidotu strādājoÅ”u rÄ«ku, nepiecieÅ”ama formālā matemātika. Kā padarÄ«t specifikāciju formālu? Tam mums bÅ«s nepiecieÅ”ams formāls valodas, piemēram, TLA+. Eiklida algoritma specifikācija Å”ajā valodā izskatÄ«sies Ŕādi:

ProgrammēŔana — vairāk nekā kodēŔana

VienādÄ«bas zÄ«me ar trÄ«sstÅ«ri nozÄ«mē, ka vērtÄ«ba pa kreisi no zÄ«mes ir definēta kā vienāda ar vērtÄ«bu pa labi no zÄ«mes. Pamatspecifikācija ir definÄ«cija, mÅ«su gadÄ«jumā divas definÄ«cijas. TLA+ specifikācijai nepiecieÅ”ams pievienot deklarācijas un kādu sintaksi, kā norādÄ«ts augstākajā slaidā. ASCII tas izskatÄ«sies Ŕādi:

ProgrammēŔana — vairāk nekā kodēŔana

Kā redzam, nekā sarežģīta. TLA+ specifikāciju var pārbaudÄ«t, t.i., iziet cauri visiem iespējamajiem uzvedÄ«bas modeļiem nelielā modelÄ«. MÅ«su gadÄ«jumā Å”is modelis bÅ«s konkrētas vērtÄ«bas M un N. Tas ir ļoti efektÄ«vs un vienkārÅ”s pārbaudes veids, kas pilnÄ«bā tiek izpildÄ«ts automātiski. Turklāt var uzrakstÄ«t formālus pierādÄ«jumus par patiesumu un pārbaudÄ«t tos mehāniski, taču tam ir nepiecieÅ”ams daudz laika, tāpēc tā gandrÄ«z neviens to nedara.

Galvenais TLA+ trÅ«kums ir tas, ka tā ir matemātika, un programmētāji un datorspeciālisti baidās no matemātikas. Pirmajā brÄ«dÄ« tas izklausās kā joks, bet, diemžēl, es runāju pavisam nopietni. Mans kolēģis tikko stāstÄ«ja, kā viņŔ mēģinājis izskaidrot TLA+ vairākiem izstrādātājiem. TiklÄ«dz uz ekrāna parādÄ«jās formulas, viņiem uzreiz izdarÄ«jās stikla acis. Tāpēc, ja TLA+ biedē, var izmantot PlusCal, tas ir tāds kā rotaļu programmēŔanas valoda. Izteiksme PlusCal var bÅ«t jebkura izteiksme TLA+, tātad, bÅ«tÄ«bā, jebkura matemātiskā izteiksme. Turklāt PlusCal ir sintakse nedeterministiskajiem algoritmiem. Pateicoties tam, ka PlusCal var rakstÄ«t jebkuru TLA+ izteiksmi, tas ir ievērojami izteiksmÄ«gāks par jebkuru reālo programmēŔanas valodu. Turklāt PlusCal tiek kompilēts saprotamā TLA+ specifikācijā. Tas nenozÄ«mē, ka sarežģīta PlusCal specifikācija pārvērtÄ«sies vienkārŔā TLA+ — vienkārÅ”i atbilstÄ«ba starp tām ir acÄ«mredzama, papildu sarežģītÄ«ba neradÄ«sies. Visbeidzot, Å”o specifikāciju varēs pārbaudÄ«t ar TLA+ rÄ«kiem. Kopumā PlusCal var palÄ«dzēt pārvarēt matemātikas fobiju, to viegli sapratÄ«s pat programmētāji un datorspeciālisti. Pagātnē es kādu laiku (apmēram 10 gadus) publicēju algoritmus uz tā.

Iespējams, kāds iebildÄ«s, ka TLA+ un PlusCal ir matemātika, un matemātika darbojas tikai ar izdomātiem piemēriem. Praksē tomēr ir nepiecieÅ”ama reāla valoda ar tipiem, procedÅ«rām, objektiem un tā tālāk. Tas nav taisnÄ«ba. Šādu komentāru sniedz Kris NÅ«kombs, kurÅ” strādājis Amazon: Ā«Mēs izmantojām TLA+ desmit lielos projektos, un katrā gadÄ«jumā tā izmantoÅ”ana bÅ«tiski veicināja izstrādi, jo mēs spējām atklāt bÄ«stamas kļūdas pirms tām nonākÅ”anu produkcijā, un tā sniedza mums izpratni un pārliecÄ«bu, kas nepiecieÅ”ama agresÄ«vām veiktspējas optimizācijām, neietekmējot programmas patiesumuĀ». Bieži var dzirdēt, ka, izmantojot formālos metodus, mēs iegÅ«stam neefektÄ«vu kodu — tomēr praksē viss ir tieÅ”i otrādi. Turklāt pastāv uzskats, ka menedžerus nevar pārliecināt par formālo metožu nepiecieÅ”amÄ«bu, pat ja programmētāji tic to lietderÄ«bai. Un NÅ«kombs raksta: Ā«Menedžeri tagad visādi mudina rakstÄ«t specifikācijas TLA+, un speciāli tam paredz laikuĀ». Tādēļ, kad menedžeri redz, ka TLA+ darbojas, viņi to entuziastiski pieņem. Kriss NjÅ«kombs to uzrakstÄ«ja apmēram pirms seÅ”iem mēneÅ”iem (2014. gada oktobrÄ«), un, cik man zināms, tagad TLA+ tiek izmantots 14 projektos, nevis 10. Vēl viens piemērs attiecas uz XBox 360 projektēŔanu. Pie Čārlza Tekeru pienāca prakÅ”u students un uzrakstÄ«ja specifikāciju atmiņu sistēmai. Pateicoties Å”ai specifikācijai, tika atrasts bugs, kuru citādi nebÅ«tu pamanÄ«ts, un kura dēļ katrs XBox 360 uzkristu pēc četru stundu lietoÅ”anas. IBM inženieri apstiprināja, ka viņu testi Å”o bug neatrastu.

Vairāk par TLA+ jÅ«s varat izlasÄ«t internetā, bet tagad parunāsim par neformālām specifikācijām. Mums reti nākas rakstÄ«t programmas, kas aprēķina mazāko kopējo dalÄ«tāju un tamlÄ«dzÄ«gi. Biežāk mēs rakstām programmas, piemēram, strukturālā izdrukas instrumentu (pretty-printer), kuru es uzrakstÄ«ju TLA+. Pēc vienkārŔākās apstrādes kods uz TLA+ izskatÄ«tos Ŕādi:

ProgrammēŔana — vairāk nekā kodēŔana

Bet dotajā piemērā lietotājs, visticamāk, vēlējās, lai konjunkcijas un vienādÄ«bas simboli bÅ«tu izkārtoti. Tādēļ pareizā formatēŔana izskatÄ«tos aptuveni Ŕādi:

ProgrammēŔana — vairāk nekā kodēŔana

Apskatīsim citu piemēru:

ProgrammēŔana — vairāk nekā kodēŔana

Å eit, tieÅ”i pretēji, vienādÄ«bas, summēŔanas un reizināŔanas simbolu izkārtojums avotā bija nejauÅ”s, tādēļ vienkārŔākās apstrādes pilnÄ«gi pietiek. Parasti precÄ«zs matemātisks definējums pareizai formatēŔanai nepastāv, jo ā€žpareizsā€ Å”ajā gadÄ«jumā nozÄ«mē ā€žtāds, kādu vēlas lietotājsā€, un to matemātiski noteikt nav iespējams.

Izskatās, ka, ja mums nav patiesÄ«bas definÄ«cijas, tad specifikācija ir bezjēdzÄ«ga. Bet tā nav. Ja mēs nezinām, ko tieÅ”i programmai jāveic, tas nenozÄ«mē, ka mums nevajadzētu izdomāt tās darbÄ«bu — tieÅ”i pretēji, mums uz to jāvelta vēl lielākas pÅ«les. Specifikācija Å”eit ir Ä«paÅ”i svarÄ«ga. Noteikt optimālu programmu strukturālajai izdrukai nav iespējams, bet tas nenozÄ«mē, ka mums nevajadzētu to mēģināt realizēt, un rakstÄ«t kodu kā apziņas plÅ«smu — tas nav pareizi. Galu galā es uzrakstÄ«ju seÅ”u noteikumu specifikāciju ar definÄ«cijām komentāru formā Java failā. LÅ«k, viens no noteikumiem piemērs: left-comment tokens ir LeftComment, kas saskaņota ar tās pārklājoÅ”o token.. Å is noteikums ir rakstÄ«ts, teiksim, matemātiskā angļu valodā: LeftComment saskaņota, left-comment un pārklājoÅ”ais token — termini ar definÄ«cijām. Tā ir matemātiÄ·u metode matemātikas aprakstīŔanai: viņi definē terminus un balstoties uz tiem — noteikumus. Šādas specifikācijas priekÅ”rocÄ«ba ir tā, ka saprast un atkļūdot seÅ”us noteikumus ir ievērojami vieglāk, nekā 850 koda rindiņas. Jāteic, rakstÄ«t Å”os noteikumus nebija viegli, samērā daudz laika tika patērēts to atkļūdoÅ”anai. TieÅ”i Å”im nolÅ«kam es uzrakstÄ«ju kodu, kas ziņo, kāds noteikums tiek izmantots. Pateicoties tam, ka es pārbaudÄ«ju Å”os seÅ”us noteikumus uz vairākiem piemēriem, man nebija jākļūdo 850 koda rindiņas, un kļūdas izrādÄ«jās salÄ«dzinoÅ”i viegli atrodamas. Java Å”im nolÅ«kam piedāvā lieliskus rÄ«kus. Ja es vienkārÅ”i bÅ«tu uzrakstÄ«jis kodu, tas man prasÄ«tu ievērojami vairāk laika un formatējums bÅ«tu daudz sliktāks.

Kāpēc nevarēja izmantot formālo specifikāciju? No vienas puses, pareizÄ«ba Å”eit nav tik bÅ«tiska. Strukturālo izdrukāŔanu noteikti kāds neapmierinās, tāpēc man nebija jādara viss iespējams, lai tā darbotos visās neordinārajās situācijas. Vēl svarÄ«gāk ir tas, ka man nebija adekvātu rÄ«ku. TLA+ modeļu pārbaudes rÄ«ks Å”eit ir bezjēdzÄ«gs, tāpēc man bÅ«tu jāraksta piemēri manuāli.

NorādÄ«tajai specifikācijai ir iezÄ«mes, kas ir kopÄ«gas visām specifikācijām. Tā ir augstāka lÄ«meņa, nekā kods. To var Ä«stenot jebkurā valodā. Tās izveidei nav noderÄ«gi nekādi rÄ«ki vai metodes. Neviens programmēŔanas kurss nepalÄ«dzēs jums uzrakstÄ«t Å”o specifikāciju. Un nav neviena rÄ«ka, kas varētu padarÄ«t Å”o specifikāciju nevajadzÄ«gu, ja, protams, jÅ«s nesarakstāt valodu tieÅ”i struktÅ«ras izdrukas programmu rakstīŔanai uz TLA+. Visbeidzot, Ŕī specifikācija neko nesaka par to, kā mēs rakstÄ«sim kodu, tajā tikai norādÄ«ts, ko Å”is kods dara. Mēs rakstām specifikāciju, lai palÄ«dzētu bÅ«t skaidriem par problēmu, pirms sākam domāt par kodu.

Tomēr Å”ai specifikācijai ir arÄ« Ä«patnÄ«bas, kas to atŔķir no citām specifikācijām. 95% citu specifikāciju ir ievērojami Ä«sākas un vienkārŔākas:

ProgrammēŔana — vairāk nekā kodēŔana

Tālāk, Å”specifikācija ir noteikumu kopums. Parasti tas ir slikta specifikācija. Saprast sekas no noteikumu kopuma ir diezgan grÅ«ti, un tieÅ”i tāpēc man bija jātērē daudz laika to atkļūdoÅ”anai. Tomēr Å”ajā gadÄ«jumā man neizdevās atrast labāku veidu.

Ir vērts teikt dažus vārdus par programmām, kas strādā nepārtraukti. Parasti tās strādā vienlaikus, piemēram, operētājsistēmas vai izkliedētās sistēmas. Saprast tās prātā vai uz papÄ«ra var ļoti maz cilvēku, un es nepiederu to skaitam, lai gan kādreiz tas man izdevās. Tāpēc ir nepiecieÅ”ami rÄ«ki, kas pārbaudÄ«s mÅ«su darbu — piemēram, TLA+ vai PlusCal.

Kāpēc bija jāraksta specifikācija, ja es jau zināju, ko tieÅ”i kodam jādar? PatiesÄ«bā man tikai likās, ka es to zinu. Turklāt, ja ir specifikācija, sveÅ”ajam cilvēkam vairs nav jāielec kodā, lai saprastu, ko tieÅ”i tas dara. Man ir noteikums: nedrÄ«kst bÅ«t nekādu kopÄ«gu noteikumu. Å im noteikumam, protams, ir izņēmums, tas ir vienÄ«gais kopÄ«gais noteikums, ko es ievēroju: specifikācijai par to, ko dara kods, jāsniedz cilvēkiem visa informācija, kas viņiem nepiecieÅ”ama, lietojot Å”o kodu.

Tātad, ko tieÅ”i programmētājiem jāzina par domāŔanu? Vispirms to paÅ”u, ko arÄ« citiem: ja tu neraksti, tad tev tikai Ŕķiet, ka tu domā. Turklāt, ir jādomā pirms kodēŔanas, un tas nozÄ«mē, ka ir jāraksta pirms kodēŔanas. Specifikācija ir tas, ko mēs rakstām pirms sākam kodēt. Specifikācija ir nepiecieÅ”ama jebkuram kodam, ko kāds var izmantot vai mainÄ«t. Un Å”is "kāds" var izrādÄ«ties pats koda autors mēnesi pēc tā uzrakstīŔanas. Specifikācija ir nepiecieÅ”ama lielām programmām un sistēmām, klasēm, metodēm un dažreiz pat sarežģītām kāda atseviŔķa metodei. Ko tieÅ”i vajag rakstÄ«t par kodu? Jāapraksta, ko tas dara, t.i., tas, kas var bÅ«t noderÄ«gs ikvienam, kas izmanto Å”o kodu. Dažreiz var bÅ«t nepiecieÅ”ams arÄ« norādÄ«t, kā tieÅ”i kods sasniedz savu mērÄ·i. Ja Å”o paņēmienu mēs esam apguvuÅ”i algoritmu kursā, tad mēs to saucam par algoritmu. Ja tas ir kaut kas Ä«paŔāks un jauns, tad mēs to saucam par augsta lÄ«meņa projektēŔanu. Formāli atŔķirÄ«bu Å”eit nav: gan tas, gan tas ir programmas abstrakta modeļa veids.

Kā tieÅ”i jāraksta koda specifikācija? Galvenais: tai jābÅ«t par vienu lÄ«meni augstāk par paÅ”u kodu. Tai jāapraksta stāvokļi un uzvedÄ«ba. Tai jābÅ«t tikpat stingrai, cik prasa uzdevums. Ja tu raksti specifikāciju uzdevuma Ä«stenoÅ”anas veidam, tad to var uzrakstÄ«t pseido kodā vai ar PlusCal palÄ«dzÄ«bu. MācÄ«ties rakstÄ«t specifikācijas ir jāizdara, izmantojot formālas specifikācijas. Tas sniegs tev nepiecieÅ”amās prasmes, kas noderēs arÄ« neformālām specifikācijām. Bet kā iemācÄ«ties rakstÄ«t formālas specifikācijas? Kad mēs mācÄ«jāmies programmēŔanu, mēs rakstÄ«jām programmas un tad tās atkļūdojām. Tas pats attiecas arÄ« uz Å”eit: ir jāuzraksta specifikācija, jāpārbauda tā ar modeļu pārbaudes lÄ«dzekli un jāpēc tam labojumi jāveic. TLA+, iespējams, nav labākais valoda formālai specifikācijai, un jÅ«su konkrētajām vajadzÄ«bām, visticamāk, labāk derēs cita valoda. TLA+ priekÅ”rocÄ«ba ir tā, ka tā lieliski māca matemātisko domāŔanu.

Kā sasaistÄ«t specifikāciju un kodu? Ar komentāriem, kas sasaista matemātiskos jēdzienus un to realizāciju. Ja jÅ«s strādājat ar grafiem, tad programmas lÄ«menÄ« jums bÅ«s mezglu masÄ«vi un saikņu masÄ«vi. Tāpēc jums jāraksta, kā tieÅ”i grafiks tiek realizēts ar Ŕīm programmēŔanas struktÅ«rām.

JāatzÄ«mē, ka nekas no iepriekÅ” minētā neattiecas uz paÅ”u koda rakstīŔanas procesu. Kad jÅ«s rakstāt kodu, kas ir treÅ”ais solis, jums arÄ« ir jādomā un jāizplāno programma. Ja apakÅ”uzdevums ir sarežģīts vai neskaidrs, jums jāuzraksta tam specifikācija. Bet par paÅ”u kodu es Å”eit nerunāju. JÅ«s varat izmantot jebkuru programmēŔanas valodu, jebkuru metodoloÄ£iju, runa nav par tām. Turklāt nekas no iepriekÅ” teiktā neatbrÄ«vo no nepiecieÅ”amÄ«bas testēt un labot kodu. Pat ja abstraktā modeļa rakstīŔana ir pareiza, tās realizācijā var bÅ«t kļūdas.

Specifikāciju rakstīŔana ir papildu posms koda rakstīŔanas procesā. Pateicoties tam, daudzas kļūdas var atklāt ar mazākām pÅ«lēm — mēs to zinām no Amazon programmētāju pieredzes. Ar specifikācijām programmu kvalitāte palielinās. Tātad, kāpēc mēs tik bieži spējam iztikt bez tām? Tāpēc, ka rakstÄ«t ir grÅ«ti. Un rakstÄ«t ir grÅ«ti, jo tam nepiecieÅ”ams domāt, un domāt arÄ« ir grÅ«ti. Vienmēr ir vieglāk izlikties, ka domājat. Å eit var izdarÄ«t analoÄ£iju ar skrieÅ”anu — jo mazāk jÅ«s skrienat, jo lēnāk jÅ«s skrienat. Jums jātrenē savi muskuļi un jāpraktizē rakstīŔana. NepiecieÅ”ama prakse.

Specifikācija var bÅ«t nepareiza. Iespējams, ka jÅ«s kaut kur izdarÄ«jāt kļūdu, vai arÄ« prasÄ«bas ir mainÄ«juŔās, vai ir bijusi nepiecieÅ”amÄ«ba veikt uzlabojumus. Ikviens kods, ko kāds izmanto, ir jāmaina, tāpēc agrāk vai vēlāk specifikācija pārstās atbilst programmē. Ideālā gadÄ«jumā Å”ajā gadÄ«jumā vajadzētu uzrakstÄ«t jaunu specifikāciju un pilnÄ«bā pārveidot kodu. Mēs lieliski zinām, ka neviens tā nedara. Praksē mēs labojam kodu un, iespējams, atjauninām specifikāciju. Ja tas ir obligāti, agrāk vai vēlāk notiek, tad kāpēc vispār rakstÄ«t specifikācijas? Pirmkārt, cilvēkam, kurÅ” labos jÅ«su kodu, katrs liekais vārds specifikācijā bÅ«s zelta vērtÄ«bā, un Å”is cilvēks varat bÅ«t arÄ« jÅ«s paÅ”i. Es bieži sev pārmāju par nepietiekamo specifikāciju, kad laboju savu kodu. Un es uzrakstu vairāk specifikāciju nekā kodu. Tāpēc, kad jÅ«s labojat kodu, specifikācija vienmēr ir jāatjaunina. Otrkārt, ar katru labojumu kods kļūst sliktāks, to kļūst arvien grÅ«tāk lasÄ«t un uzturēt. Tā ir entropijas pieaugÅ”ana. Bet, ja jÅ«s nesākat ar specifikāciju, tad katra uzrakstÄ«tā rinda bÅ«s labojums, un kods no paÅ”a sākuma bÅ«s apgrÅ«tinoÅ”s un grÅ«ti lasāms.

Kā teica Eizenhauers, neviens kauja netika uzvarēta pēc plāna, un neviens kauja netika uzvarēta bez plāna. Un viņŔ zināja kaut ko par kaujām. Ir uzskats, ka specifikāciju rakstīŔana ir tukÅ”a laika tērēŔana. Dažreiz tā tieŔām tā ir, un uzdevums ir tik vienkārÅ”s, ka pārdomāt to nav vērts. Bet vienmēr jāatceras, ka, kad jums ieteicams nerakstÄ«t specifikācijas, tas nozÄ«mē, ka jums ieteicams nedomāt. Un par to katru reizi jāpadomā. Uzdevuma pārdomāŔana negarantē, ka jÅ«s nepieļausiet kļūdas. Kā mēs zinām, neviens burvju nÅ«jiņas nav izgudrots, un programmēŔana ir sarežģīts process. Bet, ja jÅ«s nepārdomājat uzdevumu, jÅ«s garantēti pieļausiet kļūdas.

Papildu informāciju par TLA+ un PlusCal var atrast specializētajā mājaslapā, pie tās var piekļūt no manas mājaslapas caur saiti. Tas arī viss, paldies par uzmanību.

Atgādinu, ka Å”is ir tulkojums. Kad jÅ«s rakstÄ«siet komentārus — atcerieties, ka autors tos neizlasÄ«s. Ja jums patieŔām gribas sazināties ar autoru, viņŔ bÅ«s konferencē Hydra 2019, kas notiks 2019. gada 11.-12. jÅ«lijā Sanktpēterburgā. Biļetes var iegādāties . Tas ļauj izveidot savu personÄ«go pasauli, padarot to pieejamu savienojumam no jebkuras pasaules malas. Tiem, kas to dara pirmo reizi, ir lielisks.

Avots: habr.com

Iegādājieties uzticamu tÄ«mekļa hostingu ar DDoS aizsardzÄ«bu, VPS VDS serveriem šŸ”„ Iegādājieties uzticamu tÄ«mekļa hostingu ar DDoS aizsardzÄ«bu, VPS VDS serveriem | ProHoster