Help:Lua/Lua best practice/nb

From Linux Web Expert

Som enhver «beste praksis», så er denne Lua beste praksis tungt påvirket av enhver individuell bidragsyters mening om hva som bør være en god praksis. Bruk det du mener er viktig for ditt spesifikke prosjekt, men vit også at disse reglene har vist at de virker!

Eksemplene i det etterfølgende er for Lua, men de bør være enkle å reformulere for JavaScript, PHP, og Python. Grunnen for å gi eksempler for Lua er at modulene for dette språket er brukt mye, ofte av ikke-programmerere som ikke ser konsekvensene av sine valg.

Som et generelt råd så kan det være til stor hjelp å importere koden i et skikkelig programmeringsmiljø og sjekke det der for åpenbare feil og mangler. Flere frie alternativ eksisterer, blant dem Eclipse, TextMate, og Visual Studio Code for nevne noen få.

Spesielt, bruk et verktøy slik som lualint or luacheck. Det siste er noe bedre. Sjekk også om det er verktøy for deteksjon av rot og andre analyser tilgjengelig for ditt programmeringsmiljø.[1][2]

Husk; konsisten stil er viktigere enn den «riktige» stilen – selv om det er stilen som du foretrekker![3]

Navn

Beskrivende navn
Velg beskrivende navn, unngå alt for generiske navn slik som get() hvis ikke din kode virkelig er generisk. Ikke repeter en beskrivelse over flere nivåer, slik som et metodenavn som er satt til det samme som et klassenavn, hvis ikke metoden faktisk returnerer en klasse av den typen. Tenk fargerike ord, som er mer beskrivende ved større scope, men fjern unødige ord.[4]
Kortnavn
Kryptiske kortnavn bør unngås. Skriv ut navnene, men vær konsistent. Ikke skriv tmp_t, si isteden temporaryTable eller temporary_table. Du kan ofte reformulere kortnavn og fortsatt gjøre dem korte, slik som entities og categories.[5]
Iteratornavn
Iteratorer har vanligvis kortnavn i Lua, og navnene har spesiell mening. Dette er i motsetning til korte navn, og kan skape problemer hvis flere nøstede løkker skal bruke de samme navnene. En vanlig løsning er å legge til en ekstra del som prefiks eller suffiks til navnet, vanligvis fra flertallsformen brukt på samlingen, eller å bruke en entallsform av navnet på samlingen.[6]
Navn med type
Lua har et ganske svakt typesystem, selv om det kan se sterkt ut på noen områder. Argumenter må enten bli tvunget til riktig type, eller så må funksjonen kaste en feilmelding. Hvis funksjonen finnes i spesielle utgaver for å håndtere forskjellige typer, så bør det være del av funksjonens navn.[7]
Akronymer som navn
Akronymer er skremmende for de som ikke kjenner deres mening. Ikke bruk dem med mindre det er helt enkle og åpenbare tilfeller. I et bibliotek for å lage HTML-markup kan td() være akseptabelt, men i et bibliotek for å lage infobokser kan det samme være uønsket.[8]
Format for navn
Formatering av navn bør følge konvensjonen på det faktiske prosjektet. Lua bruker flere formateringsregler, men i Wikimedia virker det som UpperCamelCase for klassenavn, og lowerCamelCase for fuksjoner, metoder og variabelnavn. Modulnavn ser ut som de blir tolket som variabelnavn. Det er ikke noen klar praksis for konstanter, men UPPER_CASE_EMBEDDED_UNDERSCORE ser ut som et godt forslag.[9]
Enkel understrek
I Lua-kode brukes en enkelt understreking som navn når et må angis, men ikke blir brukt. Dette er en placeholder som ellers blir ignorert. Dette respekteres av noen lintverktøy, og bør også respekteres i ordinær kode.[10][11]
Innledende understrek
Ved konvensjon så brukes det en innledende understreking for navn som skal være private, men som av en eller annen grunn må være tilgjengelige fra utsiden. Variable med slike navn bør behandles som private uansett hva som har definert dem, hvis ikke de har en veldig klar forklaring som sier at du kan utføre spesifikke operasjoner på dem.[12][13]

Formatering

Begrens linjelengde
Linjer bør begrenses til en rimelig lengde, typisk rundt 80 tegn. Årsaken er at lange linjer er vanskelige å lese, og når de blir lengre, så har de en tendens til å innkludere flere sammenblandede konsepter, og redigering av dem vil lett skape nye feil.[14]
Innrykk av nye linjer
Programmerere har meninger om hvordan innrykk av nye linjer skal gjøres. Uansett hva slags mening du har, husk at dugnadsprosjekter bør følge noen felles standarder. Vær oppmerksom på at mens en tab ser ut som 4 mellomrom i online-editoren, vises den ikke slik i normal visning. Fordi nettverktøyet gjør innrykk på bestemte måter, bør du sette ditt programmeringsmiljø på samme måte.[15][16]
Binære og linjebrekk
Noen ganger er det nødvendig å sette inn et linjeskift i et uttrykk, vanligvis et if-clause. Dette skaper et spesielt problem, da det åpner for kopi-lim induserte feil. For å unngå problemer kan et enkelt formateringstriks brukes, sett den binære logiske operatøren foran uttrykket på en ny linje.[17]
Example 
Good Bad
if long_statement_A
    and long_statement_B
    and long_statement_C
then
    
if long_statement_A and
    long_statement_B and
    long_statement_C then
    
Mellomrom
Mellomrom er vanligvis en GodTing™, men mennesker bruker på å bli uenige om hvordan det skal brukes. Gjort riktig så øker det vanligvis lesbarhetene til din kode, men gjort feil så blir din kode vanskelig å lese. Finn en stilguide og hold deg til den. Eller bruk et verktøy.[18]

Dokumentasjon

Grensesnitt­dokumentasjon
Grensesnittet er de tilgjengelige funksjonene fra modulen, det vil si de funksjonene du kan kalle opp fra parserfunksjonen. Som et minimum dokumenter hvilke argumenter grensesnittsfunksjonen tar, og hvilke verdier den returnerer. Parserfunksjonen vil bare bruke en enkelt returverdi, uansett hva funksjonen returnerer. Husk å dokumentere om og hvordan metafunksjonen __tostring vil omdanne returverdien.
Oversiktsdokumentasjon
Dokumentasjonen skal ha en oversikt som gir en generell forklaring på hvorfor og hvordan modulen, funksjonen eller variabelen er slik den er. Dette er ikke bare den tiltenkte oppførselen, det er hvorfor funksjonen er slik den er.
Annotering av parametre
Hver parameter skal være korrekt beskrevet. Det vil si, den forventede typen skal angis, og en kort beskrivende streng. Skriv som om LDoc eller et lignende verktøy er tilgjengelig, vanligvis som -- @param type valgfri streng.
Annotering av retur
Hver returverdi skal være korrekt beskrevet. Det vil si, den forventede typen skal angis, og en kort beskrivende streng. Skriv som om LDoc eller et lignende verktøy er tilgjengelig, vanligvis som -- @param type valgfri streng.

Kommentarer

Inline kommentarer for selve koden.

Hvorfor-form på kommentarer
Kommentarer er ikek for deg som koder en eller annen algoritme, de er for den som leser din kode. I kode-stien bør det være svar på alle hvordan-spørsmålene, og i kommentarene bør det være svar på alle hvorfor-sprørsmålene. Ikke gjør feilen å gjenta kode-stien i kommentarene, gode kommentarer skal gi ny innsikt i koden.[19]
Fortell din hensikt
Si hva som er formålet med koden, med et klart og presist språk. Ikke bare skriv en masse ord, tenk på leseren, hva hun trenger for å forstå din kode.[20]
Refaktor utfra kommentarer
Når kode har blitt for komplisert, så er det ikke uvanlig å starte å forklare koden for deg selv. Hvis du trenger dine egne kommentarer, da har noe blitt for vanskelig og du bør refaktorere koden.[21]
Kommentarer om dårlige navn
En kommentar som sier at et navn er dårlig på noe vis hjelper ikke. Ikke kommenter på dårlige navn, rett dem![22]
«Todo» kommentarer
Markøren todo er en av flere vanlig markører, og kan tolkes som "kode som programmereren ikke har nådd å fikse enda". Vanligvis bør du skrive dette som -- @todo valgfri streng.[23]
«Fixme» kommentarer
Markøren fixme er en av flere vanlig markører, og kan tolkes som "kode som andre enn programmereren har identifisert som feilende". Vanligvis bør du skrive dette som -- @fixme valgfri streng. Dette er en invitasjon til andre om å forsøke å rette koden.[24]
«Hack» kommentarer
Markøren hack er en av flere vanlig markører, og kan tolkes som "kode som andre enn programmereren har identifisert som feilende og har forsøkt rettet på en uelegant måte". Vanligvis bør du skrive dette som -- @hack valgfri streng. Dette er en invitasjon til andre om å forsøke å rette koden.[25]
«XXX» kommentar
Markøren xxx er en av flere vanlig markører, og kan tolkes som "kode er identifisert som farlig ødelagt". Vanligvis bør du skrive dette som -- @xxx valgfri streng. Denne markøren skal ikke være i produksjonskode, koden bør fikses asap.[26]
Kommenter magiske tall
Konstanter og andre magiske tall bør ha kommentarer som forklarer hvorfor de har et spesifikt innhold. Hvorfor er linjelengden satt til 80 tegn? Hvorfor er π forkortet til 3,14?[27]


Kode

Små mønstre og kodepraksis.

Programvaremønstre
Mye arbeid har gått i å identifisere felles programvaremønstre, og utvikle gode generelle løsninger for disse mønstrene. Hvis du mistenker at du forsøker å gjøre noe som har et felles mønster, så gjør et søk og sjekk ut hvordan du implementerer mønsteret. Likevel, vær klar over at mønstre for språk med closure kan være svært forskjellige fra de uten closure. Vanligvis brukes det tabeller i Lua for å lage objekter, men de kan også skapes med closures. If you suspect you are attempting to do something that has a common pattern then do a search and check out how to implement the pattern. Still, know that patterns for languages with closures can be very different from those without closures. Usually tables are used in Lua to create objects, but they can also be created as closures.[28][29][30]
Sitattegn for strenger
I Lua finnes det flere typer anførselstegn for strenger. Velg en av dem og hold deg til den. Hvis du trenger flere typer anførselstegn, kan du enten bruke det vanligste anførselstegnet på det ytre nivået eller det innerste, og jobbe deg utover. Innenfra og ut enkelt anførselstegn som det primære anførselstegnet og doble anførselstegn som det sekundære synes å være vanlig, men det kan være tilfeldig. Hvis flere anførselstegn er nødvendige, så begynn å bruke doble firkantparenteser på ternært nivå.[31][32]
Tidlig retur
Returner så tidlig som mulig, spesielt hvis noe feiler. Vanligvis er programmerere fortalt at de skal bruke et enkelt returpunkt, men på grunn av språkkonstruksjonene i Lua så virker det som om dette skaper dypt nøstet kode. Det er derfor bedre å returnere tidlig.[33]
Example 
Good Bad

if done then
    return done
end


if not done then
    
end

return done
Sanne uttrykk først
Vanligvis er du fri til å ordne then- og else-betingelser slik det passer best, og da bør du organisere dem slik at if-betingelsen har en positiv test. Dette gjør at at koden blir enklere å lese. Hvis du kan unngå else-betingelsen så er det imidlertid viktigere.[34]
Example 
Good Bad
if a == b then
    
else
    
end
if a ~= b then
    
else
    
end
Spør først
Vanligvis plasseres den spurte verdien først i et logisk uttrykk, da dette er mer naturlig å lese og dermed er mindre utsatt for feil. Den omvendte formen kalles noen ganger for Yoda-formen. Noen ganger (men sjeldent) fungerer ikke den naturlige formen som forventet, og koden terminerer. Dette kan skyldes at Lua feiler i å finne den riktige hale-rekursive formen til uttrykket, og deretter får en stack overflow.[35]
Example 
Good Bad
if length > 10 then
    
if 10 <= length then
    
Angi standardverdi
På språk med en or operator som i Lua, er det veldig enkelt å angi standardverdier. Dette er fint da noen vanlige konstruksjoner feiler grovt hvis de får en uinitialisert verdi. Dette skjer for eksempel når en tabell er uinitialisert og koden forsøker å indeksere nil-verdien.[36]
Example 
Good Bad

local t = arg or {}

t['foo']

local t = arg

if t then
    t['foo']
else
    
end
Binær betingelse
Lua har ikke en binær betinget operator, men du kan likevel gjøre det samme med en or. Det som skjer er nok litt litt merkelig for nybegynnere i Lua. Operatorene and og or overfører sannhetsverdier (mmaterielle verdier), og dermed kan de være en del av andre uttrykk enn bare logiske.[37]
Example 
Good Bad
local area = (length or 0) * (width or 0)
local area = 0
if length and width then
    area = length * width
end
Trinær betingelse
Lua har ikke en trinær betinget operator, men du kan likevel gjøre det samme med en and og en or. Det som skjer er nok litt litt merkelig for nybegynnere i Lua. Operatorene and og or overfører sannhetsverdier (mmaterielle verdier), og dermed kan de være en del av andre uttrykk enn bare logiske.[38]
Example 
Good Bad
local height = pressure and millibarToMeters(length) or 0
local height = 0
if pressure then
    height = millibarToMeters(pressure)
end
Note that the form a and b or c where b is falsy will give c as outcome. That may not be the expected behavior.
Unngå repeat…until
Loop-konstruksjonen repeat... until forsinker testen til etter loopen. Dette medfører lett feil og bør unngås. De eneste gangene dette er akseptabelt, er når testen selv er kostbar i forhold til den utførte blokken, eller hvis man ved å unngå repetisjonsklausulen vil utløse ytterligere kode for opprydding eller avslutning.[39]
Test argumenter
Det er et lite verktøy libraryUtil for å teste typen til argumenter, og dette bør brukes for å unngå enkle misforståelser. Ofte er argumentene gyldige når andre koder er korrekte, men i grensetilfeller skaper noe et kall utenfor det forventede typeområdet, og koden feiler på mystiske vis. Riktig testing kan fange en feil tidlig, og øke sannsynligheten for å oppdage den virkelige årsaken. Vær oppmerksom på at type testing er en test for fail, og ikke en test for korrekthet.
Example 
Good Bad
local util = require 'libraryUtil'
local checkType = util.checkType

function concat( a, b )
    checkType( 'foo', 1, a, 'string' )
    checkType( 'foo', 1, b, 'number' )
    return a..'='..tostring(b)
end
function foo( a, b )
    return a..'='..tostring(b)
end


Mønstre

Noen få veldig vanlige programmeringsmønstre.

Kommandomønster
Det vanligste programvaremønsteret i Lua-moduler, det vil si det som vanligvis mangler, er command pattern. Noen data er tilgjengelige, og en aksjon bør velges gitt disse dataene. En typisk smell (lukt) som om at et command pattern mangler er lange kjeder av if-then-elseif-end -tester. Den vanligste varianten har ikke navngitte kommandoer, men en aksept-kvalifiseringsfunksjon. Begge versjonene er svært vanlige når en analyserer argumenter fra "invoke" parserfunksjonen.
Example 
local commands = {}
-- each member of the command table is a simplified "ConcreteCommand"
commands['foo'] = function( val ) return -math.sqrt(-val) end
commands['bar'] = function( val ) return 0 end
commands['baz'] = function( val ) return math.sqrt(val) end

function sqrt( command, value ) -- execute for the "Command"
    return commands[command]( value ) -- execute for the "ConcreteCommand"
end

sqrt( -4 ) --> -2 (Should really be a complex number!)
local commands = {}
-- each member of the command table is a simplified "ConcreteCommand"
table.insert( commands, { function( val ) return value < 0 end, function( val ) return -math.sqrt(-val) end } )
table.insert( commands, { function( val ) return value == 0 end, function( val ) return 0 end } )
table.insert( commands, { function( val ) return value > 0 end, function( val ) return math.sqrt(val) end } )

function sumSqrt( value ) -- execute for the "Command"
    local accumulator = 0
    for _,command in ipairs( commands ) do
        command[1]( value ) then -- accept for the "ConcreteCommand"
            accumulator = accumulator + command[2]( value ) -- execute for the "ConcreteCommand"
        end
    end

end

sumSqrt( -4 ) --> -2 (Should really be a complex number!)

Testbarhet

Om testing og hvordan du gjør koden testbar. Vær oppmerksom på at den opprinnelige boken fra firergjengen har programmeringsmønstre for sterkt typede språk, som ikke passer svakt typede språk særlig godt.[40] Hvorvidt Lua er sterkt typet, eller svakt, kan debatteres.[41]

Kompleksitet
Det er vanligvis flere kjøreveier gjennom en gitt kode, og dette gjør koden vanskelig å forstå. Desto flere kodeveier desto vanskeligere blir koden. Dette kan måles som cyclomatic complexity, og gir et tall på veier ved å telle grenpunkter. Dette gir et rettferdig, men ikke veldig godt mål på kodekvalitet.[42]
Unngå globale
Funksjoner med globale er vanskelige å teste, uansett hvordan globalene er inkludert i koden. For å unngå denne uheldige feilen så kan biblioteker inkluderes for å sjekke modulen, slik som require('Module:No globals'). Vær oppmerksom på at requiring kode er som å importere en global, så vær forsiktig så du ikke skaper et større problem. [43][44][45]
Example 
Good Bad
local t = {}
function f( arg, opts )
    do_something( arg, opts )
end
f( 'somevalue', t )
local t = {}
function f( arg )
    do_something( arg, t )
end
f( 'somevalue' )
Unngå å endre scope
I Lua er det mulig å sjekke omfanget av en funksjon. Ikke gjør det, da funksjonen blir avhengig av «mini-globals», som er nesten like ille som globals. Hvis alt fungerer som det skal, så vil mini-globalene trolig være semi-konstante, men det er ikke garantert.

Sikkerhet

Lua kjører i en form for sandkasse-miljø, du kan si at Lua-koden eksekveres i en demilitarisert sone på utsiden av den vanlige tjeneren, hvor kun noen få kall passerer gjennom veggen og disse bør grundig valideres av den interne koden. Generelt bør det ikke være noen grunn til å ta spesielle forhåndsregler for å gjøre koden sikker, fordi resultatet fra utførelsen av koden vil passere gjennom grundig vasking og escaping før det blir inkludert på siden.

Se også

Programmeringsmiljø

Noen råd om hvordan du konfigurerer ditt eksterne programmeringsmiljø.

Visual Studio Code

Bruk noe ala de følgende utvidelsene.

Andre verktøy

Dette er verktøy du kan finne nyttig.

Referanser

  1. LuaUsers: LuaLint
  2. GitHub: mpeterv/luacheck
  3. The Art of Readable Code p. 21,34,43.
  4. The Art of Readable Code pp. 8-11, Choose Specific Words.
  5. The Art of Readable Code pp. 18-19, How Long Should a Name Be?
  6. The Art of Readable Code p. 12, Loop iterators.
  7. The Art of Readable Code pp. 15-17, Attaching Extra Information to a Name.
  8. The Art of Readable Code pp. 19-20, Acronyms and Abbreviations.
  9. The Art of Readable Code pp. 20-21, Use Name Formatting to Convey Meaning.
  10. LuaUsers:LuaStyleGuide
  11. Programming in Lua: 1.3 – Some Lexical Conventions
  12. LuaUsers:LuaStyleGuide
  13. Programming in Lua: 1.3 – Some Lexical Conventions
  14. PEP-8: Maximum Line Length (This style guide use 79 chars.)
  15. PEP-8: Indentation
  16. PEP-8: Tabs or spaces
  17. PEP-8: Should a line break before or after a binary operator?
  18. PEP-8: Whitespace in Expressions and Statements
  19. The Art of Readable Code p. 56. The box has an alternate approach to what-why-how.
  20. The Art of Readable Code pp. 62-63, State the Intent of Your Code.
  21. Refactoring Guru: CodeSmells: Disposables: Comments
  22. The Art of Readable Code p. 49, Don’t Comment Bad Names—Fix the Names Instead.
  23. The Art of Readable Code p. 50, Comment the Flaws in Your Code.
  24. The Art of Readable Code p. 50, Comment the Flaws in Your Code.
  25. The Art of Readable Code p. 50, Comment the Flaws in Your Code.
  26. The Art of Readable Code p. 50, Comment the Flaws in Your Code.
  27. The Art of Readable Code p. 51, Comment on Your Constants.
  28. JavaScript Patterns. p. 2
  29. Programming in Lua: 6.1 – Closures
  30. LuaUsers: Minimising Closures
  31. PEP-8: String Quotes
  32. LuaUsers: StringsTutorial
  33. The Art of Readable Code pp. 75-79, Returning Early from a Function.
  34. The Art of Readable Code pp. 70-73, The Order of Arguments in Conditionals.
  35. The Art of Readable Code pp. 70-73, The Order of Arguments in Conditionals.
  36. Programming in Lua: 3.3 – Logical Operators
  37. LuaUsers: TernaryOperator (This is for ternary conditional, but the binary conditional is pretty similar.)
  38. LuaUsers: TernaryOperator
  39. The Art of Readable Code pp. 74-75, Avoid do/while Loops.
  40. JavaScript Patterns. p. 2
  41. Lua for Python Programmers: Types
  42. Quandary Peak Research: Measuring Software Maintainability
  43. C2Wiki: Global Variables Are Bad
  44. PlayControl Software: Using closures in Lua to avoid global variables for callbacks
  45. JavaScript Patterns, pp. 12-13

Lesing