Parašyti gražų, gerai suprojektuotą ir gerai atrodantį kodą nėra taip sunku, kaip atrodo. Reikia šiek tiek pastangų, kad susipažintumėte su pagrindinėmis taisyklėmis ir tiesiog jas naudotumėte savo kode. Ir tai neturi būti kaip viskas iš karto, bet kai jaučiatės patogiai su vienu dalyku, pabandykite pagalvoti apie kitą ir t. t.
Kurkite tvirtą, o ne kvailą kodą
Pradėkime nuo elementariausių taisyklių, kurios vadinamos SOLID. Tai terminas, apibūdinantis gero dizaino principų rinkinį. kodas kurį sugalvojo Robertas C. Martinas, ir kaip jis veikia:
S - bendrosios atsakomybės principas
Jame teigiama, kad klasė turėtų turėti vieną ir tik vieną priežastį, dėl kurios ją reikėtų keisti. Kitaip tariant, klasė turėtų atlikti tik vieną užduotį, todėl turėtume vengti rašyti dideles klases su daugybe pareigų. Jei mūsų klasė turi atlikti daugybę užduočių, tuomet kiekvieną iš jų reikėtų deleguoti į atskiras.
klasė Pranešimas
def initialize(params)
@params = params
end
def call
EmailSender.new(message).call
end
privatus
def pranešimas
# tam tikras įgyvendinimas
pabaiga
pabaiga
O - atviras / uždaras principas
Jame teigiama, kad turėtumėte turėti galimybę išplėsti klasės elgseną jos nekeisdami. Kitaip tariant, turėtų būti lengva išplėsti klasę jos nekeičiant. Tai galime pasiekti, pavyzdžiui, naudodami strategijos modelį arba dekoratorius.
klasė Pranešimas
def initialize(params, sender)
@params = params
@sender = sender
end
def call
sender.call message
end
privatus
def pranešimas
# tam tikras įgyvendinimas
pabaiga
pabaiga
klasė EmailSender
def call(message)
# kai kurios įgyvendinimo priemonės
end
end
klasė SmsSender
def call(pranešimas)
# kai kurie įgyvendinimo būdai
end
pabaiga
Naudojant šią konstrukciją galima pridėti naujų siuntėjų nekeičiant kodo.
L - Liskovo pakeitimo principas
Jame teigiama, kad išvestinės klasės turi būti pakeičiamos savo bazinėmis klasėmis. Kitaip tariant, klasių, kilusių iš to paties protėvio, naudojimą turi būti lengva pakeisti kita išvestine klase.
klasė Logger {
info (pranešimas) {
console.info(this._prefixFor('info') + pranešimas)
}
error (pranešimas, err) {
console.error(this._prefixFor('error') + pranešimas)
if (err) {
console.error(err)
}
}
_prefixFor (type) {
// tam tikras įgyvendinimas
}
}
klasė ScepticLogger extends Logger {
info (pranešimas) {
super.info(pranešimas)
console.info(this._prefixFor('info') + 'Ir tai viskas, ką norėjau pasakyti.')
}
error (pranešimas, err) {
super.error(message, err)
console.error(this._prefixFor('error') + 'Big deal!')
}
}
Galime lengvai pakeisti klasės pavadinimą, nes abi klasės turi lygiai tokią pačią naudojimo sąsają.
Turiu omenyje sąsajos atskyrimo principą
Jame teigiama, kad turėtumėte sukurti smulkiagrūdes sąsajas, kurios būtų pritaikytos konkrečiam klientui. Kas yra sąsaja? Tai numatytas tam tikros kodo dalies naudojimo būdas. Taigi šios taisyklės pažeidimas gali būti, pavyzdžiui, klasė, turinti per daug metodų, taip pat metodas, turintis per daug argumentų parinkčių. Geras pavyzdys šiam principui įsivaizduoti yra saugyklos modelis, ne tik todėl, kad dažnai į vieną klasę įtraukiame daug metodų, bet ir todėl, kad tie metodai gali priimti per daug argumentų.
# šį kartą nėra geriausias pavyzdys
klasė NotificationRepository
def find_all_by_ids(ids:, info:)
notifications = Notification.where(id: ids)
info ? notifications.where(type: :info) : notifications
end
end
# ir geresnis
klasė NotificationRepository
def find_all_by_ids(ids:)
Notification.where(id: ids)
end
def find_all_by_ids_info(ids:)
find_all_by_ids(ids).where(type: :info)
end
end
D - priklausomybės inversijos principas
Jame teigiama, kad turėtumėte remtis abstrakcijomis, o ne konkretybėmis. Kitaip tariant, klasė, kuri naudoja kitą klasę, neturėtų priklausyti nuo jos įgyvendinimo detalių, svarbu tik naudotojo sąsaja.
klasė Pranešimas
def initialize(params, sender)
@params = params
@sender = sender
end
def call
sender.call message
end
privatus
def pranešimas
# tam tikras įgyvendinimas
pabaiga
pabaiga
Viskas, ką turime žinoti apie sender objektą, yra tai, kad jis pateikia `call` metodą, kuris tikisi pranešimo kaip argumento.
Ne pats geriausias kodas
Taip pat labai svarbu žinoti dalykus, kurių reikėtų griežtai vengti rašant kodą, todėl čia pateikiame dar vieną rinkinį su kvailiais principais, dėl kurių kodas nėra prižiūrimas, sunkiai testuojamas ir pakartotinai naudojamas.
S - Singleton
Singletonai dažnai laikomi antišablonais ir paprastai jų reikėtų vengti. Tačiau pagrindinė šio šablono problema yra ta, kad jis yra tarsi pasiteisinimas globaliems kintamiesiems ir (arba) metodams, todėl programuotojai gali greitai persistengti.
T - sandari jungtis
Jis išsaugomas, kai keičiant vieną modulį reikia keisti ir kitas programos dalis.
U - nepatikimumas
Jei jūsų kodas yra geras, testų rašymas turėtų būti smagus, o ne košmaras.
P - priešlaikinis optimizavimas
Svarbiausia yra žodis "per anksti" - jei jums to nereikia dabar, tai tik laiko švaistymas. Geriau sutelkti dėmesį į gerą, švarų kodą nei į tam tikrą mikrooptimizaciją, kuri paprastai sukelia sudėtingesnį kodą.
Turiu omenyje neaprašomuosius pavadinimus
Tai sunkiausias dalykas rašant gerą kodą, tačiau nepamirškite, kad tai ne tik komanda bet taip pat ir būsimiems jums, todėl elkitės su jumis teisingai 🙂 Geriau parašyti ilgą metodo pavadinimą, bet jis viską pasako, nei trumpą ir mįslingą.
D - dubliavimas
Pagrindinė kodo dubliavimo priežastis - griežto susiejimo principas. Jei jūsų kodas yra glaudžiai susietas, jo tiesiog negalite pakartotinai naudoti ir atsiranda pasikartojantis kodas, todėl laikykitės DRY principo ir nesikartokite.
Dabar tai nėra labai svarbu
Taip pat norėčiau paminėti du labai svarbius dalykus, apie kuriuos dažnai nutylima. Apie pirmąjį turėjote girdėti - tai YAGNI, o tai reiškia: jums to neprireiks. Retkarčiais pastebiu šią problemą atlikdamas kodo peržiūrą ar net rašydamas savo kodą, tačiau turėtume pakeisti savo mąstymą apie funkcijos įgyvendinimą. Turėtume rašyti būtent tokį kodą, kokio mums reikia šią akimirką, o ne daugiau ar mažiau. Turėtume turėti omenyje, kad viskas labai greitai keičiasi (ypač taikomųjų programų reikalavimai), todėl nėra prasmės galvoti, kad kažkas kada nors pravers. Nešvaistykite laiko veltui.
Nesuprantu
Ir paskutinis dalykas, kuris, manau, nėra akivaizdus ir kai kuriems gali būti gana prieštaringas, tai aprašomasis kodas. Turiu omenyje ne tik tinkamų klasių, kintamųjų ar metodų pavadinimų naudojimą. Labai, labai gerai, kai visas kodas yra įskaitomas iš pirmo žvilgsnio. Koks yra labai trumpo kodo tikslas, o jis yra toks mįslingas, koks tik gali būti, ir niekas nežino, ką jis daro, išskyrus jį parašiusį asmenį? Mano nuomone, geriau parašyti keletą ženklųsąlygų teiginiaiką nors daugiau nei vieną žodį, o po to vakar sėdi ir galvoji: palauk, koks rezultatas, kaip tai įvyko ir pan.
const params = [
{
filmai: [
{ title: 'The Shawshank Redemption' },
{ pavadinimas: 'One Flew Over the Cuckoo's Nest' }
]
},
{
filmai: [
{ pavadinimas: "Saving Private Ryan" },
{ pavadinimas: "Pulp Fiction" },
{ pavadinimas: "The Shawshank Redemption" },
]
}
]
// pirmasis pasiūlymas
funkcija uniqueMovieTitlesFrom (params) {
const titles = params
.map(param => param.movies)
.reduce((prev, nex) => prev.concat(next))
.map(movie => movie.title)
return [...new Set(titles)]
}
// antrasis pasiūlymas
funkcija uniqueMovieTitlesFrom (params) {
const titles = {}
params.forEach(param => {
param.movies.forEach(movie => titles[movie.title] = true)
})
return Object.keys(titles)
}
Apibendrinant
Kaip matote, reikia prisiminti daug taisyklių, bet, kaip minėjau pradžioje, gražaus kodo rašymas yra laiko klausimas. Jei pradėsite galvoti apie vieną savo kodavimo įpročių patobulinimą, pamatysite, kad po to atsiras kita gera taisyklė, nes visi geri dalykai atsiranda savaime, kaip ir blogi.
Skaityti daugiau:
Kas yra "Ruby on Jets" ir kaip sukurti programėlę naudojant šią programėlę?
1TP68Kalendorius. Naujas Codest's projektas, paremtas Vue.js
"Codest" kassavaitinė geriausių technologijų straipsnių ataskaita. Programinės įrangos kūrimas 50 mln. vienu metu veikiančių lizdų (10)