Kena, hästi kujundatud ja hea väljanägemisega koodi kirjutamine ei olegi nii raske, kui tundub. See nõuab veidi vaeva, et õppida tundma põhireegleid ja lihtsalt kasutada neid oma koodis. Ja see ei pea olema nagu kõik korraga, vaid kui tunned end ühe asjaga mugavalt, proovi mõelda teise peale ja nii edasi.
Ehita kindel, mitte rumal kood
Alustame kõige elementaarsemate reeglite tutvustamisest, mida nimetatakse SOLIDiks. See on termin, mis kirjeldab kujunduspõhimõtete kogumikku hea kood mille leiutas Robert C. Martin ja kuidas see käib:
S tähendab ühtse vastutuse põhimõtet
Selles sätestatakse, et klassil peaks olema üks ja ainult üks põhjus, miks seda muuta. Teisisõnu, klassil peaks olema ainult üks ülesanne, nii et me peaksime vältima suurte klasside kirjutamist, millel on palju kohustusi. Kui meie klass peab tegema palju asju, siis tuleks iga ülesanne delegeerida eraldi.
klass Teavitamine
def initialize(params)
@params = params
end
def call
EmailSender.new(message).call
end
private
def message
# mõningane rakendamine
end
end
O tähendab avatud/suletud põhimõtet
Selles on öeldud, et te peaksite saama laiendada klasside käitumist, ilma seda muutmata. Teisisõnu, klassi peaks olema lihtne laiendada ilma seda muutmata. Seda saame saavutada näiteks strateegia mustri või dekoraatorite abil.
klass Teavitamine
def initialize(params, saatja)
@params = params
@sender = saatja
end
def call
sender.call message
end
private
def message
# mõningane rakendamine
end
end
class EmailSender
def call(message)
# mõningane rakendamine
end
end
klass SmsSender
def call(message)
# mõningane rakendamine
end
end
Selle kujunduse abil on võimalik lisada uusi saatjaid ilma koodi muutmata.
L tähendab Liskovi asenduspõhimõtet.
See sätestab, et tuletatud klassid peavad olema asendatavad oma baasklassidega. Teisisõnu, samast esivanemast pärinevate klasside kasutamine peaks olema kergesti asendatav teiste järeltulijatega.
klass Logger {
info (message) {
console.info(this._prefixFor('info') + message)
}
error (message, err) {
console.error(this._prefixFor('error') + message)
if (err) {
console.error(err)
}
}
_prefixFor (type) {
// mingi rakendamine
}
}
class ScepticLogger extends Logger {
info (message) {
super.info(message)
console.info(this._prefixFor('info') + 'Ja see on kõik, mis mul öelda oli.')
}
error (message, err) {
super.error(message, err)
console.error(this._prefixFor('error') + 'Big deal!')
}
}
Me võime klassi nime hõlpsasti asendada, sest mõlemal on täpselt sama kasutajaliides.
Ma mõtlen liidese eraldamise põhimõtet
Selles on öeldud, et tuleks teha kliendispetsiifilisi peeneid liideseid. Mis on liides? See on etteantud viis koodi mingi osa kasutamiseks. Nii et selle reegli rikkumine võib olla näiteks liiga paljude meetoditega klass, samuti liiga paljude argumentide valikuvõimalustega meetod. Hea näide selle põhimõtte visualiseerimiseks on repositooriumi muster, mitte ainult seetõttu, et me paneme sageli ühte klassi palju meetodeid, vaid ka need meetodid on avatud riskile võtta vastu liiga palju argumente.
# ei ole seekord parim näide
class NotificationRepository
def find_all_by_ids(ids:, info:)
notifications = Notification.where(id: ids)
info ? notifications.where(type: :info) : notifications
end
end
# ja parem
class 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 tähendab sõltuvuse ümberpööramise põhimõtet.
Selles öeldakse, et te peaksite sõltuma abstraktsioonidest, mitte konkreetsetest asjadest. Teisisõnu, klass, mis kasutab teist klassi, ei tohiks sõltuda selle rakendamise üksikasjadest, kõik, mis on oluline, on kasutajaliides.
klass Teavitamine
def initialize(params, saatja)
@params = params
@sender = saatja
end
def call
sender.call message
end
private
def message
# mõningane rakendamine
end
end
Kõik, mida me peame saatja objekti kohta teadma, on see, et see eksponeerib meetodi `call`, mis ootab argumendina sõnumit.
Mitte parim kood kunagi
Samuti on väga oluline teada asju, mida tuleks rangelt vältida koodi kirjutamisel, nii et siin läheb veel üks kogumik STUPID põhimõtetega, mis muudab koodi mitte hooldatavaks, raskesti testitavaks ja taaskasutatavaks.
S tähendab Singleton
Singletoneid peetakse sageli antimustriteks ja neid tuleks üldiselt vältida. Kuid peamine probleem selle mustriga on see, et see on omamoodi vabandus globaalsetele muutujatele/meetoditele ja arendajad võivad seda kiiresti üle kasutada.
T tähendab Tight Coupling
See säilib, kui muudatus ühes moodulis nõuab muudatusi ka rakenduse teistes osades.
U tähendab kontrollimatust
Kui teie kood on hea, siis peaks testide kirjutamine tunduma lõbus, mitte õudusunenägu.
P tähendab enneaegset optimeerimist
Sõna "enneaegne" on siinkohal võtmetähtsusega, kui te seda praegu ei vaja, siis on see ajaraiskamine. Parem on keskenduda heale, puhtale koodile kui mõnele mikro-optimeerimisele - mis üldjuhul põhjustab keerukamat koodi.
Ma mõtlen Indescriptive Naming
See on kõige raskem asi hea koodi kirjutamisel, kuid pidage meeles, et see ei ole ainult ülejäänud oma meeskond aga ka tulevastele teile, nii et kohtlege teid õigesti 🙂 Parem on kirjutada meetodile pikk nimi, kuid see ütleb kõik, kui lühike ja mõistatuslik.
D tähendab dubleerimist
Peamine põhjus, miks koodis dubleeritakse, on tiheda sidumise põhimõtte järgimine. Kui teie kood on tihedalt seotud, ei saa te seda lihtsalt uuesti kasutada ja tekib dubleeritud kood, seega järgige DRY ja ärge kordage ennast.
See ei ole praegu eriti oluline.
Tahaksin mainida ka kahte väga olulist asja, mis sageli välja jäetakse. Esimesest peaksite kuulma - see on YAGNI, mis tähendab: te ei vaja seda. Aeg-ajalt täheldan ma seda probleemi koodikontrolli tehes või isegi oma koodi kirjutades, kuid me peaksime oma mõtlemist funktsiooni rakendamisel ümber lülitama. Peaksime kirjutama täpselt seda koodi, mida meil just sel hetkel vaja on, mitte rohkem või vähem. Peaksime silmas pidama, et kõik muutub väga kiiresti (eriti rakenduse nõuded), nii et pole mõtet mõelda, et kunagi tuleb midagi kasuks. Ära raiska oma aega.
Ma ei mõista
Ja viimane asi, mis ei ole vist päris ilmselge ja võib mõnede jaoks olla üsna vastuoluline, on kirjeldav kood. Ma ei mõtle selle all ainult õigete nimede kasutamist klassidele, muutujatele või meetoditele. See on tõesti, tõesti hea, kui kogu kood on esmapilgul loetav. Mis on väga lühikese koodi eesmärk, samas kui see on nii mõistatuslik kui võimalik ja keegi ei tea, mida ta teeb, välja arvatud see, kes selle kirjutas? Minu arvates on parem kirjutada mõned tähedtingimusavaldusedmidagi muud rohkem kui üks sõna ja siis eile istub ja mõtleb: oota, mis on tulemus, kuidas see juhtus ja nii edasi.
const params = [
{
movies: [
{ title: 'The Shawshank Redemption' },
{ title: 'Üks lendas üle kägu pesa' }
]
},
{
movies: [
{ pealkiri: 'Saving Private Ryan' },
{ title: 'Pulp Fiction' },
{ title: "The Shawshank Redemption" },
]
}
]
// esimene ettepanek
function uniqueMovieTitlesFrom (params) {
const titles = params
.map(param => param.movies)
.reduce((prev, nex) => prev.concat(next))
.map(film => film.title)
return [...new Set(titles)]
}
// teine ettepanek
function uniqueMovieTitlesFrom (params) {
const titles = {}
params.forEach(param => {
param.movies.forEach(movie => titles[movie.title] = true)
})
return Object.keys(titles)
}
Kokkuvõtteks
Nagu näete, on palju reegleid, mida meeles pidada, kuid nagu ma alguses mainisin, on ilusa koodi kirjutamine aja küsimus. Kui hakkate mõtlema ühe paranduse peale oma kodeerimisharjumustes, siis näete, et järgneb veel üks hea reegel, sest kõik head asjad tekivad iseenesest nagu halvadki.
Loe edasi:
Mis on Ruby on Jets ja kuidas seda kasutades rakendust luua?
Vuelendar. Uus Codesti projekt, mis põhineb Vue.js-l.
Codesti iganädalane aruanne parimatest tehnikaartiklitest. Tarkvara ehitamine 50 miljoni samaaegse pistikupesa jaoks (10)