Att skriva en snygg, väldesignad och snygg kod är inte så svårt som det ser ut att vara. Det krävs lite ansträngning för att lära känna huvudreglerna och bara använda dem i din kod. Och det behöver inte vara allt på en gång, utan när du känner dig bekväm med en sak kan du försöka tänka på en annan, och så vidare.
Bygg solid, inte dum kod
Låt oss börja med att introducera de mest elementära reglerna som kallas SOLID. Det är en term som beskriver en samling designprinciper för bra kod som uppfanns av Robert C. Martin och hur det går till:
S står för Single Responsibility Principle
Den säger att en klass ska ha en och endast en anledning att förändras. Med andra ord bör en klass bara ha ett jobb att göra, så vi bör undvika att skriva stora klasser med många ansvarsområden. Om vår klass måste göra många saker bör var och en av dem delegeras till separata klasser.
klass Anmälan
def initialisera(params)
@params = params
slut
def anrop
EmailSender.new(meddelande).call
slut
privat
def meddelande
# viss implementering
slut
slut
O betyder öppen/sluten princip
Den säger att man ska kunna utöka en klass beteende utan att modifiera den. Med andra ord ska det vara lätt att utöka en klass utan att göra några ändringar i den. Vi kan uppnå detta t.ex. genom att använda strategimönster eller dekoratorer.
klass Notifiering
def initialize(params, avsändare)
@params = parametrar
@avsändare = avsändare
slut
def anrop
avsändare.anrop meddelande
slut
privat
def meddelande
# viss implementering
slut
slut
klass EmailSender
def call(meddelande)
# lite implementering
slut
slut
klass SmsSändare
def call(meddelande)
# lite implementering
slut
slut
Med denna design är det möjligt att lägga till nya avsändare utan att ändra någon kod.
L betyder Liskov Substitution Principle
Den säger att härledda klasser måste vara utbytbara mot sina basklasser. Med andra ord bör användningen av klasser som kommer från samma förfader vara lätt att ersätta med andra härledda klasser.
klass Logger {
info (meddelande) {
console.info(this._prefixFor('info') + meddelande)
}
error (meddelande, err) {
console.error(this._prefixFor('error') + meddelande)
if (err) {
console.error(err)
}
}
_prefixFor (typ) {
// viss implementering
}
}
klass ScepticLogger utökar Logger {
info (meddelande) {
super.info(meddelande)
console.info(this._prefixFor('info')) + "Och det var allt jag hade att säga.")
}
error (meddelande, err) {
super.error(meddelande, err)
console.error(this._prefixFor('error')) + "Det var som fan!")
}
}
Vi kan enkelt byta ut namnet på klassen, eftersom båda har exakt samma användningsgränssnitt.
Jag menar principen om gränssnittsseparering
Den säger att du bör skapa finkorniga gränssnitt som är kundspecifika. Vad är ett gränssnitt? Det är ett tillhandahållet sätt att använda någon del av koden. Så ett brott mot denna regel kan t.ex. vara en klass med för många metoder samt en metod med för många argumentalternativ. Ett bra exempel för att visualisera denna princip är ett repository-mönster, inte bara för att vi ofta lägger in många metoder i en enda klass utan också för att dessa metoder är utsatta för en risk att acceptera för många argument.
# inte det bästa exemplet den här gången
klass NotificationRepository
def find_all_by_ids(ids:, info:)
notifications = Notification.where(id: ids)
info ? notifications.where(type: :info) : notifications
slut
slut
# och en bättre
klass NotificationRepository
def find_all_by_ids(ids:)
Notifiering.where(id: ids)
slut
def find_all_by_ids_info(ids:)
find_all_by_ids(ids).where(type: :info)
end
slut
D betyder Dependency Inversion Principle (beroendeprincipen)
Den säger att man ska förlita sig på abstraktioner, inte på konkretioner. Med andra ord, en klass som använder en annan klass bör inte vara beroende av dess implementeringsdetaljer, allt som är viktigt är användargränssnittet.
klass Notifiering
def initialize(params, avsändare)
@params = parametrar
@avsändare = avsändare
slut
def anrop
avsändare.anrop meddelande
slut
privat
def meddelande
# viss implementering
slut
slut
Allt vi behöver veta om avsändarobjektet är att det exponerar `call`-metoden som förväntar sig meddelandet som ett argument.
Inte den bästa koden någonsin
Det är också mycket viktigt att känna till de saker som strikt bör undvikas när man skriver kod, så här kommer ytterligare en samling med STUPID-principer som gör att koden inte kan underhållas, svår att testa och återanvändas.
S betyder Singleton
Singletons betraktas ofta som anti-mönster och bör i allmänhet undvikas. Men det största problemet med det här mönstret är att det är en slags ursäkt för globala variabler/metoder och att det snabbt kan överanvändas av utvecklare.
T betyder tät koppling
Den bevaras när en ändring i en modul också kräver ändringar i andra delar av applikationen.
U betyder otestbarhet
Om din kod är bra ska det vara roligt att skriva tester, inte en mardröm.
P betyder för tidig optimering
Ordet för tidigt är nyckeln här, om du inte behöver det nu så är det slöseri med tid. Det är bättre att fokusera på en bra, ren kod än på några mikrooptimeringar - som i allmänhet leder till mer komplex kod.
Jag menar indescriptive namngivning
Det är det svåraste med att skriva bra kod, men kom ihåg att det inte bara är för resten av ditt liv. Team men också för framtida dig, så behandla dig rätt 🙂 Det är bättre att skriva ett långt namn för en metod men det säger allt, än kort och gåtfullt.
D betyder duplicering
Den främsta orsaken till att kod dupliceras är att man följer principen om tät koppling. Om din kod är tätt kopplad kan du bara inte återanvända den och duplicerad kod visas, så följ DRY och upprepa inte dig själv.
Det är inte särskilt viktigt just nu
Jag skulle också vilja nämna två mycket viktiga saker som ofta glöms bort. Den första har du säkert hört talas om - det är YAGNI, vilket betyder: du kommer inte att behöva det. Ibland observerar jag detta problem när jag gör kodgranskning eller till och med skriver min egen kod, men vi bör ändra vårt tänkande när vi implementerar en funktion. Vi bör skriva exakt den kod som vi behöver just nu, inte mer eller mindre. Vi bör ha i åtanke att allt förändras mycket snabbt (särskilt applikationskrav) så det finns ingen anledning att tro att något en dag kommer att komma till nytta. Slösa inte bort din tid.
Jag förstår inte.
Och det sista, som inte är helt uppenbart antar jag, och som kan vara ganska kontroversiellt för vissa, är en beskrivande kod. Med det menar jag inte bara att använda rätt namn för klasser, variabler eller metoder. Det är riktigt, riktigt bra när hela koden är läsbar från första ögonkastet. Vad är syftet med en mycket kort kod när den är så gåtfull som den kan bli och ingen vet vad den gör, förutom den som har skrivit den? Enligt min mening är det bättre att skriva några teckenVillkorskommentarernågot annat mer än ett ord och sedan igår sitta och undra: vänta vad är resultatet, hur gick det till, och så vidare.
const params = [
{
filmer: [
{ titel: "The Shawshank Redemption" },
{ titel: "En flög över gökboet" }
]
},
{
filmer: [
{ titel: "Rädda menige Ryan" },
{ titel: "Pulp Fiction" },
{ titel: "The Shawshank Redemption" },
]
}
]
// första förslaget
funktion unikaMovieTitlarFrån (params) {
const titlar = params
.map(param => param.filmer)
.reduce((prev, nex) => prev.concat(next))
.map(film => film.titel)
return [...ny uppsättning(titlar)]
}
// andra förslaget
function uniqueMovieTitlesFrom (params) {
const titlar = {}
params.forEach(param => {
param.movies.forEach(movie => titles[movie.title] = true)
})
return Object.keys(titlar)
}
Sammanfattningsvis
Som du kan se är det många regler att komma ihåg, men som jag nämnde i början är det en tidsfråga att skriva en bra kod. Om du börjar tänka på en förbättring av dina kodningsvanor så kommer du att se att en annan bra regel kommer att följa, eftersom alla bra saker uppstår av sig själva precis som de dåliga.
Läs mer om detta:
Vad är Ruby on Jets och hur bygger man en app med hjälp av det?
Vuelkalender. Ett nytt Codest-projekt baserat på Vue.js
Codests veckovisa rapport över de bästa tekniska artiklarna. Bygga programvara för 50 miljoner samtidiga socklar (10)