Kā nenogalināt projektu ar sliktu kodēšanas praksi?
Bartošs Slišs (Bartosz Slysz)
Software Engineer
Daudzi programmētāji, kas sāk savu karjeru, uzskata, ka mainīgo, funkciju, failu un citu komponentu nosaukumu piešķiršana nav īpaši svarīga. Rezultātā viņu projektēšanas loģika bieži vien ir pareiza - algoritmi darbojas ātri un rada vēlamo efektu, bet var būt tikko salasāmi. Šajā rakstā mēģināšu īsi aprakstīt, pēc kā vajadzētu vadīties, nosaucot dažādus koda elementus, un kā nenonākt no vienas galējības otrā.
Kāpēc nosaukuma piešķiršanas posma ignorēšana paildzinās (dažos gadījumos - ļoti būtiski) jūsu projekta izstrādi?
Pieņemsim, ka jūs un jūsu komanda pārņem kods no citiem programmētājiem. Portāls projekts jūs mantojat tika izstrādāta bez jebkādas mīlestības - tā darbojās labi, taču katru tās elementu varēja uzrakstīt daudz labāk.
Ja runa ir par arhitektūru, koda mantošanas gadījumā tā gandrīz vienmēr izraisa naidu un dusmas no programmētāju puses, kas to ieguvuši. Dažreiz tas ir saistīts ar izmirstošu (vai izmirstošu) tehnoloģiju izmantošanu, dažreiz ar nepareizu domāšanu par lietojumprogrammu izstrādes sākumā, bet dažreiz vienkārši ar atbildīgā programmētāja zināšanu trūkumu.
Jebkurā gadījumā, projekta laikam ritot, ir iespējams nonākt līdz brīdim, kad programmētāji dusmojas uz arhitektūrām un tehnoloģijām. Galu galā, katrā lietojumprogrammā pēc kāda laika ir jāpārraksta dažas daļas vai vienkārši jāveic izmaiņas konkrētās daļās - tas ir dabiski. Taču problēma, kas programmētājiem sarauj matus, ir grūtības lasīt un saprast mantoto kodu.
Īpaši ekstrēmos gadījumos, kad mainīgie tiek nosaukti ar atsevišķiem, bezjēdzīgiem burtiem un funkcijas ir pēkšņs radošuma uzplūds, kas nekādā veidā nav saskaņots ar pārējo lietojumprogrammu, jūsu programmētāji var pārsteigt. Šādā gadījumā jebkurai koda analīzei, ko varētu veikt ātri un efektīvi, ja tiktu izmantoti pareizi nosaukumi, ir nepieciešama papildu analīze, piemēram, algoritmiem, kas ir atbildīgi par funkcijas rezultāta iegūšanu. Un šāda analīze, lai arī neuzkrītoša, - izšķiež milzum daudz laika.
Jaunu funkcionalitāšu ieviešana dažādās lietojumprogrammas daļās nozīmē iziet cauri murgam, analizējot to, pēc kāda laika jums ir jāatgriežas pie koda un jāanalizē tas vēlreiz, jo tā nolūki nav skaidri, un iepriekšējais laiks, kas pavadīts, mēģinot saprast tā darbību, ir bijis veltīgs, jo jūs vairs neatceraties, kāds bija tā mērķis.
Tādējādi mēs ieslīdam nekārtības tornado, kas valda lietojumprogrammā un lēnām aprij katru tās izstrādes dalībnieku. Programmētāji ienīst projektu, projektu vadītājiem nepatīk skaidrot, kāpēc tā izstrādes laiks sāk nepārtraukti pieaugt, bet klients zaudē uzticību un kļūst nikns, jo nekas nenotiek atbilstoši plānam.
Kā no tā izvairīties?
Atzīsim - dažas lietas nevar izlaist. Ja projekta sākumā esam izvēlējušies noteiktas tehnoloģijas, mums jāapzinās, ka ar laiku tās vai nu vairs netiks atbalstītas, vai arī arvien mazāk programmētāju pratīs izmantot pirms dažiem gadiem radītās tehnoloģijas, kas pamazām noveco. Dažas bibliotēkas savos atjauninājumos prasa vairāk vai mazāk saistošas izmaiņas kodā, kas bieži vien rada atkarību virpuli, kurā var iestrēgt vēl vairāk.
No otras puses, tas nav tik melns scenārijs; protams, tehnoloģijas noveco, taču faktors, kas noteikti palēnina ar tām saistīto projektu izstrādes laiku, ir lielākoties neglīts kods. Un, protams, šeit jāpiemin Roberta K. Martina grāmata - tā ir programmētāju bībele, kurā autors iepazīstina ar daudz labās prakses piemēriem un principiem, kas jāievēro, lai radītu uz pilnību tiecošos kodu.
Nosaucot mainīgos, galvenais ir skaidri un vienkārši izteikt to nolūku. Tas izklausās pavisam vienkārši, taču dažkārt daudzi cilvēki to neievēro vai ignorē. Labs nosaukums norādīs, ko tieši mainīgajam ir paredzēts saglabāt vai ko funkcijai ir paredzēts darīt - to nedrīkst nosaukt pārāk vispārīgi, bet, no otras puses, tas nedrīkst kļūt par garu sliņķi, kura vienkārša nolasīšana sagādā smadzenēm pamatīgu izaicinājumu. Pēc kāda laika ar labu kvalitātes kods, mēs izjūtam iegremdēšanas efektu, kad mēs varam zemapziņā organizēt nosaukšanas un nodošanas dati funkcijai tā, lai tas viss neradītu ilūzijas par to, kāds nolūks to virza un kāds ir sagaidāmais rezultāts pēc tās izsaukšanas.
Vēl viena lieta, ko var atrast JavaScript, cita starpā ir mēģinājums pārāk optimizēt kodu, kas daudzos gadījumos padara to nelasāmu. Ir normāli, ka dažiem algoritmiem ir nepieciešama īpaša rūpība, kas bieži vien atspoguļo to, ka koda nolūks var būt mazliet sarežģītāks. Tomēr gadījumi, kad nepieciešama pārmērīga optimizācija, ir ārkārtīgi reti vai vismaz tie, kuros mūsu kods ir netīrs. Ir svarīgi atcerēties, ka daudzas ar valodu saistītas optimizācijas notiek nedaudz zemākā abstrakcijas līmenī; piemēram, V8 dzinējs, veicot pietiekami daudz iterāciju, var ievērojami paātrināt cilpas. Jāuzsver tas, ka mēs dzīvojam 21. gadsimtā un nerakstām programmas Apollo 13 misijai. Mums ir daudz lielākas manevrēšanas iespējas resursu jomā - tie ir tur, lai tos izmantotu (vēlams, saprātīgā veidā :>).
Dažreiz koda sadalīšana daļās patiešām dod daudz. Ja operācijas veido ķēdi, kuras mērķis ir veikt darbības, kas ir atbildīgas par konkrētu datu modifikāciju, - ir viegli apmaldīties. Tāpēc vienkāršā veidā, tā vietā, lai visu darītu vienā virknē, var sadalīt atsevišķās koda daļās, kas atbild par kādu konkrētu lietu, atsevišķos elementos. Tas ne tikai padarīs skaidru atsevišķu darbību nolūku, bet arī ļaus testēt koda fragmentus, kas atbild tikai par vienu lietu un kurus var viegli izmantot atkārtoti.
Daži praktiski piemēri
Manuprāt, visprecīzāk dažus no iepriekš minētajiem apgalvojumiem būs parādīt, kā tie darbojas praksē - šajā punktā es mēģināšu izklāstīt dažas sliktas koda prakses, kuras vairāk vai mazāk var pārveidot par labām. Norādīšu, kas dažos brīžos traucē koda lasāmību un kā to novērst.
Viena burta mainīgo bauslis
Briesmīga prakse, kas diemžēl ir diezgan izplatīta pat universitātēs, ir mainīgo nosaukšana ar vienu burtu. Grūti nepiekrist, ka reizēm tas ir diezgan ērts risinājums - mēs izvairāmies no liekas domāšanas, kā noteikt mainīgā nolūku, un tā vietā, lai nosaukumā izmantotu vairākus vai vairākus burtus, izmantojam tikai vienu burtu - piemēram, i, j, k.
Paradoksāli, bet dažas šo mainīgo definīcijas ir apveltītas ar daudz garāku komentāru, kas nosaka, ko autors ir domājis.
Labs piemērs šeit varētu būt iterācija pār divdimensiju masīvu, kas satur atbilstošās vērtības kolonnas un rindas krustpunktā.
const array = [[0, 1, 2], [3, 4, 5], [6, 7, 8]];
// diezgan slikti
for (let i = 0; i < array[i]; i++) {
for (let j = 0; j < array[i][j]; j++) {
// šeit ir saturs, bet katru reizi, kad tiek izmantoti i un j, man ir jāatgriežas un jāanalizē, kam tie tiek izmantoti
}
}
// joprojām slikti, bet smieklīgi
let i; // rinda
let j; // sleja
for (i = 0; i < array[i]; i++) {
for (j = 0; j < array[i][j]; j++) {
// šeit ir saturs, bet katru reizi, kad tiek izmantoti i un j, man ir jāatgriežas un jāpārbauda komentāri, kam tie tiek izmantoti
}
}
// daudz labāk
const rowCount = array.length;
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
const row = array[rowIndex];
const columnCount = row.length;
for (let columnIndex = 0; columnIndex < columnCount; columnIndex++) {
const column = row[columnIndex];
// vai kādam ir šaubas par to, kas ir kas?
}
}
Viltīga pārmērīga optimizācija
Kādu skaistu dienu es sastapos ar ļoti sarežģītu kodu, ko uzrakstīja kāds programmatūras inženieris. Šis inženieris bija noskaidrojis, ka lietotāja atļauju sūtīšanu kā virknes, kurās norādītas konkrētas darbības, var ievērojami optimizēt, izmantojot dažus bitu līmeņa trikus.
Iespējams, šāds risinājums būtu labs, ja mērķis būtu Commodore 64, bet šī koda mērķis bija vienkārša. tīmekļa vietne lietojumprogramma, kas rakstīta JS. Ir pienācis laiks pārvarēt šo dīvainību: Pieņemsim, ka lietotājam visā sistēmā ir tikai četras satura modificēšanas iespējas: izveidot, lasīt, atjaunināt, dzēst. Tas ir diezgan dabiski, ka mēs vai nu nosūtām šīs atļaujas JSON formā kā objekta atslēgas ar stāvokļiem, vai kā masīvu.
Tomēr mūsu gudrais inženieris pamanīja, ka binārajā attēlojumā skaitlis četri ir maģiska vērtība, un izdomāja to šādi:
Visā iespēju tabulā ir 16 rindas, bet es esmu uzskaitījis tikai 4, lai parādītu šo atļauju izveides ideju. Atļauju lasīšana notiek šādi:
Tas, ko redzat iepriekš, nav WebAssembly kods. Es nevēlos, lai mani pārprastu - šāda optimizācija ir normāla lieta sistēmās, kur noteiktām lietām ir nepieciešams ļoti maz laika vai atmiņas (vai abas). No otras puses, tīmekļa lietojumprogrammas noteikti nav vieta, kur šādai pārmērīgai optimizācijai ir pilnīga jēga. Es negribu vispārināt, bet front-end izstrādātāju darbā sarežģītākas operācijas, kas sasniedz bitu abstrakcijas līmeni, tiek veiktas reti.
Tas vienkārši nav lasāms, un programmētājs, kas spēj veikt šāda koda analīzi, noteikti brīnīsies, kādas neredzamas priekšrocības ir šim risinājumam un kas var tikt bojāts, ja. izstrādes komanda vēlas to pārrakstīt uz saprātīgāku risinājumu.
Vēl vairāk - man ir aizdomas, ka, nosūtot atļaujas kā parastu objektu, programmētājs varētu nolasīt nodomu 1-2 sekundēs, savukārt visas šīs lietas analīze no sākuma prasīs vismaz dažas minūtes. Projektā būs vairāki programmētāji, katram no viņiem nāksies saskarties ar šo koda gabalu - viņiem nāksies to analizēt vairākas reizes, jo pēc kāda laika viņi aizmirsīs, kāda maģija tur notiek. Vai ir vērts saglabāt šos dažus baitus? Manuprāt, nē.
Sadal un valdi
Tīmekļa izstrāde strauji pieaug, un nekas neliecina, ka drīzumā šajā ziņā varētu kaut kas mainīties. Jāatzīst, ka pēdējā laikā ir ievērojami palielinājusies front-end izstrādātāju atbildība - viņi ir pārņēmuši loģikas daļu, kas atbild par datu attēlojumu lietotāja saskarnē.
Dažreiz šī loģika ir vienkārša, un objekti, ko nodrošina API ir vienkārša un viegli lasāma struktūra. Tomēr dažkārt, lai tos pielāgotu dažādām vietām lapā, ir jāveic dažāda veida kartēšana, šķirošana un citas darbības. Un šī ir vieta, kur mēs varam viegli iekrist purvā.
Daudzas reizes esmu pieķēris sevi pie tā, ka dati operācijās, ko veicu, ir praktiski nelasāmi. Neraugoties uz pareizu masīva metožu lietošanu un pareizu mainīgo nosaukumu piešķiršanu, operāciju ķēdes dažos punktos gandrīz zaudēja kontekstu tam, ko es vēlējos panākt. Turklāt dažas no šīm operācijām dažkārt bija jāizmanto citur, un dažkārt tās bija pietiekami globālas vai sarežģītas, lai būtu nepieciešams rakstīt testus.
Es zinu, es zinu - tas nav triviāls koda gabaliņš, kas viegli ilustrē to, ko es vēlos parādīt. Un es arī zinu, ka abu piemēru skaitļošanas sarežģītība ir nedaudz atšķirīga, bet 99% gadījumos mums par to nav jāuztraucas. Atšķirība starp algoritmiem ir vienkārša, jo abi sagatavo atrašanās vietu un ierīču īpašnieku karti.
Pirmais šo karti sagatavo divas reizes, bet otrais - tikai vienu reizi. Un visvienkāršākais piemērs, kas parāda mums ka otrais algoritms ir pārnesamāks, slēpjas faktā, ka mums ir jāmaina šīs kartes izveides loģika attiecībā uz pirmo algoritmu un, piemēram, jāizslēdz noteiktas vietas vai citas dīvainas lietas, ko sauc par biznesa loģiku. Otrā algoritma gadījumā mēs modificējam tikai kartes iegūšanas veidu, bet visas pārējās datu modifikācijas, kas notiek nākamajās rindās, paliek nemainīgas. Pirmā algoritma gadījumā mums ir jāmaina katrs kartes sagatavošanas mēģinājums.
Un šis ir tikai piemērs - praksē ir daudz šādu gadījumu, kad mums ir nepieciešams pārveidot vai pārveidot noteiktu datu modeli visā lietojumprogrammā.
Labākais veids, kā izvairīties no sekošanas līdzi dažādām izmaiņām uzņēmējdarbībā, ir sagatavot globālus rīkus, kas ļauj mums iegūt interesējošo informāciju diezgan vispārīgā veidā. Pat uz to rēķina, ka mēs varam zaudēt tās 2-3 milisekundes, ko varam zaudēt uz deoptimizācijas rēķina.
Kopsavilkums
Būt programmētājam ir tāda pati profesija kā jebkura cita - katru dienu mēs mācāmies jaunas lietas un bieži vien pieļaujam daudz kļūdu. Svarīgākais ir mācīties no šīm kļūdām, kļūt labākam savā profesijā un neatkārtot šīs kļūdas nākotnē. Nevar ticēt mītam, ka mūsu darbs vienmēr būs nevainojams. Tomēr jūs varat, pamatojoties uz citu pieredzi, attiecīgi samazināt trūkumus.
Es ceru, ka šī raksta izlasīšana palīdzēs jums izvairīties no vismaz dažiem no slikta kodēšanas prakse ko esmu pieredzējis savā darbā. Ja jums rodas jautājumi par labākajām kodēšanas praksēm, varat sazināties ar The Codest apkalpe ārā, lai konsultētos par savām šaubām.