Help:Lua/Lua best practice/nl
Deze pagina is op het moment een concept.
|
Zoals elke beste aanpak, wordt deze Lua beste aanpak sterk beïnvloed door de indruk van individuele bijdragers over wat een goede aanpak in de praktijk zou zijn. Gebruik wat u denkt dat belangrijk is voor uw specifieke project, maar weet ook dat deze regels werken!
De voorbeelden in het volgende zijn voor Lua, maar ze zouden makkelijk te herformuleren moeten zijn voor JavaScript, PHP en Python. De reden om voorbeelden voor Lua te geven is dat modules voor deze taal veel worden gebruikt, vaak door niet-programmeurs die de gevolgen van hun keuzes niet zien.
Een algemeen advies is dat het erg helpen om de code te importeren in een goede programmeeromgeving en daar te controleren op duidelijke fouten. Er bestaan verschillende gratis opties, waaronder Eclipse, TextMate, en Visual Studio Code om er een paar te noemen.
Gebruik vooral een lint hulpmiddel zoals lualint of luacheck. De laatste is iets beter. Controleer ook of er voor uw programmeringsomgeving hulpmiddelen voor het detecteren van storingen of andere analyses beschikbaar zijn.[1][2]
Onthoud: een consistente stijl is belangrijker dan de "juiste" stijl - zelfs als die stijl de beste is![3]
Namen
- Beschrijvende namen
- Kies beschrijvende namen, vermijd te generieke namen zoals
get()tenzij uw code echt generiek is. Herhaal een beschrijving niet op meerdere niveaus, zoals een methodenaam die op hetzelfde is gezet als de naam van een class, tenzij de methode daadwerkelijk een class van dat type teruggeeft. Denk aan 'kleurrijke' woorden, meer beschrijvend voor grotere scopes, maar gooi overbodige woorden weg.[4] - Korte namen
- Cryptische korte namen moeten worden vermeden. Schrijf de namen uit, maar blijf beknopt. Gebruik niet
tmp_t, zeg in plaats daarvantemporaryTableoftemporary_table. Vaak kan men de korte namen opnieuw formuleren en ze nog steeds kort houden, zoalsentiteitenencategories. Gebruik bijvoorbeeld een naam met meervoud voor tabellen met verschillende waarden.[5] - Iterator namen
- Iterators hebben meestal korte namen in Lua, en de namen hebben een speciale betekenis. Dit gaat in tegen korte namen en kan problemen veroorzaken als meerdere geneste lussen dezelfde namen gebruiken. Een veelgebruikte oplossing is het voorvoegen of achtervoegsel van een extra deel aan de naam, meestal uit de meervoudsvorm die door de collectie wordt gebruikt, of om een enkelvoud van de naam van de collectie te gebruiken.[6]
- Namen met types
- Lua heeft een vrij zwak type systeem, zelfs al lijkt het dat het sterk is op sommige delen. Argumenten moeten ofwel worden gedwongen tot het juiste type, of de functie moet een fout geven. Als de functie bestaat in speciale incarnaties om verschillende soorten te behandelen, dan moet dat onderdeel zijn van de functienaam.[7]
- Acroniemen als namen
- Acroniemen zijn intimiderend voor degenen die hun betekenis niet weten. Gebruik ze niet tenzij het de eenvoudigste en meest voor de hand liggende geval is. In een bibliotheek voor het maken van HTML-markering kan
td()aanvaardbaar zijn, maar in een bibliotheek voor het maken of het maken van infoboxen kan hetzelfde niet aanvaardbaar worden.[8] - Formaat namen
- De opmaak van namen moet de conventie van het daadwerkelijke project volgen. Lua gebruikt als zodanig verschillende opmaakstijlen, maar in Wikimedia-projecten lijkt het UpperCamelCase voor class-namen, en lowerCamelCase voor functie-, methode- en variabelenamen. Modulenamen lijken te worden geïnterpreteerd als variabelenamen. Er is geen duidelijke praktijk voor constanten, maar UPPER_CASE_EMBEDDED_UNDERSCORE lijkt me een verstandige keuze.[9]
- Enkel liggend streepje
- In Lua-code wordt een naam met een enkel liggend streepje gebruikt waar een naam moet worden opgegeven, maar deze wordt niet gebruikt. Dat wil zeggen, het is een placeholder die anders genegeerd wordt. Dit wordt erkend door sommige lint hulpmiddelen en moet ook worden gerespecteerd in gewone codes.[10][11]
- Liggend streepje vooraan
- Bij conventie wordt een liggend streepje vooraan gebruikt voor namen die enigszins privé zijn, maar om een of andere reden moeten worden geplaatst zodat het van buitenaf toegankelijk is. Variabelen met dergelijke namen moeten worden behandeld als privé voor wat ze ook definieert, tenzij ze een zeer duidelijke verklaring hebben die zegt dat u bepaalde specifieke operaties kunt doen op hen.[12][13]
Opmaak
- Limiet regellengte
- Regels moeten beperkt worden tot een redelijke lengte, meestal rond de 80 tekens. De reden is dat lange regels moeilijk te lezen zijn, en naarmate ze langer worden, bevatten ze vaak meer verstrengelde concepten, en het bewerken ervan zal nieuwe bugs veroorzaken.[14]
- Inspringen bij nieuwe regels
- Programmeurs hebben meningen over hoe men het inspringen van nieuwe regels kunt doen. Wat u ook van mening bent, onthoud dat projecten die door het publiek worden gedaan, aan enkele gemeenschappelijke normen moeten voldoen. Let op dat hoewel een 'tab' er in de online editor uitziet as 4 ruimtes, het niet zo verschijnt in de normale weergave. Omdat de online editor op specifieke manieren aan inspringing doet, moet u uw programmeeromgeving zo instellen dat ze zich zo gedraagt.[15][16]
- Tweedelige componenten en regelafbrekingen
- Soms is het nodig om een regelovergang in een expressie te plaatsen, meestal een if-clausule. Dit is een bijzonder probleem, aangezien er fouten ontstaan die door kopie-plak worden veroorzaakt. Om problemen te voorkomen kan een eenvoudige opmaak trucs worden gebruikt, gewoon de logische binaire operator voor het deel op een nieuwe regel.[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 …
- Witruimte
- Witruimte is meestal een goede zaak™, maar mensen zijn het vaak oneens over hoe men het moet gebruiken. Als menhet goed doet, verhoogt het de leesbaarheid van de code, maar als men het fout doet, kan de code erg moeilijk te lezen zijn. Zoek een stijlgids en houd u eraan. Of gebruik een hulpmiddel.[18]
Documentatie
- Interface documentatie
- De interface heeft de openbare functies van de module, dat wil zeggen de functies die u kunt invoeren van de parserfunctie. Als minimaal document, welke argumenten de interfacefunctie neemt en welke waarde het teruggeeft. De parserfunctie zal slechts één waarde teruggeven, ongeacht wat de functie teruggeeft. Vergeet niet om te documenteren of en hoe de metafunctie
__tostringde waarde zal transformeren. - Overzicht documentatie
- De documentatie moet een overzicht hebben om een algemene verklaring te geven van waarom en hoe de module, functie of variabele is zoals ze is. Dit is niet alleen het beoogde gedrag, het is de reden waarom het gedrag is zoals het is.
- Parameter uitleg
- Elke parameter moet correct worden uitgelegd. Dat is het verwachte type dat gegeven moet worden en een korte beschrijvende tekst. Schrijf het alsLDoc of een vergelijkbaar hulpmiddel beschikbaar is, meestal als
-- @param type optionele tekst. - Retourwaarde uitleg
- Elke retourwaarde moet correct worden uitgelegd. Dat is het verwachte type dat gegeven moet worden en een korte beschrijvende tekst. Schrijf het als LDoc of een vergelijkbaar hulpmiddel beschikbaar is, meestal als
-- @return type optionele tekst.
Commentaar
Inline commentaar voor de code zelf.
- Waarom-vorm van commentaar
- Commentaar is niet alleen voor u als de persoon die het programma heeft geschreven, maar ook voor degenen die uw code lezen. In het codepad moeten antwoorden staan op de hoe-vragen en in het commentaar moeten antwoorden staan op de waarom-vragen. Maak niet de fout de tekst in het codepad te herhalen in het commentaar, goed commentaar geeft een nieuw inzicht in de code.[19]
- Geef uw bedoeling aan
- Geef de bedoeling van uw code, in een duidelijke en precieze taal. Voeg niet alleen veel woorden toe, denk aan de lezer, wat moet die weten om de code te begrijpen.[20]
- Commentaar opnieuw schrijven
- Wanneer de code complex is geworden, is het gebruikelijk om de code te verklaren om uzelf te helpen. Als u uw eigen opmerkingen nodig heeft, is er iets te ingewikkeld geworden en moet u de code refactoren.[21]
- Commentaar op slechte namen
- Een opmerking dat een naam in zekere zin slecht is, helpt niet. Geef geen commentaar, maar maak ze goed![22]
- Commentaar "Todo"
- De tekst todo is een van de veelvoorkomende en kan worden geïnterpreteerd als "code die de programmeur nog niet heeft opgelost". Meestal moet u het schrijven als
-- @todo optionele string.[23] - Commentaar "Fixme"
- De tekst fixme is een van de veelvoorkomende en kan worden geïnterpreteerd als "code die iemand anders dan de programmeur als kapot heeft geïdentificeerd". Meestal moet u het schrijven als
-- @fixme optionele string. Dit is een uitnodiging aan anderen om te proberen de code te verbeteren.[24] - Commentaar "Hack"
- De tekst hack is een van de veelvoorkomende en kan worden geïnterpreteerd als "code die iemand anders dan de programmeur als kapot heeft geïdentificeerd en op een minder elegante manier heeft proberen te verbeteren". Meestal moet u het schrijven als
-- @fhack optionele string. Dit is een uitnodiging aan anderen om te proberen de code te verbeteren.[25] - Commentaar "XXX"
- De tekst xxx is een van de veelvoorkomende en kan worden geïnterpreteerd als "code geïdentificeerd als gevaarlijk gebroken". Meestal moet u het schrijven als
-- @xxx optionele string. Deze tekst hoort niet in productiecode te staan, de code moet zo snel mogelijk worden verbeterd.[26] - Commentaar op magische getallen
- Constanten en andere magische getallen moeten opmerkingen bevatten die uitleggen waarom ze de specifieke inhoud hebben. Waarom is de regellengte ingesteld op 80 karakters? Waarom is π ingesteld als 3,14?[27]
Code
Kleine patronen en het coderen in de praktijk.
- Software ontwerppatronen
- Er is veel werk gestoken in het identificeren van veelvoorkomende software ontwerppatronen en het ontwikkelen van goede algemene oplossingen voor die patronen. Als u vermoedt dat u iets probeert te doen dat een gemeenschappelijk patroon heeft, doe dan een zoekopdracht en bekijk hoe u het patroon kunt implementeren. Toch moet u weten dat patronen voor talen met closures heel anders kunnen zijn dan die zonder' closures. Meestal worden tabellen in Lua gebruikt om objecten te maken, maar ze kunnen ook als closures worden gemaakt.[28][29][30]
- Aanhalingstekens
- In Lua zijn er verschillende soorten aanhalingstekens. Kies er een en blijf erbij. Als u verschillende soorten quotes nodig heeft, gebruik dan uw typische aanhalingsteken op het buitenste niveau of op het meest binnen niveau en werk ze uit. Binnen en buiten met een enkele aanhalingsteken als primaire aanhalingsteken en dubbele aanhalingstekens als secundaire lijkt veel te zijn, maar kan gewoon toevallig zijn. Als er meer aanhalingstekens nodig zijn, moet u op het derde niveau met dubbele vierkante haken beginnen.[31][32]
- "Return" vroeg
- Doe de "return" zo snel mogelijk, vooral als er iets misgaat. Meestal wordt de programmeur verteld om bij een "return" te blijven, maar vanwege de taalconstructies in Lua lijkt dit een diep verneste code te creëren. Het is dus beter snel een "return" te doen.[33]
Example Good Bad … if done then return done end …
… if not done then … end … return done
- Eerst expressies die waar zijn
- Meestal bent u vrij om clausules in then en else te ordenen zoals u dat wil, en u moet de clausules zo ordenen dat de clausule if een positieve test heeft. Dit maakt de code makkelijker leesbaar. Als u de clausule else kunt vermijden, is dat wel belangrijker.[34]
Example Good Bad if a == b then … else … end
if a ~= b then … else … end
- Eerst vragen
- Meestal gaat de gevraagde waarde eerst in een logische expressie, omdat dit natuurlijker te lezen is en daardoor minder foutgevoelig is. De omgekeerde vorm wordt soms de 'Yoda-vorm' genoemd. Soms (maar zelden) werkt de natuurlijke vorm niet zoals verwacht, en eindigt de code. Dit kan komen doordat Lua er niet in slaagt een juiste tail-recursieve vorm van de expressie te vinden, waarna de stack overloopt.[35]
Example Good Bad if length > 10 then …
if 10 <= length then …
- Standaardwaarden geven
- In talen met een of een operator
orzoals in Lua is het heel gemakkelijk om in een standaard te voorzien. Dit is mooi, omdat sommige algemene constructies slecht werken als ze een niet-initiale waarde krijgen. Dit gebeurt bijvoorbeeld wanneer een tabel niet is geïnitieerd en de code probeert de nulwaarde te indexen.[36]
Example Good Bad … local t = arg or {} … t['foo']
… local t = arg … if t then t['foo'] else … end
- Binair conditioneel
- Lua heeft geen binaire conditionele operator (??), of "nullish coalescing operator", maar u kunt hetzelfde doen met een
oroperator. Wat er gebeurt is, hoewel het voor nieuwkomers in Lua een beetje mysterieus is. De logische operatorenandenorgeven truthy-waarden door (gematerialiseerde waarden), en kunnen dus deel uitmaken van andere expressies dan alleen logische.[37]
Example Good Bad local area = (length or 0) * (width or 0)
local area = 0 if length and width then area = length * width end
- Drie-waarden conditioneel
- Lua heeft geen conditionele operator (?ː), maar u kunt hetzelfde doen met een code>and en een
oroperator. Wat er gebeurt is een beetje mysterieus voor nieuwkomers in Lua. De logische operatoren code>and enoroverdragen de ware waarden (materialiseerde waarden), en daarom kunnen ze deel uitmaken van andere expressies dan alleen logische.[38]
Example Good Bad local height = pressure and millibarToMeters(length) or 0
local height = 0 if pressure then height = millibarToMeters(pressure) end
- Let op dat de vorm
a and b or cwaarbij b false is, c als resultaat zal geven. Dat is misschien niet het verwachte gedrag. - Vermijd repeat…until
- De loopconstructie
repeat…untilde test vertraagt tot na de loop. Dit is foutgevoelig en moet worden vermeden. Dit is alleen aanvaardbaar wanneer de test zelf duur is in vergelijking met het uitgevoerde blok, of het vermijden van de herhalingsclausule zou leiden tot extra opruimen of code afronden.[39] - Testargumenten
- Er is een kleine utility libraryUtil om de types van argumenten te testen, en die moet worden gebruikt om eenvoudige fouten te voorkomen. Vaak zijn de argumenten geldig wanneer andere code correct is, maar in randgevallen creëert iets een aanroep buiten het verwachte typebereik en loopt de code op een onverklaarbare manier stuk. Een goede test kan een fout vroegtijdig opvangen en de kans vergoten op het ontdekken van de ware oorzaak. Maat het testen van het type is een test op een fout, en geen test op goed.
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
Patronen
Een paar gewone software patronen.
- Commando patroon
- Het meest voorkomende softwarepatroon in Lua-modules, dat het vaakst ontbreekt, is het commando patroon. Sommige gegevens zijn beschikbaar en er moet op basis van deze gegevens een bepaalde actie worden gekozen. Een typische geur die een commandopatroon mist, zijn lange ketens van als-dan-anders-af-testen. De meest voorkomende variant heeft geen benoemde commando's, maar een accept-qualifier functie. Beide versies zijn zeer gebruikelijk bij het parsen van argumenten vanuit de "invoke"-parserfunctie.
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!)
Testbaarheid
Over testen en hoe te zorgen dat de code te testen is. Let op dat het originele boek van the gang of four softwarepatronen bevat voor sterk getypeerde talen, wat niet goed past bij een zwak getypeerde taal.[40] Of Lua sterk of zwak is typehandhaving heeft, is iets waar over gesproken kan worden.[41]
- Complexiteit
- Er zijn meestal meerdere uitvoerpaden door een bepaalde code, wat de code moeilijk te begrijpen maakt. Hoe meer paden, hoe moeilijker de code wordt. Dit kan worden gemeten als cyclomatische complexiteit, en is een telling van paden door vertakkingspunten te tellen. Dit geeft een eerlijke, maar niet erg goede maatstaf voor de codekwaliteit.[42]
- Globale waarden vermijden
- Functies met globale waarden zijn moeilijk te testen, ongeacht hoe ze in de code zijn opgenomen. Om dit per ongeluk te voorkomen kunnen "accidental trap" bibliotheken worden toegevoegd om de module soepel te maken. Houd er nog steeds rekening mee dat het vereisen van wat code is als het importeren van een globale waarde, dus wees voorzichtig dat u geen groter probleem binnen haalt. [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' )
- Veranderen van scope vermijden
- In Lua is het mogelijk om de scope van een functie te controleren. Doe dat niet, want de functie zal dan afhankelijk zijn van "mini-global", wat bijna net zo slecht is als globale waarden. Als alles werkt zoals het hoort, dan zijn de mini-globalen waarschijnlijk semi-constant, maar er is geen garantie.
Beveiliging
Lua loopt in een soort zandbak omgeving, men kan zeggen dat de Lua-code wordt uitgevoerd in een dmz aan de buitenkant van de gebruikelijke server, waar slechts een paar aanroepen door de bak gaan en die moeten goed worden gevalideerd door de interne code. In het algemeen zou er geen reden moeten zijn om speciale voorzorgsmaatregelen te nemen om de code veilig te maken, omdat het resultaat van de code-uitvoering door een goede controle en ontsnapping zal gaan voordat het op de pagina wordt opgenomen.
Zie ook
Programmeeromgeving
Enkele tips voor het opzetten van uw externe programmeringsomgeving.
Visual Studio Code
Gebruik iets als de volgende extensies.
- Lua
- vscode-luacheck
- Dit heeft een bestand
.luacheckrcnodig met één regelglobals = { 'mw' }, anders zal het gaan klagen over de globale variabelemw.
- Dit heeft een bestand
- Lua snippets for Wikimedia
Andere hulpmiddelen
Dit zijn hulpmiddelen die u misschien nuttig vindt.
Referenties
- ↑ LuaUsers: LuaLint
- ↑ GitHub: mpeterv/luacheck
- ↑ The Art of Readable Code p. 21,34,43.
- ↑ The Art of Readable Code pp. 8-11, Choose Specific Words.
- ↑ The Art of Readable Code pp. 18-19, How Long Should a Name Be?
- ↑ The Art of Readable Code p. 12, Loop iterators.
- ↑ The Art of Readable Code pp. 15-17, Attaching Extra Information to a Name.
- ↑ The Art of Readable Code pp. 19-20, Acronyms and Abbreviations.
- ↑ The Art of Readable Code pp. 20-21, Use Name Formatting to Convey Meaning.
- ↑ LuaUsers:LuaStyleGuide
- ↑ Programming in Lua: 1.3 – Some Lexical Conventions
- ↑ LuaUsers:LuaStyleGuide
- ↑ Programming in Lua: 1.3 – Some Lexical Conventions
- ↑ PEP-8: Maximum Line Length (This style guide use 79 chars.)
- ↑ PEP-8: Indentation
- ↑ PEP-8: Tabs or spaces
- ↑ PEP-8: Should a line break before or after a binary operator?
- ↑ PEP-8: Whitespace in Expressions and Statements
- ↑ The Art of Readable Code p. 56. The box has an alternate approach to what-why-how.
- ↑ The Art of Readable Code pp. 62-63, State the Intent of Your Code.
- ↑ Refactoring Guru: CodeSmells: Disposables: Comments
- ↑ The Art of Readable Code p. 49, Don’t Comment Bad Names—Fix the Names Instead.
- ↑ The Art of Readable Code p. 50, Comment the Flaws in Your Code.
- ↑ The Art of Readable Code p. 50, Comment the Flaws in Your Code.
- ↑ The Art of Readable Code p. 50, Comment the Flaws in Your Code.
- ↑ The Art of Readable Code p. 50, Comment the Flaws in Your Code.
- ↑ The Art of Readable Code p. 51, Comment on Your Constants.
- ↑ JavaScript Patterns. p. 2
- ↑ Programming in Lua: 6.1 – Closures
- ↑ LuaUsers: Minimising Closures
- ↑ PEP-8: String Quotes
- ↑ LuaUsers: StringsTutorial
- ↑ The Art of Readable Code pp. 75-79, Returning Early from a Function.
- ↑ The Art of Readable Code pp. 70-73, The Order of Arguments in Conditionals.
- ↑ The Art of Readable Code pp. 70-73, The Order of Arguments in Conditionals.
- ↑ Programming in Lua: 3.3 – Logical Operators
- ↑ LuaUsers: TernaryOperator (This is for ternary conditional, but the binary conditional is pretty similar.)
- ↑ LuaUsers: TernaryOperator
- ↑ The Art of Readable Code pp. 74-75, Avoid do/while Loops.
- ↑ JavaScript Patterns. p. 2
- ↑ Lua for Python Programmers: Types
- ↑ Quandary Peak Research: Measuring Software Maintainability
- ↑ C2Wiki: Global Variables Are Bad
- ↑ PlayControl Software: Using closures in Lua to avoid global variables for callbacks
- ↑ JavaScript Patterns, pp. 12-13
Leesvoer
- Kerievsky, Joshua; Refactoring to Patterns
- Boswell, Dustin; Foucher, Trevor; The Art of Readable Code
- Stefanov, Stoyan; JavaScript Patterns
- Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John; Design Patterns: Elements of Reusable Object-Oriented Software
- Programming in Lua (5.0)
- Lua 5.1 Reference Manual
- LuaUsers: Sample Code
- PEP 8 -- Style Guide for Python Code
- LuaUsers: Lua Style Guide
- The Power of Ten – Rules for Developing Safety Critical Code