Si e vendosni një standard për cilësinë e shkrimit të kodit për veten dhe të tjerët? A keni një kornizë për këtë? Ndoshta një grup rregullash apo udhëzimesh?

Më lejoni t'ju tregoj për një trinitet absolutisht bazë për të gjykuar kodin dhe koduesit:

  1. Kontrolli i rrjedhësi referohet përdorimit të deklaratave programuese si: continue, break, return, goto, exit, halt, etj. në varësi të një gjuhe programimi
  2. Deklaratat e kushtëzuarai referohen deklaratave të tilla si if then else, switch, case, etj.
  3. Nxjerrja & Specializimi i referohet nxjerrjes së zorrëve të një funksioni ose procedurës dhe paketimit të tij nën një funksion të dedikuar dhe të specializuar. Ne gjithashtu mund ta zbatojmë këtë në një kontekst të programimit objektiv dhe metodave të objektit.

Sintaksa e saktë mund të ndryshojë nga një gjuhë programimi në tjetrën. Por leksimat e përmendura më sipër janë mjaft të zakonshme. Dhe përveç kësaj, të 3 aspektet e një programimi të përmendur më sipër janë të përgjithshme dhe universale në të gjithë bordin si për gjuhët e programimit strukturor ashtu edhe për ato objektive.

Kjo është arsyeja pse unë i quaj ata një "trinitet bazë" dhe është gjithashtu arsyeja pse pavarësisht nga etiketa që i vendosa, këto 3 aspekte janë një instrument absolutisht themelor në vlerësimin tim të cilësisë së programimit. Jo një përfundimtar, i vetëm ose ekskluziv, por një themelor.

KUADRI I PLANETIT PËR NJË KODI BURIMOR TË MIRË

Unë kam formuluar një kornizë rreth trinitetit bazë të kodit të mirë. Unë do ta shtroj atë për ju që thjesht ta kapni dhe ta përdorni. Më pas do të vazhdoj me një seksion të dedikuar, me shembuj kodesh dhe një koment.

Pa u zgjatur më tej, korniza aktuale është mjaft e shkurtër. Ai përbëhet nga shtatë rregulla. Dhe kështu e quajta PLANETS, sipas planētēs(mrekullues) që na jepte 7 ditë të javës (gjithashtu është një akronim):

E hënë (hëna):
Ndani me deklarata të kushtëzuara sa herë që është e mundur

E martë (Mars):
Përdorimi i fluksit të kontrollit në reduktimin dhe thjeshtimin e deklaratave të kushtëzuara

E mërkurë (Mërkuri):
Gjithmonë dilni nga një gjendje me një kod të vetëm të arritshëm

E enjte (Jupiteri):
Asnjëherë mos varni një program në një deklaratë të kushtëzuar

E premte (Venus):
Zhduk keqpraktikën e foleve të deklaratave të kushtëzuara

E shtunë (Saturni):
Trajto funksionet e llojit të rezultatit boolean si kontrollin e rrjedhës suaj

E diel (dielli):
Specializoni funksionet për të thjeshtuar deklaratat e kushtëzuara, për të hequr tepricën dhe për të rritur lexueshmërinë.

Ky kuadër zbaton disa aspekte të mira të kodit burimor të mirë:

  1. Kuptim i fortë i logjikës boolean. Nëse jeni programues, atëherë është çështje e përgjegjësisë suaj profesionale të keni një themel të fortë në logjikën boolean.
  2. Kontrolli i rrjedhës është një trashëgimi e programimit të nivelit të ulët. Duke u kthyer përsëri te Assembly language, deklarata e saj goto dhe udhëzime të ndryshme kërcimi. Në thelb, kështu funksionon programimi në nivelin e makinës, dhe të gjitha gjuhët e programimit të nivelit të lartë thjesht ndërtohen në krye të kësaj. Pra, zotëroni kontrollin e rrjedhës dhe përfitoni plotësisht prej tij.
  3. Nxjerrja dhe Specializimi. Promovon lexueshmërinë dhe koncizitetin. Lexueshmëria është njohja dhe respekti i programuesit për të tjerët. Konciziteti është detyrimi profesional i programuesit për të identifikuar dhe zhdukur tepricën. Specializimi është një pasqyrim i mjeshtërisë së arkitekturës dhe dizajnit në nivelin më themelor.
  4. Të gjitha të kombinuara— këto aspekte janë disa nga më themeloret në zanatin e programimit. Është në atë nivel themelor dhe themelor ku bëhet dallimi mes një amatori, dhe një zejtari apo një artizani. Bëni kodin tuaj të bukur dhe të arsyeshëm duke trajtuar këto aspekte.

Megjithëse e publikoj zyrtarisht këtë si një kornizë të emërtuar në vitin 2022 pasi kam qenë programues dhe udhëheqës i zhvillimit të softuerit për më shumë se një dekadë, idetë pas saj datojnë që nga vitet e mia të kolegjit në "University of Warmia and Mazury" në qytetin tim. Olsztyn. I frymëzuar nga një person nga e kaluara ime - Mariusz Abramczuk - i cili është leksione mbi programimin strukturor dhe objektiv, unë pata fatin t'i kisha marrë prapa rreth vitit 2004. Kujtimet e pikëpamjeve të tij për programimin e mirë dhe kodin e mirë kanë formuar zanatin tim të kodimit gjatë gjithë jetës dhe karrierës sime.

SHEMBUJ KODI

Vetëm shkurtimisht, unë do të ilustroj çdo rregull të Kornizës PLANETS me një copë kodi të thjeshtë. Në kapitullin tjetër do të marrim disa kode të botës reale për praktikë, që mendoj se është një vlerë më e madhe.

REFERIMI: Doja të përdorja përpiluesin gcc për fragmentet. Por C++ nuk e mbështet sintaksën e provoni përfundimisht, siç bëjnë Object Pascal, C#, Delphi, Java, JS. Ai mbështet "RAII", por kjo nuk funksionon për mua. Ndërsa ofron funksionalitetin, nuk ndihmon me lexueshmërinë, siç do të provonte më në fund sintaksa. Kështu që unë thjesht pretendova se C++ në fakt mbështet seksionin më në fund dhe shkova me të. Ose mund të pretendoni, kur e shihni, se po shikoni kodin C#.

RREGULLI I TË HËNËS:

RREGULLI i së martës:

RREGULLI i të mërkurës:

RREGULLI i së Enjtes:

RREGULLI I TË Premtes:

Ju gjithashtu mund t'i referoheni shembullit të rregullit të së dielës për përdorimin e funksioneve të specializuara ndihmëse për të adresuar këtë rregull. Dhe këtu është një lloj tjetër shembulli për rregullin e së Premtes:

RREGULLI i së shtunës:

Përveç fragmentit më poshtë, shembulli i përdorur për rregullin e së dielës është gjithashtu i rëndësishëm.

Këtu në fakt po shtoj linja kodi për të arritur një strukturë dhe lexueshmëri më të mirë. Unë jam duke përdorur funksionet e mbajtësit:

Një koncept i një funksioni mbajtës është se ai kthen true ose false jo bazuar në faktin nëse një nënprogram është ekzekutuar apo jo siç duhet, por vetëm bazuar në faktin nëse ai ka zbuluar apo jo skenarin e besuar, në mënyrë që të parandalojë trajtuesit e tjerë që të shqyrtojnë rastin. Edhe nëse janë zbuluar gabime ose janë arritur përjashtime gjatë trajtimit.

Siç mund ta shihni, në këtë rast numri i rreshtave të kodit u rrit, por lexueshmëria, cilësia dhe struktura e kodit u përmirësuan të gjitha.

RREGULLI i së dielës:

KORNIZA NË VEPRIM

Mund të inkorporoja mostra kodi në çdo gjuhë programimi. Mund të përpiqem të kërkoj në internet për renditjen e popullaritetit të gjuhës. Por unë jam dembel dhe e di që këto gjëra janë aq elementare sa do ta kuptoni pavarësisht nga gjuha që zgjedh. Ky kuadër është thjesht universalisht i lidhur në të gjitha gjuhët.

Dhe kështu unë zgjedh Object Pascal-in tim më të dashur, i cili është ndoshta gjuhët moderne të programimit më të nënvlerësuara dhe më të anashkaluara për programimin ndër-platformë, ndër-arkitekturor dhe programimin vendas (dhe skriptimi) me qëllime të ndryshme. Për back-end, front-end, desktop, celular dhe çfarë jo. Është ndoshta edhe gjuha programuese më e lexueshme nga njeriu në mesin e atyre me përdorim praktik në programimin e aplikuar.

Për seminarin zgjodha një fragment nga një implementim zyrtar i FCL (Biblioteka e Komponentit Falas), të cilin e merrni me Përpiluesin Falas Pascal. Në një njësi Process.pp të FCL, e cila zbaton klasën TProcess, ekziston një funksion ndihmës i quajtur RunCommand. Ai ekzekuton një komandë në një direktori aktuale duke thirrur një proces sistemi dhe kontrollon tubat e tij hyrëse dhe dalëse.

Funksioni ju lejon të kaloni emrin e procesit për t'u ekzekutuar, me një sërë parametrash të linjës komanduese (të cilat mund të jenë bosh) dhe një referencë për një variabël vargu për kapjen e prodhimit të procesit. Ai kthen një rezultat boolean që tregon nëse procesi u ekzekutua me sukses dhe nëse nuk ktheu ndonjë kod gabimi:

Do të dëshiroj të punoj me një version më të vjetër të FCL më vonë, por ndërsa jemi këtu, le të shqyrtojmë shkurtimisht zbatimin aktual.

Unë do të punoj në kopjen time lokale, që do të verifikoj në çdo fazë modifikimi nëse është ende e përpiluar apo jo. Ashtu si të tjerët, edhe unë kam preferencën time personale për formatimin dhe stilimin e kodit. Pra, këtu është saktësisht i njëjti kod i ristrukturuar/riformatuar sipas dëshirës sime:

Le të fillojmë me rregullin e së hënës: Ndahuni me deklarata të kushtëzuara sa herë që është e mundur. Dhe kështu rreshtat 44–45 dhe 56–57 bëhen:

Result në Object Pascal është një funksion pak i ngjashëm me atë që është this për një objekt në Java ose JavaScript. Ai i referohet vlerës së kthimit të funksionit, dhe brenda fushës së funksionit ai korrespondon gjithmonë me një lloj të saktë sipas përkufizimit të kokës së funksionit. Këtu, rezultati është i llojit boolean, dhe NUK është zgjidhja më e mirë për ta vendosur atë duke përdorur deklaratën e kushtëzuar if then. Për më tepër, programuesi është jokonsistent sepse në rreshtin #51 përdoret mënyra më e përshtatshme.

Në rreshtin #44 e anashkala plotësisht deklaratën e kushtëzuar. Sintaksa e gjuhës nuk kërkon trajtim të veçantë për kushtin që po testohej: nëse një grup që zbritet nga një tjetër është bosh apo jo. Gjuha dhe përpiluesi trajtojnë mirë të dyja rastet e skajeve. Një përdorim krejtësisht i panevojshëm i një deklarate të kushtëzuar.

Dhe tani, unë do të kaloj në një version më të vjetër 3.0.2 të FCL dhe zbatimin e tij të funksionit RunCommand në njësinë Process.pp. Trupi i vetë funksionit është shumë i vogël dhe ne do të kujdesemi për nënfunksionin e tij për ridizajnimin e kodit:

Tani është koha për një punë të vërtetë. Le të ridizajnojmë InternalRunCommand i cili është një funksion privat i vendosur në njësinë linjat 473–570 të procesit.pp. Le të fillojmë nga fundi dhe thjesht të shohim para dhe pas.

PARA:

Në fakt, kur kam të bëj me një fole të ndërlikuar të deklaratave të kushtëzuara si kjo, unë gjithmonë filloj me ndryshimin e paraqitjes së tekstit: ku rreshtat prishen dhe futen. Për ta bërë vizualisht më të lehtë për mua të lundroj në një strukturë komplekse, të mbivendosur.

Pra, kodi i mësipërm është kopja ime lokale e formatuar në paraqitjen time të preferuar. Nëse dëshironi të shihni paraqitjen origjinale, kontrolloni "këtu".

PASI:

Ne kemi nxjerrë disa kode në funksione të veçanta ndihmëse. Në fund do të gjeni një kod të plotë. Tani le t'i zbërthejmë ndryshimet në hapa më të vegjël për të demonstruar kornizën në lojë.

NDARJA

Së pari, zbatimi origjinal është i çmendur. Është e dhimbshme të lexosh, kryesisht sepse foleja e pakëndshme e blloqeve të kodit. Pjesët e kodit varen nën një hutim të tmerrshëm të deklaratave të kushtëzuara me shumë nivele.

NESE, PASTAJ, TJETER, NËSE ATHESH... prisni, a ishte kjo një ELSE që korrespondon me këtë IF apo ​​me atë ELSE-IF?

Për hir të F#@#, çfarë po ndodh këtu?! A është shkruar kjo që një njeri ta lexojë?

OK, ju e keni parë versionin e mëvonshëm, kështu që le të gjurmojmë përsëri hapat që çuan në të.

Duke ndjekur kornizën, ne fillimisht sulmojmë pjesën më fyese me nxjerrjen dhe specializimin. E shihni, teprica në këtë kod është e rëndë dhe laike. Koha për rregullin e së dielës: Specializo funksionet për të thjeshtuar deklaratat e kushtëzuara, për të hequr tepricën dhe për të rritur lexueshmërinë.

Le të shohim se sa më i pastër bëhet kodi:

Ne sapo morëm kodin kryesor të tepërt, i cili ishte bllok 4 herë pothuajse kopjues-ngjit i kodit, dhe e nxorëm atë në një funksion ndihmës të quajtur ReadFromPipe me argumente që lejojnë ripërdorimin e tij si kundër tubave stdout ashtu edhe stderr të një procesi: p.Output dhe p.Stderr respektivisht.

Ne përgjysmuam përafërsisht madhësinë e trupit të funksionit RunCommand. Ne hoqëm tepricat e mëdha dhe rritëm lexueshmërinë.

Nënprogrami ReadFromPipe tani përmban kodin e nxjerrë:

Ka më shumë për të bërë me këtë funksion ndihmës. Së pari, deklarata e kushtëzuar krejtësisht e panevojshme në rreshtin #51 më sipër. Në thelb varet detyrën aktuale të këtij funksioni ndihmës nën një deklaratë të kushtëzuar të pakuptimtë. Kjo shkel disa rregulla të kornizës, por më së shumti shkel rregullin e së mërkurës: Gjithmonë dilni nga një kusht me një kod të vetëm të arritshëm.

Kushti këtu ka një kod të vetëm të arritshëm, që do të thotë, nuk ka kod për t'u arritur përveç për një rast të vetëm. Dhe përtej këtij rasti të vetëm, nuk ka asgjë tjetër për të trajtuar.

Për më tepër, le të pranojmë se kodi mbi deklaratën e kushtëzuar është thjesht një kontroll i thjeshtë fillestar i arsyeshmërisë. Puna aktuale që duhet bërë nga funksioni qëndron prapa kushtit. Pra, ne po shkelim edhe rregullin e së enjtes: Asnjëherë mos e varni një program në një deklaratë të kushtëzuar.

Pra, le të jemi profesionistë dhe le të heqim qafe këtë marrëzi amatore:

Shikoni rreshtin e zgjedhur #51, ai përdor deklaratën e kontrollit të rrjedhës exit për t'u kthyer menjëherë nga funksioni ndihmës me një vlerë rezultati FALSE, nëse kushti fillestar nuk kualifikohet për fillimin e nën-rutinës.

Dhe nëse kualifikohemi, atëherë nën-rutina aktuale do të funksionojë në bllokun kryesor të kodit, dhe jo si ana e djathtë e një gramatike shprehjeje të kushtëzuar.

Mund ta lëmë këtë me kaq, dhe do të ishte në rregull. Por ne gjithashtu mund të bëjmë një nxjerrje shtesë:

Ndërsa ju mund të pyesni veten nëse kjo është apo jo një e tepruar, kjo është praktikë e mirë. Funksioni i ri ndihmës i nxjerrë mund të ripërdoret edhe përtej fushëveprimit aktual.

Por ka më shumë përfitim. Pasi të përdorim kornizën, përfundojmë me një kod shumë më të pastër dhe më të lexueshëm. Më pas bëhet më e lehtë aplikimi i optimizimeve të mëtejshme dhe rregullimi i mëtejshëm në kod. Për shembull:

Shikoni rreshtin e zgjedhur #101. Mungonte plotësisht nga zbatimi origjinal.

Kodi po lexonte të dhëna nga dy tuba të ndryshëm në dy buferë të ndryshëm të vargut. Por bëri vetëm një prerje përfundimtare në njërën prej tyre, dhe jo tjetrën.

Nëse kjo ka qenë nga neglizhenca e programuesit origjinal, atëherë me siguri është kontribuar nga një lexueshmëri e dobët e kodit.

Nëse ishte me dizajn, atëherë ishte një dizajn i dobët. Megjithatë, fakti që ishte i dobët u errësua nga një lexueshmëri e dobët e kodit.

Ne gjithashtu hoqëm fryrjen nga seksioni except (i cili është i barabartë me seksionincatch në gjuhë të tjera). Sepse kodi brenda nuk varet vërtet nga përjashtimi që i përket ndonjë klase specifike. Pra, vlerësimi i klasës së përjashtimit nuk i shërbente aspak qëllimit.

Kodi u bë më konciz dhe më i pastër, kështu që ne vumë re një pjesë që mungonte nga ajo që po ndodhte në një funksion ndihmës. Pavarësisht nëse ishte diçka që u neglizhua apo synohej, ne e bëmë kodin më të lehtë për mirëmbajtje dhe rishikim. Dhe në fund ne morëm iniciativën për të përmirësuar dizajnin ekzistues.

Kodi i mirë dhe i pastër është më i lehtë për t'u dalluar dhe për të rregulluar të metat e dizajnit. Kështu që unë përmirësova dizajnin e ndërfaqes origjinale të funksionit RunCommand. Duket se ai përdor nga brenda informacione që mund të jenë të dobishme për telefonuesin e tij. Megjithatë, informacioni shpërfillet dhe shpërdorohet. E kam fjalën për daljen StdErr dhe vlerën ExitCode. Pra, në kodin përfundimtar kam dy versione të mbingarkuar të funksionit RunCommand2: një i pajtueshëm me implementimin origjinal RunCommand dhe një tjetër me aksesin në dy pjesët shtesë të të dhënave.

Unë gjithashtu shpëtoj nga disa ndryshore të cilat tani u bënë zorrët e brendshme të një funksioni ndihmës. Ne shtuam disa pastrime fillestare të shëndetit, etj. Të gjitha këto llogariten si optimizime shtesë përtej qëllimit të kornizës origjinale. Por ato u bënë më të lehta për t'u aplikuar në një kod më të pastër dhe një strukturë më të mirë kodi.

Në fund e zhvendosa edhe shkurtimin e buferit në funksionin ndihmës dhe e parametrizova:

Ju mund të shihni se dy linjat e zgjedhura kanë një argument boolean i cili kur vendoset në true do ta shkurtojë bufferin në madhësinë e përdorur aktualisht nga të dhënat brenda. Vlera e paracaktuar është vendosur në true, kështu që ne vetëm kërkojmë në mënyrë eksplicite që të mos shkurtohet buferi brenda ciklit while, dhe në rreshtat #95–96 ne e kapërcejmë atë, në mënyrë që buferët të shkurtohen si parazgjedhje.

Gjithashtu, ne i heqim të gjitha variablat me numra të plotë, sepse këto kishin të bënin me diçka që tani kujdeset vetëm për një funksion ndihmës.

FINALJA E MADHE

Dhe siç u premtua, këtu është kodi i plotë me të gjitha funksionet ndihmëse:

Si bonus, çdo funksion që rezulton, duke përfshirë të gjitha funksionet ndihmëse, janë të përmasave në atë mënyrë që secili prej tyre mund të përshtatet në një ekran pa nevojën për lëvizje. Megjithëse kjo nuk është pjesë e kornizës sime, është një rregull i madh për mua. Unë gjithmonë e ndjek atë si parazgjedhje, përveç nëse gjej një arsye të mirë për të mos.