Kas ir SOLID principi?
SOLID principi ietver piecas pamatnostādnes, kas nodrošina tīru, viegli uzturamu un elastīgu kodu objektorientētā programmēšanā. Šo principu piemērošana un ievērošana nodrošina viegli saprotamu programmatūras dizainu pat ilgstošas izstrādes laikā. Pateicoties šiem principiem, ne tikai var rakstīt labāku kodu, bet arī esošo kodu ir vieglāk uzturēt.
Kas ir SOLID principi un kas tos izstrādāja?
Labs avota kods sākas ar noteikumiem, programmēšanas paradigmām un piemērotu programmēšanas stilu, kas nodrošina efektīvu un skaidru kodu. Tieši to garantē pieci SOLID principi, kurus izstrādāja Roberts C. Martins, Bertrands Meijers un Barbara Liskova. Ievērojot šos principus objektorientētā programmēšanā (OOP) ar tādām valodām kā Python vai Java, jūs ne tikai rakstāt labāku kodu, bet arī nodrošināt efektīvāku koda uzturēšanu, ilgtspējīgu un elastīgu programmatūras dizainu un lielāku drošību ilgtermiņā.
Nosaukums SOLID simbolizē stingru programmēšanas pamatu, kas nepieciešams ikvienam, kurš vēlas apgūt programmēšanu. Šo akronīmu izveidoja Maikls Feiterss, izmantojot katra no pieciem principiem pirmos burtus:
- Vienas atbildības princips: klasei vajadzētu būt vienam un tikai vienam iemeslam, kāpēc tā jāmaina.
- Atvērtības-slēgtības princips: Programmatūras vienībām (klasēm, moduļiem, funkcijām utt.) jābūt atvērtām paplašināšanai, bet slēgtām modifikācijām.
- Liskovas aizstājamības princips: apakšklasēm jāspēj mantot un īstenot visas virsklases metodes un īpašības.
- Saskarnes nošķiršanas princips: saskarnēm nevajadzētu saturēt vairāk metožu, nekā nepieciešams klašu īstenošanai.
- Atkarības apgriešanas princips: Klasēm nevajadzētu būt atkarīgām no citām klasēm, bet gan no interfeisēm vai abstraktām klasēm.
Kādas priekšrocības sniedz SOLID principi?
Ja nav noteikumu, rodas haoss, un tas kļūst īpaši pamanāms programmēšanā. Pat nelielas kļūdas, neprecizitātes un nepilnības var padarīt labu avota kodu ilgtermiņā pilnīgi nelietojamu, ja tās netiek novērstas. Dažkārt pietiek ar sarežģītām klasēm, kas apgrūtina īstenošanu, vai apakšklasēm, kurām trūkst virsklases individuālo īpašību. SOLID principi nodrošina, ka refaktorizācijas rezultātā jālabo pēc iespējas mazāk koda.
SOLID principi nosaka kodu:
- Skaidrs, pārskatāms un pievilcīgs: programmatūra un kods ir vieglāk saprotams, efektīvāks un vienkārši izskatās labāk.
- Viegli uzturams: vienkāršā un skaidrā struktūra atvieglo vairākiem sadarbības partneriem gan jauna, gan esošā koda uzturēšanu un pārvaldību.
- Pielāgojams, paplašināms, atkārtoti izmantojams: pateicoties uzlabotai lasāmībai, samazinātai sarežģītībai un atbildībai, kā arī mazākai atkarībai no klasēm, kodu var labāk rediģēt, pielāgot un paplašināt, izmantojot saskarnes, un elastīgi atkārtoti izmantot.
- Mazāk pakļauts kļūdām: tīrs kods ar vienkāršu struktūru nozīmē, ka izmaiņas vienā koda daļā nejauši neietekmē citas jomas vai funkcijas.
- Drošs un uzticamāks: samazinot vai novēršot ievainojamības, nesaderības un kļūdas, tiek uzlabota sistēmas funkcionalitāte un uzticamība, kas savukārt uzlabo drošību.
Ko nozīmē katrs no SOLID principiem?
SOLID principi ir uzskatāmi par labas programmēšanas zelta likumiem, un tie būtu jāzina ikvienam, kurš nodarbojas ar objektorientētu programmēšanu. Turpinājumā mēs katru principu izskaidrosim sīkāk.
SRP: Vienas atbildības princips
Roberts C. Martins izstrādāja šī principa sākotnējo definīciju grāmatā „Agile Software Development: Principles, Patterns and Practices“ (Ātrā programmatūras izstrāde: principi, modeļi un prakse), rakstot:
„Katram programmatūras modulim vajadzētu būt vienam un tikai vienam iemeslam, kāpēc to mainīt”.
Vienotās atbildības princips (SRP) nosaka, ka katrai klasei objektorientētā programmēšanā (OOP) vajadzētu būt tikai vienai atbildības jomai. Tas nozīmē, ka klases modificēšanai vajadzētu būt tikai vienam iemeslam. Pretēji izplatītajam uzskatam tas nenozīmē, ka klasei vai modulim var būt tikai tieši viens uzdevums. Drīzāk tas nozīmē, ka tai vajadzētu būt atbildīgai tikai par konkrētiem uzdevumiem, kuri ideālā gadījumā nepārklājas ar citām jomām.
Atbildības pārklāšanās, piemēram, funkciju nodrošināšana dažādiem biznesa segmentiem, var ietekmēt klases funkcionalitāti, ja vienā segmentā tiek veiktas izmaiņas. Ja klasei ir vairākas atbildības un daudzas atkarības, viena izmaiņa vienā jomā var izraisīt kļūdas kodā vai nepieciešamību veikt papildu izmaiņas.
Vienotās atbildības princips (SRP) ir izstrādāts, lai veidotu saskaņotus moduļus, kuriem uzticētas konkrētas, skaidri definētas funkcijas vai objekti. Pateicoties tā skaidrajai, strukturētajai uzbūvei ar minimālu atkarību skaitu un neatkarīgām īstenojumiem, izmaiņas un pielāgojumus var veikt efektīvāk, ātrāk un vienkāršāk.
Klases, kas pazīstamas arī kā objektu tipi, ir objektorientētās programmēšanas (OOP) galvenie elementi. Tās var uzskatīt par objektu plāniem, kuros aprakstīti to atribūti, lai programmatūrā varētu atveidot reālās pasaules objektus un jēdzienus. Klases, kas pazīstamas arī kā moduļi, bieži salīdzina ar failu tipiem.
OCP: Atvērtā-slēgtā princips
Saskaņā ar Roberta C. Martina un Bertranda Meijera grāmatu „Objektorientēta programmatūras izstrāde“ OCP nosaka:
„Programmatūras vienībām (klasēm, moduļiem, funkcijām utt.) jābūt atvērtām paplašināšanai, bet slēgtām izmaiņu veikšanai”.
OCP nodrošina, ka, lai ieviestu izmaiņas, nav nepieciešams pārrakstīt programmatūras kodola daļu. Ja ir nepieciešamas padziļinātas izmaiņas kodā, pastāv risks, ka var rasties grūti pamanāmas kļūdas un „kodēšanas smaržas”. Labi strukturētam kodam ir jānodrošina saskarnes, kuras var izmantot, lai to paplašinātu ar papildu funkcijām. Galvenais jēdziens šeit ir klases pārmantošana.
Jaunas funkcijas un paplašinājumi ar skaidri definētām jaunām funkcijām un metodēm, kuras ir jāievieš, var viegli pievienot virsklasei, izmantojot interfeisu apakšklases veidā. Tādējādi nav nepieciešams mainīt jau izstrādāto, stabilo kodu. Tas vienkāršo programmatūras uzturēšanu un apkopi, kā arī ievērojami uzlabo stabilu koda elementu atkārtotas izmantošanas efektivitāti, izmantojot interfeisus.
LSP: Liskova aizvietošanas princips
Kā norāda Barbara H. Liskov un Jeannette M. Wing rakstā „Uzvedības apakštipizācija, izmantojot invariantus un ierobežojumus”, LSP nosaka, ka:
„Pieņemsim, ka q(x) ir īpašība, ko var pierādīt par objektiem x tipa T. Tad q(y) būtu jābūt pierādāmai attiecībā uz objektiem y tipa S, kur S ir T apakštips”.
Tas var šķist neskaidrs, taču patiesībā tas ir diezgan viegli saprotams: saistītās vai paplašinātās apakšklases ir jādarbojas tāpat kā to virsklases vai bāzes klases. Tas nozīmē, ka katrai apakšklasei mantojuma ceļā ir jāsaglabā attiecīgās virsklases īpašības, un šīs īpašības apakšklasē nedrīkst mainīt. Tām principā jābūt aizvietojamām, no kā arī cēlies aizvietošanas princips. Virsklases, savukārt, var tikt mainītas.
Lai to izskaidrotu, aplūkosim Roberta C. Martina klasisko piemēru par taisnstūriem un kvadrātiem. Ģeometrijas stundās mēs apgūstam šādu principu: katrs kvadrāts ir taisnstūris, bet ne katrs taisnstūris ir kvadrāts. Kvadrātam ne tikai visas malas ir taisnleņķīgas, tāpat kā taisnstūrim, bet arī visas tā malas ir vienāda garuma.
Programmēšanā pieņēmums, ka līdzīgas vai šķietami identiskas klases ir savstarpēji saistītas vai atkarīgas viena no otras, rada kļūdas, pārpratumus un neskaidru kodu. Tāpēc programmēšanā klase „Rectangle” nav kvadrāts, un klase „Square” nav taisnstūris. Abas ir atdalītas un īstenotas atsevišķi. Bez integrētas saiknes starp klasēm pārpratumi nevar izraisīt kļūdas starp klasēm. Tas uzlabo drošību un stabilitāti, mainot īstenojumus apakšklasēs vai virsklasēs, neradot nekādas sekas.
ISP: Interfeisu nošķiršanas princips
Saskaņā ar Roberta C. Martina darbu „Interfeisa segregācijas princips“ (The Interface Segregation Principle) ISP tiek definēts šādi:
„Klientiem nevajadzētu būt spiesti paļauties uz saskarnēm, kuras viņi nelieto”.
ISP nosaka, ka lietotājiem nevajadzētu izmantot interfeisus, kas viņiem nav nepieciešami. Citiem vārdiem sakot: lai nodrošinātu klientiem noteiktu klašu funkcijas, tiek izstrādāti jauni, mazāki interfeisi, kas pielāgoti konkrētām prasībām. Tas novērš interfeisu pārmērīgu paplašināšanos un nodrošina, ka starp klasēm neveidojas pārāk ciešas atkarības. Priekšrocība ir tāda, ka programmatūru ar atdalītām klasēm un vairākiem maziem, konkrētām prasībām pielāgotiem interfeisiem ir vieglāk uzturēt.
DIP: Atkarību apgriešanas princips
Saskaņā ar Roberta C. Martina izklāstīto grāmatā „The Dependency Inversion Principle“ piektais un pēdējais no SOLID principiem ir šāds:
„A. Augstāka līmeņa moduļiem nevajadzētu būt atkarīgiem no zemāka līmeņa moduļiem. Abiem vajadzētu būt atkarīgiem no abstrakcijām. B. Abstrakcijām nevajadzētu būt atkarīgām no detaļām”.
DIP nodrošina, ka konkrētas funkcijas un atkarības avota koda slāņos balstās uz abstraktām saskarnēm, nevis tieši viena no otras. Programmatūras arhitektūras parasti tiek strukturētas augstākos lietotāju līmeņos un zemākos, abstraktākos līmeņos. Loģiski varētu domāt, ka abstraktais pamats ietekmē augstāko slāņu darbību. Tomēr DIP šeit norāda uz potenciālu problēmu, jo tas rada augstāko līmeņu atkarību no zemākajiem līmeņiem, kas var izraisīt problēmas.
Tā vietā, lai augstākie līmeņi būtu saistīti ar zemākiem līmeņiem, augstāko un zemāko līmeņu klasēm vajadzētu balstīties uz abstraktām starplīmeņu saskarnēm. Šīs saskarnes iegūst no zemākiem līmeņiem funkcijas, kas nepieciešamas augstākajos līmeņos, un nodrošina to pieejamību. Tādējādi var izvairīties no atkarību hierarhijas, kas veidojas no apakšas uz augšu, jo tā laika gaitā var izraisīt kļūdas kodā. Tas veicina moduļu atkārtotu izmantošanu un ļauj veikt izmaiņas zemākajās klasēs, neietekmējot augstākos līmeņus.
Kas notiek, ja netiek ievēroti SOLID principi?
Tīra un pārskatāma koda izstrāde, kas atvieglo tā uzturēšanu, ir jāuzskata par galveno mērķi programmatūras izstrādē. Ja izstrādātāji neievēro būtiskas vadlīnijas, piemēram, SOLID principus, koda kvalitāte var ievērojami pasliktināties drošības risku, liekuma, uzkrāto kļūdu un pārmērīgu atkarību dēļ. Ekstrēmos gadījumos kods laika gaitā var kļūt nelietojams. Tas ir būtisks jautājums ātrās programmatūras izstrādē, kur sarežģītos programmēšanas uzdevumos bieži vien strādā daudzi cilvēki.
Nepareizi rakstīta koda vai nepietiekamas koda uzturēšanas sekas ir šādas:
- Koda „smakums“: ja kods nav rakstīts atbilstoši nepieciešamajiem standartiem, tas var izraisīt koda „smakumu“ jeb „smakojošu kodu“, kas savukārt var novest pie funkcionālām kļūdām un programmu nesaderības.
- Koda pūšana: ja kods netiek uzturēts vai labots, veicot refaktorizāciju vai dārgu koda pārskatīšanu, tas var figuratīvi „pūst” un pilnībā zaudēt savu funkcionalitāti. Cits termins, kas apzīmē nesaprotamu, sarežģītu kodu, ir spageti kods.
- Drošības riski: Problēmas neaprobežojas tikai ar darbības pārtraukumiem, sarežģītu uzturēšanu un saderības problēmām. Pastāv arī drošības nepilnības, kas ļaunprogrammatūrām sniedz iespējas izmantot kodu, tostarp „zero-day” ekspluatācijas.
Kas izstrādāja SOLID principus?
SOLID principu izcelsme saistīta ar vairākiem principiem, kurus 2000. gadā savā esejā „Design Principles and Design Patterns” pirmo reizi ieviesa Roberts C. Martins („Uncle Bob”), viens no ātrās programmēšanas iniciatoriem. SOLID principus izstrādāja Roberts C. Martins, Bertrands Meijers un Barbara Liskova. Šo viegli iegaumējamo akronīmu popularizēja Maikls Feiters, kurš piecu būtisko principu sākumburtus pārkārtoja viegli iegaumējamā secībā.
Kādi ir līdzīgi programmēšanas principi?
Programmatūras izstrādē principi ir vispārīgas vai ļoti konkrētas vadlīnijas un ieteikumi rīcībai. Papildus SOLID principiem, kas tika izstrādāti objektorientētajai programmēšanai, citi programmēšanas principi tīra koda izstrādei ietver:
- DRY princips (Don’t repeat yourself) funkcijām ar vienu, unikālu izpausmi
- KISS princips (Keep it simple, stupid) kodam, kas veidots pēc iespējas vienkāršāk