diff --git a/.all-contributorsrc b/.all-contributorsrc index f53bc982..f7fbedf1 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -813,7 +813,8 @@ "avatar_url": "https://avatars3.githubusercontent.com/u/13496126?v=4", "profile": "https://github.com/collierrgbsitisfise", "contributions": [ - "content" + "content", + "translation" ] }, { @@ -1032,6 +1033,205 @@ "contributions": [ "translation" ] + }, + { + "login": "victor-homyakov", + "name": "Victor Homyakov", + "avatar_url": "https://avatars1.githubusercontent.com/u/121449?v=4", + "profile": "https://github.com/victor-homyakov", + "contributions": [ + "content" + ] + }, + { + "login": "josh-hemphill", + "name": "Josh", + "avatar_url": "https://avatars3.githubusercontent.com/u/46608115?v=4", + "profile": "http://joshuahemphill.com", + "contributions": [ + "content", + "security" + ] + }, + { + "login": "alec-francis", + "name": "Alec Francis", + "avatar_url": "https://avatars2.githubusercontent.com/u/32949882?v=4", + "profile": "https://github.com/alec-francis", + "contributions": [ + "content" + ] + }, + { + "login": "arjun6610", + "name": "arjun6610", + "avatar_url": "https://avatars1.githubusercontent.com/u/61268891?v=4", + "profile": "https://github.com/arjun6610", + "contributions": [ + "content" + ] + }, + { + "login": "jan-osch", + "name": "Jan Osch", + "avatar_url": "https://avatars2.githubusercontent.com/u/11651780?v=4", + "profile": "https://github.com/jan-osch", + "contributions": [ + "content" + ] + }, + { + "login": "thiagotrs", + "name": "Thiago Rotondo Sampaio", + "avatar_url": "https://avatars2.githubusercontent.com/u/32005779?v=4", + "profile": "https://github.com/thiagotrs", + "contributions": [ + "translation" + ] + }, + { + "login": "Alexsey", + "name": "Alexsey", + "avatar_url": "https://avatars0.githubusercontent.com/u/6392013?v=4", + "profile": "https://github.com/Alexsey", + "contributions": [ + "content" + ] + }, + { + "login": "13luismb", + "name": "Luis A. Acurero", + "avatar_url": "https://avatars1.githubusercontent.com/u/32210483?v=4", + "profile": "https://github.com/13luismb", + "contributions": [ + "translation" + ] + }, + { + "login": "lromano97", + "name": "Lucas Romano", + "avatar_url": "https://avatars1.githubusercontent.com/u/22394847?v=4", + "profile": "https://lromano97.github.io/", + "contributions": [ + "translation" + ] + }, + { + "login": "denisecase", + "name": "Denise Case", + "avatar_url": "https://avatars0.githubusercontent.com/u/13016516?v=4", + "profile": "https://github.com/denisecase", + "contributions": [ + "content" + ] + }, + { + "login": "elektronik2k5", + "name": "Nick Ribal", + "avatar_url": "https://avatars3.githubusercontent.com/u/1078554?v=4", + "profile": "http://stackoverflow.com/story/elektronik", + "contributions": [ + "content" + ] + }, + { + "login": "0xflotus", + "name": "0xflotus", + "avatar_url": "https://avatars3.githubusercontent.com/u/26602940?v=4", + "profile": "https://github.com/0xflotus", + "contributions": [ + "content" + ] + }, + { + "login": "dijonkitchen", + "name": "Jonathan Chen", + "avatar_url": "https://avatars3.githubusercontent.com/u/11434205?v=4", + "profile": "https://www.dijonkitchen.org/", + "contributions": [ + "content" + ] + }, + { + "login": "dilansri", + "name": "Dilan Srilal", + "avatar_url": "https://avatars2.githubusercontent.com/u/5089728?v=4", + "profile": "https://github.com/dilansri", + "contributions": [ + "content" + ] + }, + { + "login": "vladthelittleone", + "name": "vladthelittleone", + "avatar_url": "https://avatars3.githubusercontent.com/u/4215285?v=4", + "profile": "https://vectree.ru", + "contributions": [ + "translation" + ] + }, + { + "login": "nosvalds", + "name": "Nik Osvalds", + "avatar_url": "https://avatars0.githubusercontent.com/u/60047271?v=4", + "profile": "https://www.nikolaso.com", + "contributions": [ + "content" + ] + }, + { + "login": "kdaniel21", + "name": "Daniel Kiss", + "avatar_url": "https://avatars0.githubusercontent.com/u/39854385?v=4", + "profile": "https://github.com/kdaniel21", + "contributions": [ + "doc" + ] + }, + { + "login": "forresst", + "name": "Forresst", + "avatar_url": "https://avatars2.githubusercontent.com/u/163352?v=4", + "profile": "https://twitter.com/forresst17", + "contributions": [ + "content" + ] + }, + { + "login": "svenheden", + "name": "Jonathan Svenheden", + "avatar_url": "https://avatars1.githubusercontent.com/u/76098?v=4", + "profile": "https://github.com/svenheden", + "contributions": [ + "content" + ] + }, + { + "login": "AustrisC", + "name": "AustrisC", + "avatar_url": "https://avatars2.githubusercontent.com/u/12381652?v=4", + "profile": "https://github.com/AustrisC", + "contributions": [ + "content" + ] + }, + { + "login": "cisco0808", + "name": "kyeongtae kim", + "avatar_url": "https://avatars0.githubusercontent.com/u/60251188?v=4", + "profile": "https://github.com/cisco0808", + "contributions": [ + "translation" + ] + }, + { + "login": "6gx7iycn53ioq2e8apk1j1ypwov4giui", + "name": "007", + "avatar_url": "https://avatars.githubusercontent.com/u/65741741?v=4", + "profile": "https://keybase.io/651z9pz968v2accj", + "contributions": [ + "content" + ] } ], "projectName": "nodebestpractices", diff --git a/.operations/.common-answers.md b/.operations/.common-answers.md index 9484e951..184e8f16 100644 --- a/.operations/.common-answers.md +++ b/.operations/.common-answers.md @@ -1,15 +1,17 @@ **Welcoming new translators** -@name - Welcome aboard 🎆 +@name - Welcome aboard, it's great to have you here 🎆 -Having an Egyptian translation could be awesome +Having A Slovak translation could be awesome! At the end, we can Tweet about this, put in our news section, include your name at the top of the translated language and also at the main home page contributors list Let's go for this? Few basic guideliness: -1. Work on your own fork - fork, create a branch, translate & collaborate with other translators, then PR finally -2. Focus on translation, not content editing - the focus is on translation, should anyone want to modify the content or the graphics - let's PR first in English and then translate to other languages. Also the format of the text should remain intact (same design) -3. Duplicate the readme and the inner pages - the content should be translated over a page duplication. Readme.MD became Readme.{translated-language}.MD (e.g. readme.french.md), all other files should be duplicated similarly. So the number of English & translated pages should be the same -4. Collaborate - once you do the basic setup (branch, duplicate pages), we can announce the work on a new language and get others involved and help you in translation (if you wish) -5. We're here to help - let us know whether we can do anything to support you. We can Tweet about this work, put homepage banner or anything else +- Work on your own fork - Fork this repo, create a branch for yourself, translate & collaborate with other translators, then finally when ready create a PR -____________________ +- Focus on translation, not content editing - The focus is on translation, should you want to modify the content or the graphics - let's PR first in English and then translate to other languages. Also the format of the text should remain intact (same design) + +- Duplicate the readme and the inner pages - Tthe content should be translated over a page duplication. Readme.MD became Readme.{translated-language}.MD (e.g. readme.french.md), all other files should be duplicated similarly. So the number of English & translated pages should be the same. You may see examples in currently translated languages + +Collaborate - once you do the basic setup (branch, duplicate pages), we can announce the work on a new language and get others involved and help you in translation (if you wish) + +We're here to help - let us know whether we can do anything to support you. We can Tweet about this work, put homepage banner or anything else diff --git a/.operations/writing-guidelines.basque.md b/.operations/writing-guidelines.basque.md new file mode 100644 index 00000000..97a36b0f --- /dev/null +++ b/.operations/writing-guidelines.basque.md @@ -0,0 +1,31 @@ +# Gure agiria edukia hobeto idazteko + +Nola hobetu gure bisitarien irakurtzeko eta ikasteko esperientzia + +## 1. Sinplea ezin hobea da + +Gure helburua da irakurketa eta ezagutzaren xurgaketa erraztea: edukia zaintzen dugu. Horrenbestez, saiatzen gara gai konplexu eta nekagarriak zerrenda erraztu bihurtzen, informazio astuna zati txikiagoetan eta zehaztasun gutxiagokoetan eratzen dugu, gai eztabaidagarri eta 'sukoiak' eta ekiditen ditugu, ideia subjektiboak sahiestuz eta orokorrean onartutako jarraibideak erabiliz + +## 2. Oinarritu egitate frogatu eta fidagarrietan + +Gure irakurleek konfidantza handia izan behar dute irakurtzen duten informazioa fidagarria dela. Hori lortzeko, erreferentziak, datuak eta gaiarekin zerikusirik duten bestelako ebidentziak erabiltzen ditugu. Praktikan, gure baieztapenak frogatzeko, ahalegintzen gara iturburu fidagarrietako aipuak aurkezten eta konparaketak, erlazionatutako diseinu ereduak edo neurketa zientifikoak azaltzen + +## 3. EEKS (Elkarrekiko Esklusiboa eta Kolektiboki Sakona) + +Edukia ondo editatua eta fidagarria izateaz gain, haren irakurketak gaiaz bere osoan jabetzea bermatu behar du. Garrantzi gabeko azpigaiak batertuak izan behar dira + +## 4. Formatu koherentea + +Edukia txantiloi finkoak erabiliz dago aurkeztua, eta etorkizuneko beste edozein edukik txantiloi bera errespetatu behar du. Eduki berriak gehitu nahi izanez gero, kopiatu buleta formatua iada existitzen den bulet batetik eta moldatu zure beharretara. Informazio gehiago nahi izanez gero begiratu [txantiloi hau](../sections/template.basque.md) + +## 5. Node.jsi buruz ari gara + +Aholku bakoitzak zuzenean Node.jsekin erlazionatuta egon behar du, eta ez orokorrean software garapenarekin. Node.jsen eredu/arau generikoak ezartzea aholkatzen dugunean, edukiak Noderen ezarpenean ardaztuta egon behar da. Adibidez, eskaera sarrera guztiak onbideratzea aholkatzen dugunean, segurtasun arrazoiengatik, Node-lingo erabili behar da, ‘erabili middlewarea eskaera sarrera onbideratzeko‘. Gai batek Node.jsen ezarpenik ez badauka (esaterako Python & Jaban bezala), gehitu edukiontzi generiko batean, begiratu 6.5 gaia adibidetzat + +## 6. Hornitzaile nagusiak soilik + +Batzuetan, npm paketeak, open source tresnak edota produktu komertzialak bezalako zenbait erronka eta arazo abordatzen dituzten hornitzaileen izenak gehitzea erabilgarria da. Gainezka egiten duten zerrenda luzeak edota ospetsuak eta egonkorrak ez diren proiektuak ekiditeko, hurrengo arauak proposatzen ditugu: + +- Soilik 3 hornitzaile ezagunenak gomendatu behar dira: hitz gako batentzat bilaketa motore bateko (Google edo Github ospearen arabera ordenatua) lehenengo 3 emaitzetan agertzen den hornitzaile bat aipatu genezake gure gomendioetan +- npm pakete bat bada, batazbeste egunean, gutxienez, 750 aldiz deskargatua izan behar da +- Kode irekiko proiektu bat bada, azken 6 hilabeteetan gutxienez behin eguneratua izan behar da diff --git a/README.basque.md b/README.basque.md new file mode 100644 index 00000000..fb7ab29f --- /dev/null +++ b/README.basque.md @@ -0,0 +1,1559 @@ +[✔]: assets/images/checkbox-small-blue.png + +# Node.js-ren jardunbide egokiak + +

+ Node.js-ren jardunbide egokiak +

+ +
+ +
+ 102 items Azken eguneratzea: 2020ko azaroa Node 14.0.0rako eguneratua +
+ +
+ +[![nodepractices](/assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Hemen ere bagaude!** [**@nodepractices**](https://twitter.com/nodepractices/) + +
+ +Irakurri beste hizkuntza batzuetan: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), [![BR](/assets/flags/BR.png)**BR**](/README.brazilian-portuguese.md), [![RU](/assets/flags/RU.png)**RU**](/README.russian.md), [![PL](/assets/flags/PL.png)**PL**](/README.polish.md) [(![ES](/assets/flags/ES.png)**ES**, ![FR](/assets/flags/FR.png)**FR**, ![HE](/assets/flags/HE.png)**HE**, ![KR](/assets/flags/KR.png)**KR** eta ![TR](/assets/flags/TR.png)**TR** aribidean!)](#translations) + +
+ +###### Gure [Zuzendaritza Batzordeak ](#zuzendaritza-batzordea) eta [laguntzaileek](#Languntzaileak) eraiki eta mantentzen dute webgune hau + +# Azken jardunbide egokiak eta albisteak + +- **✅ Jardunbide egoki berria:** [Alexsey](https://github.com/Alexsey)-ren 2.12 bulletak erakusten du funtzio asinkronikoen zain egon gabe itzultzeak pila aztarna partzialak uzten dituela. Hor arazo handia izan liteke salbuespenek eragindako arazoak konpontzean exekuzio fotogrametako batzuk ez dituzten produkzioetan + +- **✅ Jardunbide egoki berria:** Josh Hemphill-en 6.8 bulletak "Erabiltzaileen pasahitzak / sekretuak BCrypt edo Script erabiliz" babestea gomendatzen du. Azalpen sakona ematen du aukera bakoitza proiektu zehatz batera noiz eta zergatik egokitzen den jakiteko. Ez galdu gida labur hau hash-en aukeren azalpen labur bat eskaintzen duena + +- **:whale: Node.js + Docker-en jardunbide egokiak:** Atal berri bat argitaratu berri dugu, 15 jardunbide egoki jasotze + dituena Dockerrekin erabili beharreko kodetze teknikei buruzkoak + +

+ +# Ongi etorri! Hasi aurretik jakin beharreko 3 gauza + +**1. Hemen dozenaka artikulu dauzkazu, onenetarikoak Node.jsri buruz egindakoetan:** alegia, bilduma honek Node.jsren jardunbide egokienak jasotzen ditu, edukien arabera sailkatuta + +**2. Dagoen bildumarik handiena da, eta astetik astera handiagoa da:** une honetan 80tik gora jardunbide, estilo eskuliburu eta arkitektura aholku dauzkagu bilduta. Gustura asko jasoko genituzte zure ekarpenak bilduma hau eguneratuta edukitzeko, bai kode akatsak konponduz, bai itzulpenak eginez, bai ideia berriak proposatuz egin ditzakezunak: izan zaitez Node.jsren jardunbide egokienen liburuko partaide. Ikusi gure [idazketa jarraibideak](/.operations/writing-guidelines.basque.md) + +**3. Jarraibide gehienek informazio gehigarria dute.** Jarraibideko puntu bakoitzaren ondoan **🔗Informazio gehiago** esteka aurkituko duzu, jarraibidea osatzen duena kode adibideekin, blogetako aipu hautatuekin eta informazio osagarri gehiagorekin + +

+ +## Edukien aurkibidea + +1. [Proiektuaren egitura (5)](#1-proiektuaren-egitura) +2. [Erroreen kudeaketa (11) ](#2-erroreen-kudeaketa) +3. [Kode estiloa (12) ](#3-kode-estiloa) +4. [Probak eta kalitate orokorra (13) ](#4-probak-eta-kalitate-orokorra) +5. [Ekoizpena (19) ](#5-ekoizpena) +6. [Segurtasuna (25)](#6-segurtasuna) +7. [Errendimendua (2) (Aribidean ✍️)](#7-zirriborroa-errendimendua) +8. [Docker (15)](#8-docker) + +

+ +# `1. Proiektuaren egitura` + +## ![✔] 1.1 Antolatu zure proiektua atal eta osagai txikiagotan + +**TL;PL:** aplikazio handien oztoporik handiena kode base erraldoi bat mantendu beharra da, ehundaka lotura eta menpekotasun dituena. Horrelako lan monolitikoek programatzaileen lana motelarazten dute, funtzionalitate berriak gehitzen saiatzen dira eta. Hori gerta ez dadin, zatitu zure kodea osagai txikiagotan, bakoitza bere datuekin karpeta banatan, eta bermatu osagai bakoitza laburra eta sinplea izatea. Bisitatu hemen behean dagoen “Informazio gehiago” esteka, proiektu egoki baten egitura zuzenaren adibideak ikusteko + +**Bestela:** Bestela: funtzionalitate berriak programatzean, garatzaileek zailtasun handiak izaten dituzte aldaketa horien eragina antzemateko, eta beldur izaten dira funtzionalitateon menpeko osagaiak hautsiko ote dituzten. Ondorioz, inplementazioak motelagoak eta arriskutsuagoak izaten dira. Oro har, zailagoa izaten da aplikazio baten kodea luzatzea negozio unitateak banatuta ez daudenean + +🔗 [**Informazio gehiago: antolatu zure proiektua osagai txikiagotan**](/sections/projectstructre/breakintcomponents.basque.md) + +

+ +## ![✔] 1.2 Antolatu zure aplikazioa geruzatan eta mantendu webaren geruza bere esparruaren barruan + +**TL;PL:** osagai bakoitzak «geruzak» izan beharko lituzke: hau da, berariaz weberako egindako objektu bat; beste bat, logikarako; eta beste bat, datuen sarbidearen koderako. Horrek, zati bakoitzaren funtzioak ondo bereizteko aukera eskaintzeaz gainera, sistema errazago simulatu eta testatzea ahalbidetzen du. Modelo hau oso ohikoa bada ere, APIen garatzaileek joera izaten dute geruzak nahasteko, webeko objektu espezifikoa (Express req, res) logika operatiboaren eta datuen geruzetara pasatuz, eta, ondorioz bai aplikazioa bai sarbidea Expressen menpeko bihurtzen dira + +**Bestela:** aplikazio batean webeko objektuak beste geruzekin nahastuta badaude, ezingo da bertara sartu testak, CRON atazak eta Express middleware-ak baino erabiliz + +🔗 [**Informazio gehiago: antolatu zure aplikazioa geruzatan**](/sections/projectstructre/createlayers.basque.md) + +

+ +## ![✔] 1.3 Kokatu baliabide komunak NPM paketetan + +**TL;PL:** data base askok osatzen duten aplikazio handi bat prestatzen dugunean, geruza guztietan lan egiten duten zeharkako tresna bakoitzak –erregistragailuak, zifragailuak eta beste– bere kodearen barruan egon behar du, NPM pakete pribatu moduan, tresna horiek hainbat proiektutan partekatu ahal izatea ahalbidetzen duena + +**Bestela:** zuk zeuk asmatu beharko duzu zeure inplementazioa eta menpekotasun gurpila + +🔗 [**Informazio gehiago: antolatu funtzioen arabera**](/sections/projectstructre/wraputilities.basque.md) + +

+ +## ![✔] 1.4 Banandu Express 'aplikazioa' eta 'zerbitzaria' + +**TL;PL:** ekidin [Express](https://expressjs.com/) aplikazioa artxibo handi batean oso-osorik definitzeko ohitura desegokia. Banandu Express aplikazioaren definizioa bi artxibotan gutxienez: batetik, APIaren definizioa (app.js); eta, bestetik, sarearen ezaugarriak (WWW). Are gehiago, egitura egokiagoa izan dadin, jarri APIaren definizioa osagaiekin batera + +**Bestela:** probak egiteko, HTTP deien bidez baino ezingo da zure APIra sartu. Sarbide hori motelagoa da eta asko zailtzen du estaldura txostenak egitea. Gainera, ziur aski, ez da bat ere atsegina izango ehundaka lerro dituen kodea mantentzea + +🔗 [**Informazio gehiago: banandu Express 'aplikazioa' eta 'zerbitzaria'**](/sections/projectstructre/separateexpress.basque.md) + +

+ +## ![✔] 1.5 Erabili ingurunea errespetatzen duen konfigurazio seguru eta hierarkiko bat + +**TL;PL:** akatsik gabeko konfigurazio perfektu batek bermatu behar du (a) giltzak fitxategietatik eta inguruneko aldagaietatik irakurri ahal izatea, (b) sekretuak iturri kodetik kanpo gordeta egotea, eta, (c), bilaketak errazte aldera, konfigurazioa hierarkikoa izatea. Hori dena lortzeko badira paketeak, hala nola, rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) eta [convict](https://www.npmjs.com/package/convict). + +**Bestela:** konfiguazioa egitean baldintza horietarikoren bat betetzen ez baduzu, lana moteldu egingo da, bai garapen taldearena, bai devops taldearena + +🔗 [**Informazio gehiago: konfigurazio jardunbide egokiak**](/sections/projectstructre/configguide.basque.md) + +


+ +

⬆ Itzuli hasierara

+ +# `2. Erroreen kudeaketa` + +## ![✔] 2.1 Erabili Async-Await edo errore asinkronoak kudeatzeko promesak + +**TL;PL:** errore asinkronoak callback erabiliz kudeatzen badituzu, infernurako biderik azkarrena hartuko duzu edo galbiderako piramidean sartuko zara. Zure kodeari opari on bat egin nahi badiozu, erabili agintzen biblioteka ezagun bat edo async-await, try-catch erakoa adibidez kode sintaxis askoz trinkoago eta ohikoago bat eskaintzen duena + +**Bestela:** Node.js-en callback teknika (“err, response” prozedura) erabiltzen baduzu, kode ez jasangarriak sortuko dituzu, batera suertatuko baitira kode arrunta duten erroreen kudeaketa, habiaratze sarriegiak eta kodetze eredu ez erosoak + +🔗 [**Informazio gehiago: ekidin callback prozedurak**](/sections/errorhandling/asyncerrorhandling.basque.md) + +

+ +## ![✔] 2.2 Erabili soilik “Errorea” objektu kapsulatua + +**TL;PL:** maiz, erroreak kate gisa edo modu pertsonalizatuan agertzen dira, erroreak kudeatzeko logika zaildu eta moduluen arteko elkarreragingarritasuna oztopatzen duena. Agintza bat baztertu zein salbuespen bat ezarri edo errore ohar bat argitaratzen duzunean, soilik “Errorea” objektu kapsulatua –edo “Errore txertatua“ objektua zabaltzen duen objektua– erabiliz lortuko duzu bermatzea bateratasuna handitu eta informazioa ez galtzea + +**Bestela:** osagairen bati deitzean erroreak zein motatakoak diren jakin gabe, askoz zailagoa da eurak kontrolatzea. Are okerrago, erroreak deskribatzeko modu pertsonalizatuak erabiltzeak errore kritikoen informazioa galtzea ekar dezake, pilaren aztarna, besteak beste + +🔗 [**Informazio gehiago: erabili soilik “Errorea” objektu kapsulatua**](/sections/errorhandling/useonlythebuiltinerror.basque.md) + +

+ +## ![✔] 2.3 Bereizi eragiketa erroreak eta programatze erroreak + +**TL; DR:** errore operazionalek (adibidez, APIak balio gabeko sarrera jasotzea) agerian jartzen dituzten arazoak ezagunak izaten dira, eta, haien eragina guztiz ulertu eta kontuz kudeatzeko modukoak izaten dira. Bestetik, programatzaileen erroreak (adibidez, zehaztu gabeko aldagaia irakurtzen saiatzea) aplikazioa berrabiarazteko agindua ematen duten kode hutsegite ezezagunak izaten dira + +**Bestela:** eti berrabiaraz dezakezu aplikazioa errore bat agertzen denean. Baina zergatik utzi 5.000 erabiltzaile offline iragarri daitekeen errore funtzional txiki batengatik? Kontrakoa ere ez da egokia: arazo ezezagun bat gertatzen denean -programatzailearen errore bat, esaterako- aplikazioa martxan mantentzeak ezusteko jokaerak eragin ditzake. Biak bereizteak aukera ematen du kontuz jokatzeko eta ikuspegi orekatu bat aplikatzeko testuinguruan oinarrituz + +🔗 [**Informazio gehiago: eragiketa erroreak vs programazio erroreak**](/sections/errorhandling/operationalvsprogrammererror.basque.md) + +

+ +## ![✔] 2.4 Kudeatu erroreak gune bakar batean, Express middleware erabili partez + +**TL;PL:** erroreak kudeatzeko logika -hala nola, haien erregistroa eramatea eta administratzaileari mezuak bidaltzea- objektu dedikatu zentralizatu batean kapsulatu behar da, erroreren bat gertatzen denean helmuga guztiek (adibidez, Express middleware, cron atazak, atalkako egiaztatzeak) hara deitu dezaten + +**Bestela:** erroreak toki bakarrean ez kudeatzeak kodea bikoiztea eragiten du eta, ziur aski, erroreak gaizki kudeatzea ere bai + +🔗 [**Informazio gehiago: kudeatu erroreak gune bakar batean**](/sections/errorhandling/centralizedhandling.basque.md) + +

+ +## ![✔] 2.5 Dokumentatu aplikazioaren erroreak Swagger edo GraphQL-ren laguntzarekin + +**TL;PL:** jakinaren gainean jarri aplikazioaren deitzaileak erroreak berriro gerta daitezkeela, errore horiek behar bezala konpondu ahal izateko hutsik egin gabe. RESTful aplikazioetan Swagger bezalako dokumentazio esparruak erabiltzen dira. GraphQL erabiltzen baduzu, zeure eskema eta azalpenak erabil ditzakezu + +**Bestela:** aplikazio baten bezeroak erabaki dezake aplikazioa itxi eta berrabiaraztea, ulertzen ez duen errore baten abisua jaso duelako soil-soilik. Oharra: zu zeu izan zaitezke zure aplikaziotik deitzen duena (oso ohikoa mikrozerbitzu inguruneetan) + +🔗 [**Informazio gehiago: dokumentatu aplikazioaren akatsak Swagger edo GraphQLren laguntzarekin**](/sections/errorhandling/documentingusingswagger.basque.md) + +

+ +## ![✔] 2.6 Irten prozesutik elegantziarekin kanpoko norbait iristen denean hirira + +**TL;PL:** errore ezezagun bat gertatzen denean (programazio errore bat, ikusi 2.3 jardunbide egokia), zalantza izaten da era egokian lanean ote dabilen aplikazioa. Kasu horietan, oso ohikoa izaten da prozesuak kudeatzeko tresna bat erabiltzea [Forever](https://www.npmjs.com/package/forever), [PM2](http://pm2.keymetrics.io/) edo antzekoren bat– prozesua berriro hasteko + +**Bestela:** ezagutzen ez duzun zerbait gertatzen denean, izan daiteke objekturen batzuk egoera txarrean daudelako (esaterako, globalki erabiltzen den gertaera igorle bat, barneko erroreren batengatik ondo ez dabilena) eta gerta daiteke aurrerantzean abisuek huts egitea edo modu ero samarrean funtzionatzea + +🔗 [**Informazio gehiago: gelditu prozesua**](/sections/errorhandling/shuttingtheprocess.basque.md) + +

+ +## ![✔] 2.7 Erabili erregistratze tresna helduak erroreen ikusgaitasuna handitzeko + +**TL;PL:** erregistratze tresna helduen sortak erabiltzen badituzu –[Pino](https://github.com/pinojs/pino) edo [Log4js](https://www.npmjs.com/package/log4js), adibidez–, erroreak lehenago antzeman eta ulertuko dituzu. Beraz, utzi alde batera console.log + +**Bestela:** console.log-ak arakatu behar badituzu edo testua desordenatua duen artxibo batean erroreak eskuz, kontsulta tresnarik gabe edo erregistratze bisore ganorazkorik gabe bilatu behar badituzu, ordu asko emango dituzu lanean gaueko ordu txikiak arte + +🔗 [**Informazio gehiago: erabili erregistratze tresna helduak**](/sections/errorhandling/usematurelogger.basque.md) + +

+ +## ![✔] 2.8 Testeatu erroreen fluxua zure test framework gustukoena erabiliz + +**TL;PL:** kalitate profesionaleko kontrol tresna automatizatu bat izan zein programatzaileentzako eskuzko test soil bat izan, bermatu zure kodeak ez duela egoera positiboetan bakarrik lan egiten, baizik eta errore zuzenak ere kudeatu eta birbidaltzen dituela. Mocha & Chai bezalako unitate test frameworkek erraz egin dezakete lan hori (ikusi “Gist leiho”ko kode adibideak) + +**Bestela:** automatikoki zein eskuz probarik egin gabe ezin duzu konfiantzarik izan zure kodeak benetako erroreak antzemango dituen. Errore adierazgarririk gabe ez dago erroreak kudeatzerik + +🔗 [**Informazio gehiago: testeatu erroreen fluxua**](/sections/errorhandling/testingerrorflows.basque.md) + +

+ +## ![✔] 2.9 Aurkitu erroreak eta jardunik gabeko uneak APM produktuak erabiliz + +**TL;PL:** monitorizazio eta errendimendu produktuek (APM, ingelesezko siglen arabera) modu proaktiboan ebaluatzen dute zure kode basea edo aplikazioa automatikoki aurkitu ahal izan ditzaten erroreak, blokeoak eta atzeman ezin dituzun eraginkortasun txikiko atalak + +**Bestela:** denbora asko pasa zenezake zure aplikazioaren errendimendua eta jardunik gabeko uneak neurtzen, eta, hala ere, ez zenuke aurkituko zeintzuk diren zure kodearen zatirik motelenak egoera errealetan eta ez zenuke inoiz jakingo nola eragiten dioten erabiltzailearen lanari + +🔗 [**Informazio gehiago: APM produktuen erabilera**](/sections/errorhandling/apmproducts.basque.md) + +

+ +## ![✔] 2.10 Atzeman kudeatu gabeko agintzen arbuioak + +**TL;PL:** agintza baten barruan dauden salbuespenak xurgatuak eta baztertuak izango dira programatzaileak modu esplizituan kudeatzen ez baditu, haren kodea `process.uncaughtException`-ari atxikia egonda ere. Ekidin hori `process.unhandledRejection` erabiliz + +**Bestela:** zure erroreak xurgatuak izango dira eta ez da haien arrastorik geratuko. Ez duzu zertaz kezkatu + +🔗 [**Informazio gehiago: atzeman kudeatu gabeko aginduen arbuioak**](/sections/errorhandling/catchunhandledpromiserejection.basque.md) + +

+ +## ![✔] 2.11 Huts egin azkar, balidatu argudioak liburutegi dedikatu baten laguntzarekin + +**TL;PL:** Express erabiltzen duzunean, zure jardunbide egokietako bat izan beharko litzateke aplikazioaren sarbidea kontrolatzea, ustegabeko erroreak ekiditeko, aurrerago erroreak atzematea askoz zailagoa izaten da eta. Balidazio kodea gogaikarria izan ohi da, [ajv](https://www.npmjs.com/package/ajv) eta [Joi](https://www.npmjs.com/package/joi) bezalako laguntza liburutegi moderno bat erabili ezean + +**Bestela:** pentsatu zure funtzioa agintza numeriko baten zain dagoela, adibidez «deskontua», eskatzaileak bidaltzea ahaztu duena; geroago, haren kodeak baieztatzen du « deskontua! = 0 (baimendutako deskontua zero baino handiagoa da)», eta horrek ahalmena ematen dio erabiltzaileari deskontua izateko. Ene, nolako errore arriskutsua! Konturatzen zara? + +🔗 [**Informazio gehiago: huts egin azkar**](/sections/errorhandling/failfast.basque.md) + +


+ +

⬆ Itzuli hasierara

+ +## ![✔] 2.12 Agintzen zain egon beti itzuli aurretik, pilak arrastorik uztea saihesteko + +**TL; DR:** beti egin `return await` promesa bat itzultzean, pila osoaren jarraipena egin ahal izateko. Funtzio batek promesa bat itzultzen badu, funtzio hori `async`, hau da, asinkronotzat jo behar da, eta esplizituki `await`, itxaron agintza, itzuli aurretik + +**Bestela:** itxaron gabe agintza itzultzen duen funtzioa ez da pilaren arrastoan agertuko. Galdutako fotograma horiek akatsa eragingo duen fluxua ulertzea zailduko lukete, batez ere portaera anormalaren zergatia falta den funtzioaren barruan baldin badago + +🔗 [**Gehiago irakurri: agintzak itzultzea**](/sections/errorhandling/returningpromises.basque.md) + +


+ +

⬆ Itzuli hasierara

+ +# `3. Kode estiloa` + +## ![✔] 3.1 Erabili ESLint + +**TL;PL:** [ESLint](https://eslint.org) da gerta daitezkeen kode erroreak egiaztatzeko eta kodearen estiloa zuzentzeko estandarra. Ez da soilik erabiltzen tarteen arazoak identifikatzeko, baizik eta kodearen antipatroi kritikoak atzemateko ere, hala nola garatzaileen errore ez-sailkatuak. ESLint kode estiloak automatikoki zuzentzeko gai bada ere, badira beste tresna batzuk eraginkorragoak direnak zuzenketak egiten –esaterako, [prettier](https://www.npmjs.com/package/prettier) eta [beautify](https://www.npmjs.com/package/js-beautify)– eta, gainera, ESLintekin batera egiten dute lan + +**Bestela:** garatzaileek arreta jarriko dute hain gogaikarriak diren arazo batzuk konpontzen –kodearen tarteak eta lerroaren luzera–, eta denbora gehiegi gal dezakete proiektuaren kode estiloa aztertzen + +🔗 [**Informazio gehiago: erabili ESLint eta Prettier**](/sections/codestylepractices/eslint_prettier.basque.md) + +

+ +## ![✔] 3.2 Node.jsentzako plugin espezifikoak + +**TL;PL:** ESLintek JavaScript vainilla babesteko dituen arau estandarretatik aparte, komeni da Node.jsen osagai espeziko batzuk erabiltzea, hala nola [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) eta [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security) + +**Bestela:** Node.jsen arau akastun batzuek radarraren kontrolari ihes egin ahal diote. Esaterako, garatzaileek sarbide moduan aldagai jakin baten beharra izan dezakete (require(variableCommeChemin)), edozein script JS erabiltzeko aukera ematen diena erasotzaileei. Node.jsen lintersek patroi horiek antzeman ditzakete eta garaiz jo alarma + +

+ +## ![✔] 3.3 Jarri kode multzo baten giltzak lerro bakar batean + +**TL;PL:** kode bloke baten hasierako parentesiak irekiera instrukzioaren lerroan egon behar du + +### Kodearen adibidea + +```javascript +// Egin +function edozeinFuntzio() { + // kode blokea +} + +// Baztertu +function edozeinFuntzio() { + // kode blokea +} +``` + +**Bestela:** jardunbide egoki hau ez erabiltzeak ustekabeko emaitzak eragin ditzake, behean dagoen StackOverflow-en eztabaida harian ikus daitekeen bezala: + +🔗 [**Informazio gehiago:** “Zergatik aldatzen dira emaitzak giltzen kokapenaren arabera?” (StackOverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement) + +

+ +## ![✔] 3.4 Bereizi instrukzioak modu egokian + +Ez dio axola instrukzioak bereizteko puntu eta koma erabiltzen duzun edo ez, ohiko lerro jauzi okerrak edo koma txertatze automatikoak ezagutzeak lagundu egingo dizu ohiko errore sintaktikoak ez egiten + +**TL;PL:** erabili ESLint bereizketetan izaten diren erroreez jabetzeko. [Prettier](https://prettier.io/) edo [Standardjs](https://standardjs.com/) erabiliz automatikoki konpon ditzakezu arazo horiek + +**Bestela:** aurreko atalean esan bezala, JavaScripteko interpreteak automatikoki “puntu eta koma” gehitzen du instrukzio baten amaieran “punto eta koma”rik ez badago edo instrukzioa behar den tokian ez dela amaitu eta horrek okerreko emaitzak eragin ditzakeela pentsatzen badu. Ustekabeko errore gehienak ekiditeko, esleipenak erabil ditzakezu eta, horrela, berehala deitutako funtzio adierazpenak erabiltzea saihestuko duzu + +### Kodearen adibidea + +```javascript +// Egin +function eginZerbait() { + // ... +} + +eginZerbait() + +// Egin + +const items = [1, 2, 3] +items.forEach(console.log) + +// Baztertu — exception bat jaurtitzen du +const m = new Map() +const a = [1,2,3] +[...m.values()].forEach(console.log) +> [...m.values()].forEach(console.log) +> ^^^ +> SyntaxError: Unexpected token ... + +// egin zerbait — exception bat jaurtitzen du +const count = 2 // 2() burutzen saiatzen da, baina 2() ez da funtzio bat +(function egin zerbait() { + // egin zerbait paregabea +}()) +// jarri puntu eta koma berehala deitutako funtzioa baino lehen, const definizioaren ostean, funtzio anonimoak bueltatutako balioa aldagarri batean gorde edo baztertu IIFE guztiak +``` + +🔗 [**Informazio gehiago:** "Semi ESLint araua"](https://eslint.org/docs/rules/semi) +🔗 [**Informazio gehiago:** "stekabeko ESLint arau lerroaniztunik ez"](https://eslint.org/docs/rules/no-unexpected-multiline) + +

+ +## ![✔] 3.5 Izendatu funtzio guztiak + +**TL;PL:** izendatu funtzio guztiak, itxierak eta deiak. Saihestu funtzio anonimoak. Hau bereziki erabilgarria da nodo aplikazio bat profilatzerakoan. Funtzio guztiak izendatzeak memoria argazkia egiaztatzean aukera emango dizu zer bilatzen ari zaren ulertzen + +**Bestela:** zaila izan liteke produkzio arazoak araztea memoria erregistroak erabiliz (memoria argazkia), funtzio anonimoetako memoria kontsumoa handia denean + +

+ +## ![✔] 3.6 Erabili izen deskriptiboak aldagaiak, konstanteak, funtzioak eta klaseak izendatzeko + +**TL;PL:** Erabili **_lowerCamelCase_** konstanteak, aldagaiak eta funtzioak izendatzean eta **_UpperCamelCase_** (maiuskulazko lehen letra ere) klaseak izendatzean. Horrek lagunduko dizu aldagai/funtzio arruntak eta instantziazioa behar duten klaseak erraz bereizten. Erabili izen deskriptiboak, baina saiatu laburrak izan daitezen + +**Bestela:** Javascript munduko hizkuntza bakarra da eraikitzailea ("Klasea") zuzenean deitzea ahalbidetzen duena aurretik eskatu/instantziatu gabe. Horrenbestez, klaseak eta funtzio eraikitzaileak bereizten dira UpperCamelCase-tik hasita + +### 3.6 Kode eredua + +```javascript +// funtzioa izendatzeko UpperCamelCase erabiltzen dugu +class KlaseBatenAdibidea {} + +// konstanteak izendatzeko const hitz gakoa eta lowerCamelCase erabiltzen ditugu +const config = { + key: "balioa", +}; + +// aldagaiak eta funtzioak izendatzeko lowerCamelCase erabiltzen dugu +let aldagaiBatenAdibidea = "balioa"; +function eginZerbait() {} +``` + +

+ +## ![✔] 3.7 Aukeratu const, let ordez. Ez erabili var + +**TL;PL:** `const` erabiltzeak esan nahi du behin aldagai bat esleituta ezin dela berriro esleitu. Beraz, erabilera desberdinetarako aldagai bakarra erabiltzeko joera baztertzen lagunduko dizu `const` erabiltzeak, bai eta kodea garbitzen ere. Aldagai bat behin baino gehiagotan esleitu behar baduzu –for begizta batean, adibidez– erabili `let`, garbiagoa da eta. Leten beste alderdi garrantzitsu bat da definitu duzun blokearen eremuan bakarrik eskura dezakezula deklaratutako aldagia. `var` funtzioen eremukoa da, ez blokearena, eta [ez da ES6n erabili behar](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70), `const` eta `let` erabiltzeko aukera duzu eta + +**Bestela:** arazketa askoz ere astunagoa da, maiz aldatzen den aldagai baten jarraipena egitean + +🔗 [**Gehiago irakurri: JavaScript ES6 +: var, let, edo const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75) + +

+ +## ![✔] 3.8 Erabili moduluak lehenengo, barne funtzioen partez + +**TL;PL:** moduluak fitxategi bakoitzaren hasieran erabili behar dira, edozein funtzioren aurretik eta kanpo. Jardunbide on eta sinple honek lagunduko dizu fitxategiaren menpekotasunak erraz eta azkar antzematen haren eskuineko goi aldean, baita arazo posible batzuk ekiditen ere + +**Bestela:** Node.js.k aldi berean exekutatzen ditu require-ak. Funtzio batek dei egiten badie, egoera kritikoago batean dauden beste eskaera batzuk blokea daitezke. Gainera, deitutako moduluetako batek edo haren menpeko ataza batek errore bat izanez gero, komeni da lehenbailehen haren berri jakitea, eta agian ezingo da hori egin, modulu horri funtzio batek deitzen badio + +

+ +## ![✔] 3.9 Inportatu moduluak karpetaka eta ez artxiboak zuzenean + +**TL;PL:** modulua/liburutegia karpeta batean garatzean, sartu index.js fitxategia, moduluaren barruko osagarriak agerian jarri eta erabiltzaile guztiek bertara joko dute eta. Hori eginez gero, moduluaren 'interfaze' gisa lan egiten du, eta geroago egin beharreko aldaketak errazten ditu kontratua hautsi gabe + +**Bestela:** fitxategien barne egitura edo sinadura aldatzeak erabiltzaileen interfazea apur dezake + +### 3.9 Kodearen adibidea + +```javascript +// Egin +module.exports.SMSProvider = require("./SMSProvider"); +module.exports.SMSNumberResolver = require("./SMSNumberResolver"); + +// Baztertu +module.exports.SMSProvider = require("./SMSProvider/SMSProvider.js"); +module.exports.SMSNumberResolver = require("./SMSNumberResolver/SMSNumberResolver.js"); +``` + +

+ +## ![✔] 3.10 Erabili `===` eragilea + +**TL;PL:** hobetsi berdintasunaren eragile zorrotza `===` berdintasun abstraktuaren eragile ahulagoa baino `==`. `==` eragileak bi aldagai alderatuko ditu, behin aldagai arrunt bihurtu ondoren. `===` eragileak ez du aldagai motaren bihurketarik egiten, eta bi aldagaiek mota berekoak izan behar dute berdinak izateko + +**Bestela:** `==`eragileak, berdinak ez diren aldagaiak alderatuz gero, berdinak direlako mezua helaraz dezake + +### 3.10 Kodearen adibidea + +```javascript +"" == "0"; // false +0 == ""; // true +0 == "0"; // true + +false == "false"; // false +false == "0"; // true + +false == undefined; // false +false == null; // false +null == undefined; // true + +" \t\r\n " == 0; // true +``` + +Aurreko azalpen guztiak faltsuak izango lirateke `===` eragilea erabili izan balitz + +

+ +## ![✔] 3.11 Erabili Async Await, ekidin callbackak + +**TL;PL:** Node 8 LTS erabat bateragarria da orain Async-waitekin, eta, horrela kode asinkronikoa kudeatzeko aukera ematen du, callbackik eta agintzarik erabili gabe. Async-waitek ez du blokeorik eragiten, eta kode asinkronikoak sinkroniko bihurtzen ditu. Zure kodeari egin ahal diozun oparirik onena async-wait erabiltzea da, eskaintzen duen kode sintaxia askoz ere trinkoagoa eta ezagunagoa da eta + +**Bestela:** gaizki pasatu eta infernura joateko biderik azkarrena hartu nahi baduzu, erabili callbackak errore asinkronoak kudeatzeko, seguruenik, infernura joateko biderik azkarrena aukeratuko duzu. Estilo honek gune guztietako erroreak egiaztatzera behartzen du, eta, gainera, kode habiaratze beti deserosoaren kudeaketa eta kode fluxua ulertzea zailtzen du + +🔗[**Informazio gehiago:** async wait 1.0ren gida](https://github.com/yortus/asyncawait) + +

+ +## ![✔] 3.12 Erabili gezi funtzioak (=>) + +**TL;PL:** agintzak eta callbackak onartzen dituzten API zaharrekin async-wait erabiltzea eta funtzio parametroak ekiditea gomendarria bada ere, gezi funtzioek kodearen egitura trinkotu egiten dute eta erro funtzioaren testuinguru lexikoa bermatu (hau da, `this` ) + +**Bestela:** (ES5 funtzioetan) kode luzeek erroreak izateko joera handiagoa dute, eta, gainera, irakurtzeko astunak dira + +🔗 [**Informazio gehiago: gezi funtzioak erabiltzeko garaia da**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75) + +


+ +

⬆ Itzuli hasierara

+ +# `4. Probak eta kalitate orokorra` + +## ![✔] 4.1 Idatzi APIaren probak (osagaia), gutxienez + +**TL;PL:** proiektu gehienei ez zaie proba automatikorik egiten denbora gutxian egiten direlako edo, maiz, 'proba proiektua' kontroletik kanpo geratu eta bertan behera uzten direlako. Hori dela eta, lehentasuna eman API probei eta hasi beraiek egiten; izan ere, hori da idazteko erarik errazena eta, gainera, proba unitarioek baino estaldura handiagoa eskaintzen dute; are gehiago, API probak sor ditzakezu, [Postman](https://www.getpostman.com/) bezalako tresnak erabiliz. Ondoren, baliabide eta denbora gehiago edukiz gero, jarraitu proba aurreratuak egiten, hala nola proba unitarioak, datu baseen probak, errendimendu probak, etab. + +**Bestela:** luzaroan aritu zintezke proba unitarioak idazten, azkenean soilik %20ko estaldura lortu duzula jakiteko + +

+ +## ![✔] 4.2 Erabili 3 zati proba izen bakoitzean + +**TL;PL:** proba adierazgarria izan behar da eskakizunen mailan, barne kodearekin lan egiten ohituta ez dauden QAko ingeniariek eta garatzaileek berez eta erraz uler dezaten. Probaren izenean adierazi zer ari den probatzen (probatzen ari den unitatea), zer egoeratan eta zer emaitza espero den + +**Bestela:** inplementazio batek huts egin du, “Gehitu produktua“ izeneko proba batek huts egin du. Esaten dizu horrek zehazki zer dabilen gaizki? + +🔗 [**Irakurri gehiago: erabili 3 zati proba izen bakoitzean**](/sections/testingandquality/3-parts-in-name.basque.md) + +

+ +## ![✔] 4.3 Egitura probak AAA ereduaren arabera + +**TL;PL:** egituratu zure probak ondo bereizitako 3 ataletan: antolatu, aritu eta baieztatu (AAA). Lehenengo atalean probaren konfigurazioa egin behar da; ondoren proba egikaritu behar da; eta, azkenik, baieztapen fasea dator. Egitura horri jarraitzeak bermatzen du irakurleak garuneko PUZik ez gastatzea proba plana ulertzen + +**Bestela:** kode nagusia ulertzen egunero orduak eta orduak pasatzeaz gainera, orain zure garuna trebatzen pasatzen duzu bestela eguneko zatirik lasaiena izan behar zuena (probak) + +🔗 [**Informazio gehiago: egitura probak AAA ereduaren arabera**](/sections/testingandquality/aaa.basque.md) + +

+ +## ![✔] 4.4 Antzeman kodeko arazoak linter bat erabiliz + +**TL;PL:** erabili kode linterra oinarrizko kalitatea egiaztatzeko eta antiereduak garaiz antzemateko. Exekutatu edozein proba baino lehen eta gehitu aurre-commit-a git kako moduan, edozein arazo berrikusteko eta zuzentzeko behar den denbora minimizatu ahal izateko. Era berean, egiaztatu [3. atala](#3-code-style-practices), kodearen estilo praktikei dagokienez + +**Bestela:** kode antiereduren bat zuzendu gabe utz dezakezu, zure produkzio ingurunean ahula izan litekeena + +

+ +## ![✔] 4.5 Saihestu datu globalak, gehitu datu pertsonalizatuak proba bakoitzean + +**TL;PL:** probak akopla daitezen ekiditeko eta proben fluxuari buruz erraz arrazoitzeko, proba bakoitzak bere datu baseko lerroen multzoan lan egin beharko luke. Proba batek datu baseko datu batzuk ba ote diren jakin nahi duenean edo haien beharra duen bakoitzean, berariaz erantsi behar dira datu horiek eta eragotzi beste erregistroren bat mutatzea + +**Bestela:** probek huts egin dutela eta, inplementazioa bertan behera utzi beharra izan duzula pentsatu. Egoera horretan, lan taldeak denbora asko pasatuko du porrotaren zergatiak aztertzen, azkenean, ondorio tamalgarri honetara iristeko: sistema ondo dabil; probek, ordea, elkarri eragiten diote eta egitura hausten dute + +🔗 [**Informazio gehiago: saihestu datu globalak**](/sections/testingandquality/avoid-global-test-fixture.basque.md) + +

+ +## ![✔] 4.6 Etengabe ikuskatu menpekotasun ahulak + +**TL;PL:** Express bezalako menpekotasun ospetsuenek ere ahultasun ezagunak dituzte, erraz gaindi daitezkeenak tresna komunitarioak eta komertzialak erabiliz, esaterako 🔗 [npm auditoria](https://docs.npmjs.com/cli/audit) eta 🔗 [snyk.io](https://snyk.io), zure CItik dei ditzakezunak konpilazio bakoitzean + +**Bestela:** zure kodeak ahultasunik ez izatea lortzeko tresna dedikaturik erabili gabe, etengabe begiratu beharko duzu mehatxu berriei buruz onlinen zer argitaratzen den eta haren jarraipena egin + +

+ +## ![✔] 4.7 Etiketatu zure probak + +**TL;PL:** egin beharreko probak desberdinak dira eszenatokiaren arabera; ke lasterrak, input-output gabekoak, garatzaileek artxibo bat gorde edo commit egiten dutenean erabiltzen diren testak, hasieratik amaierarainoko test erabatekoak presio eskaera berri bat bidaltzen denean egikaritzen direnak, etab. Hori lor daiteke #cold #api #sanity bezalako gako hitzak erabiliz probak etiketatzean, aukera izan dezazun zure proba tresnak erabiltzeko eta behar duzun azpimultzoari deitzeko. Adibidez, honela deitu ahal izango zenioke zentzutasun proba multzoari [Mocha](https://mochajs.org/) erabiliz: mocha --grep 'sanity' + +**Bestela:** garatzaile batek aldaketa txiki bat egiten duen bakoitzean oso motela izan daiteke proba guztiak exekutatzea, datu baseak kontsultatzen dituzten probak barne. Horrelako kasuetan, garatzaileei etsigarria gertatuko zaie probak egitea + +

+ +## ![✔] 4.8 Egiaztatu zure proben estaldura, proba eredu okerrak identifikatzen laguntzen du eta + +**TL;PL:** [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc) bezalako estaldura tresnak oso aproposak dira 3 arrazoirengatik: dohainik dira, hau da, ez da lanik egin behar txostenak lortzeko; proben estaldura gutxitu den identifikatzen laguntzen dute; eta, azkenik, baina ez garrantzi txikiagokoa, proben desdoikuntzak agerian jartzen dituzte. Koloretako kode estalduraren txostenak aztertzean, baliteke harrapaketa kapsula moduan sekula testatzen ez diren kode arloak ikustea, adibidez. Horrek esan nahi du probek bide arrakastatsuak besterik ez dituztela antzematen eta ez aplikazioak nola jokatzen duen erroreak gertatzen direnean. Konfiguratu zure probak estaldura maila batetik behera jaisten denean erroreak eragiteko + +**Bestela:** ez da inolako neurgailu automatizaturik egongo zure kodearen zati handi bat proben estalduratik kanpo dagoela esango dizuna + +

+ +## ![✔] 4.9 Ikuskatu pakete zaharkituak + +**TL;PL:** erabili zure tresnarik gogokoena (adibidez, 'npm outdated' edo [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) zaharkituta dauden paketeak antzemateko, ezarri kontrol hau zure IEren bideetan eta, are gehiago, eragin konpilazio batek huts egitea ingurune kritikoetan. Adibidez, agertoki kritikoa izan daiteke instalatutako pakete batek 5 adabaki baieztatuak dituenean (adibidez, bertsio lokala 1.3.1 da eta biltegi bertsioa 1.3.8) edo haren egileak zaharkitu etiketa jarri dionean. Kasu horretan, ezabatu konpilazioa eta ekidin bertsio hori erabiltzea + +**Bestela:** modu esplizituan arriskutsutzat etiketatuta dauden paketeak egikarituko ditu zure produkzioak + +

+ +## ![✔] 4.10 Erabili production bezalako inguruneak e2e probetarako + +**TL;PL:** zuzeneko datuak erabiltzen dituen hasieratik amaierarainoko proba(e2e) lehen CIren prozesuko katebegirik ahulena izaten zen, datu baseak bezalako zerbitzu astun askoren menpean dago eta. Erabili zure ekoizpen errealetik ahalik eta hurbilen dagoen ingurunea + +**Bestela:** docker-compose erabili ezean, taldeek ingurune bakoitzeko proben datu baseak mantendu behar izaten dituzte, garatzaileen makinak barne. Mantendu beti datu base horiek sinkronizatuta, proben emaitzak alda ez daitezen ingurune batetik bestera + +

+ +## ![✔] 4.11 Eguneratu probak aldizka analisi estatikoko tresnak erabiliz + +**TL;PL:** analisi estatikoko tresnak erabiltzeak lagundu egiten dizu kodearen kalitatea hobetzeko modu objektiboak lortzen eta zure kodea jasangarri izaten. Analisirako tresna estatikoak gehitu ahal dizkiozu zure IE konpilazioari, huts egingo duen susmoa duzuenean. Estaldurari dagokionean, bere aldeko puntu nagusiak dira kalitatea ikuskatzeko gaitasuna dutela fitxategi anitzen testuinguruan (adibidez, bikoizketak antzematea), azterketa aurreratuak egitea (adibidez, kodearen konplexutasuna hautematea), eta kode arazoen historiaren eta aurrerapenaren jarraipena egitea. Horretarako, bi tresna hauek erabil ditzakezu: [Sonarqube](https://www.sonarqube.org/) (2.600+ [izar](https://github.com/SonarSource/sonarqube)) eta [Code Climate](https://codeclimate.com/) (1.500+ [izar](https://github.com/codeclimate/codeclimate)) + +**Bestela:** kodearen kalitatea txarra denean, erroreek eta errendimenduak beti emango dituzte arazoak, azken belaunaldiko ezaugarriak dituen liburutegi berri distiratsu batek ere konpontzerik izango ez dituenak + +🔗 [**Informazio gehiago: Berregituratu!**](/sections/testingandquality/refactoring.basque.md) + +

+ +## ![✔] 4.12 Aukeratu arretaz zure IE plataforma (Jenkins vs CircleCI vs Travis vs gainerako mundua) + +**TL;PL:** zure integrazio jarraituaren plataformak (CICD) kalitateko tresna guztiak (adib. testak, lintak) ostatatu behar ditu, eta, beraz, indartsua izan beharko du pluginen ekosistema. Aspaldian [Jenkins](https://jenkins.io/) proiektu askoren balio lehenetsia izan ohi zen, komunitaterik handiena eta oso plataforma indartsua baititu, ordainetan konfigurazio konplexu samarra eta ikaste kurba pikoa baditu ere. Gaur egun, askoz errazagoa da IE irtenbide bat sortzea [CircleCI](https://circleci.com) eta haren antzeko SaaS tresnak erabiliz. Tresna horiek IE hodi malgu bat sortzea ahalbidetzen dute azpiegitura osoa kudeatzeko zama hartu beharra izan gabe. Azken batean, sendotasuna eta abiaduraren arteko oreka lortzea da kontua. Egin zure aukera arretaz + +**Bestela:** hornitzaile espezializatu bat aukeratzeak blokeatu zaitzake, pertsonalizazio aurreratu bat behar duzunean. Bestalde, Jenkins erabiltzeak denbora asko eska dezake azpiegitura konfiguratzean + +🔗 [**Irakurri gehiago: IC plataforma aukeratzea**](/sections/testingandquality/citools.basque.md) + +

+ +## ![✔] 4.13 Probatu zure middlewareak eurak bakarrik + +**TL;PL:** middlewareak eskaera askori erantzuten dion logika sendo bat duenean, merezi du middlewarea probatzea bera bakarrik, web esparru osoa aktibatu gabe. Hori erraz lor daiteke {req, res, next} objektuak antzemanez eta behatuz + +**Bestela:** middleware Expressean === errorea izanez gero, errorea gertatuko zaizu eskaera guztietan edo gehienetan + +🔗 [**Irakurri gehiago: probatu zure middlewareak eurak bakarrik**](/sections/testingandquality/test-middlewares.basque.md) + +


+ +

⬆ Itzuli hasierara

+ +# `5. Ekoizpena` + +## ![✔] 5.1. Monitorizazioa + +**TL;PL:** bezeroek baino lehenago arazoak aurkitzeko joku bat da monitorizazioa. Jakina, garrantzi handia eman behar zaio. Merkatua eskaintzez gainezka dago, eta, beraz, komeni zaizu zehazten hastea zeintzuk diren hartu behar dituzun oinarrizko neurriak (hemen dituzu nire iradokizunak); ondoren, pentsatu zer neurri osagarri ezarri behar dituzun; eta, azkenik, aukeratu hipotesi guztiak kontuan hartzen dituen soluzioa. Egin klik soluzioen ikuspegi orokorra izateko + +**Bestela:** hutsegitea === bezero zapuztuak + +🔗 [**Irakurri gehiago: monitorizazioa!**](/sections/production/monitoring.md) + +

+ +## ![✔] 5.2. Gardentasuna handitu erregistratze plataforma adimendunak erabiliz + +**TL;PL:** erregistroak arazketa adierazpen hutsalen biltegia izan daitezke edo zure aplikazioaren historia kontatzen duen aginte mahai praktikoa. Planifikatu zure erregistratze plataforma lehenengo egunetik: hau da, nola bildu, gorde eta aztertuko dituzun erregistroak, nahi duzun informazioa benetan eskura daitekeela bermatzeko (adibidez, zein den errore tasa, zerbitzu eta zerbitzarien bidez transakzio oso bat egin ondoren, eta abar) + +**Bestela:** kutxa beltz batekin amaituko duzu, eta zaila izango zaizu han jasotako ezarpenen zergatia aurkitzea. Azkenean, erregistro adierazpen guztiak idazten hasiko zara informazio osagarria gehitzeko + +🔗 [**Gehiago irakurri: gardentasuna handitu erregistratze plataforma adimendunak erabiliz**](/sections/production/smartlogging.md) + +

+ +## ![✔] 5.3. Utzi ahal den guztia alderantzizko proxy batean (adibidez, gzip, SSL) + +**TL;PL:** Node izugarri txarra da PUZen zeregin intentsiboak egiten, esate baterako, gzipping, SSL termination. Haien partez benetako middleware zerbitzuak erabili behar dituzu –hala nola nginx eta Haproxy– +edo hornitzaileen lainoko zerbitzuak + +**Bestela:** zure hari bakarra lanpetuta egongo da azpiegitura lanak egiten, zure aplikazioaren guneari kasu egin beharrean, eta, ondorioz, haren errendimenduak behera egingo du + +🔗 [**Irakurri gehiago: utzi ahal den guztia alderantzizko proxy batean (adibidez, gzip, SSL)**](/sections/production/delegatetoproxy.md) + +

+ +## ![✔] 5.4. Blokeatu menpekotasunak + +**TL;PL:** zure kodeak berdin-berdina izan behar du ingurune guztietan, baina harrigarria bada ere npm lehenetsita dago menpekotasunei ingurune batetik bestera pasatzen uzteko. Instalatzen dituzunean paketeak hainbat ingurunetan, paketeen azken bertsioa eskuratzen saiatzen da. Hori saihesteko, erabili npm edo .npmrc konfigurazio artxiboak, ingurune bakoitzean dagokion paketearen zein bertsio zehatz (eta ez derrigorrez berriena) komeni zaizun adieraziko dizu eta. Bestela, kontrola fintze aldera, erabili `npm shrinkwrap`. \*Eguneratzea: NPM5 bertsiotik aurrera, menpekotasunak defektuz blokeatzeko konfiguratuta dator. Yarn pakete kudeatzaile berria ere lehenetsita dago horrela lan egiteko + +**Bestela:** QAk kodea xeheki probatuko du eta onartuko duen bertsioak desberdin jokatuko du produkzioan. Are okerrago, produkzio talde bereko zerbitzarien kodeak desberdinak izan litezke + +🔗 [**Informazio gehiago: blokeatu menpekotasunak**](/sections/production/lockdependencies.md) + +

+ +## ![✔] 5.5. Babestu prozesuaren erabilgarritasuna tresna egokiak erabiliz + +**TL;PL:** prozesuak huts eginez gero, aurrera egin eta berrabiarazi beharra dago. Egoera arruntetan, nahikoak izan daitezke PM2 bezalako prozesuak kudeatzeko tresnak, baina gaur egungo mundu ”docker”-izatuan, taldeak kudeatzeko tresnak ere kontuan hartu behar dira + +**Bestela:** estrategia argirik gabe dozenaka eskaera exekutatzeak DevOpsa nahaste-borrastera eraman dezake, hartarako aldi berean tresna gehiegi (talde kudeaketa, dockerra, PM2) erabiliz gero + +🔗 [**Irakurri gehiago: babestu prozesuaren erabilgarritasuna tresna egokiak erabiliz**](/sections/production/guardprocess.md) + +

+ +## ![✔] 5.6. Erabili PUZeko nukleo guztiak + +**TL;PL:** Noderen oinarrizko bertsioa PUZeko nukleo bakar batean exekutatzen da, eta beste nukleo guztiak geldi geratzen dira. Beharrezkoa da Noderen prozesua erreplikatzea PUZ guztiak erabiliz: aplikazio txiki eta ertainekin, Node Cluster edo PM2 erabil dezakezu; aplikazio handi samarrekin, berriz, saiatu erabiltzen Docker tankerako talderen bat (adibidez, K8S, ECS) edo Linux hasieratze sisteman oinarritutako garatze idazkerak (adibidez, systemd) + +**Bestela:** seguruenik, zure aplikazioak erabilgarri dituen baliabideen %25a besterik ez du erabiltzen (!), edo gutxiago, agian. Kontuan izan ohiko zerbitzariek gutxienez lau nukleo dituztela PUZen, eta Node.jsren garatzaile soilak bat bakarra erabiltzen duela (AWS beanstalk bezalako PaaS zerbitzuekin lan egiten duenean ere) + +🔗 [**Informazio gehiago: erabili PUZeko nukleo guztiak**](/sections/production/utilizecpu.md) + +

+ +## ![✔] 5.7. Sortu ‘bukaerako mantentze puntua‘ + +**TL;PL:** API seguru batean, jarri agerian sistemarekin lotutako informazio multzo bat, hala nola, memoriaren erabilera eta REPL, etab. Nahiz eta gomendagarria den proba estandarretan eta tresna arruntetan oinarritzea, zenbait informazio eta eragiketa baliotsu errazago egiten dira kodea erabiliz + +**Bestela:** konturatuko zara “diagnostiko-inplementazio“ asko egiten ari zarela, eta kodea produkziora bidaltzen duzula soilik informazioa lortzeko diagnostikoa egite aldera + +🔗 [**Informazio gehiago: sortu ‘bukerako mantentze puntua‘**](/sections/production/createmaintenanceendpoint.md) + +

+ +## ![✔] 5.8. Aurkitu akatsak eta geldialdiak APM produktuak erabiliz + +**TL;PL:** aplikazioen jarraipen eta errendimendu produktuek (APM deritzona) modu proaktiboan neurtzen dituzte kode basea eta APIa, modu automatikoan ohiko jarraipenetik haratago joateko eta erabiltzaileen esperientzia arrunta zerbitzu eta maila guztietan neurtzeko. Adibidez, APM produktu batzuek agerian jarri dezakete azken erabiltzaileen aldean motelegi kargatzen dela transakzio bat, sakoneko arrazoia iradokitzen duten bitartean + +**Bestela:** APIaren errendimendua eta geldialdiak neurtzeko ahalegin handia egin zenezake, eta, ziurrenik, ez zinateke jabetuko zein diren zure kodearen atalik motelenak mundu errealeko eszenatokian eta nola eragiten dioten zure erabiltzaile esperientziari + +🔗 [**Irakurri gehiago: aurkitu akatsak eta geldialdiak APM produktuak erabiliz**](/sections/production/apmproducts.md) + +

+ +## ![✔] 5.9. Prestatu zure kodea ekoizpenerako + +**TL;PL:** programatu helburua kontuan izanik; planifikatu produkzioa lehenengo egunetik hasita. Horrek lausoa eta zehazgabea ematen duenez, produkzioaren mantentzeari estu-estu lotuta dauden garatze aholku batzuk bildu ditut (egin klik hemen behean dagoen Gist estekan) + +**Bestela:** IT / DevOps arloko munduko txapeldun batek ere ez du salbatuko gaizki idatzita dagoen sistema + +🔗 [**Irakurri gehiago: prestatu zure kodea ekoizpenerako**](/sections/production/productioncode.md) + +

+ +## ![✔] 5.10. Neurtu eta babestu memoriaren erabilera + +**TL;PL:** Node.jsek harreman gatazkatsuak ditu memoriarekin: v8 motorrak muga leunak dauzka memoria erabiltzean (1,4 GB) eta ezaguna da zein bidetatik galtzen duen Noderen kodeak memoria. Beraz, ezinbestekoa da Noderen prozesu memoriari erreparatzea. Aplikazio txikietan memoria aldizka neur dezakezu geruza komandoak erabiliz; baina aplikazio ertainetan eta handietan aztertu beharko zenuke ez ote zaizun komeni zure memoria erlojua kontrol sistema sendo baten erara erabiltzea + +**Bestela:** zure memoria prozesuak 100 bat megabyte gal dezake egunean, [Walmart](https://www.joyent.com/blog/walmart-node-js-memory-leak)-i gertatu zitzaion bezala + +🔗 [**Irakurri gehiago: neurtu eta babestu memoriaren erabilera**](/sections/production/measurememory.md) + +

+ +## ![✔] 5.11. Atera zure frontend modulu aktiboak Nodetik + +**TL;PL:** prestatu frontend edukia middleware dedikatu bat erabiliz (adibidez, nginx, S3, CDN), zeren Noderen errendimenduak behera egiten baitu artxibo estatiko askorekin lan egiten duenean, bera azpiprozesu bakarrekoa da eta + +**Bestela:** Node eduki dinamikoa eskaintzeko sortu zen arren, haren hari bakarra lanpetuta egongo da html / images / angular / react erako ehunka fitxategi bidaltzen, bera egiteko sortua izan zen zereginei esleitu barik bere baliabide guztiak + +🔗 [**Irakurri gehiago: atera zure frontend aktiboak Nodetik**](/sections/production/frontendout.md) + +

+ +## ![✔] 5.12. Izan stateless, hil zerbitzariak ia egunero + +**TL;PL:** gorde edozein datu mota (adibidez, erabiltzaile saioak, cacheak, kargatutako fitxategiak) kanpoko datu biltegietan; eta aztertu ez ote zenituzkeen zure zerbitzari guztiak aldian behin “hil” beharko edo “zerbitzaririk gabe”ko plataformaren bat erabili (adibidez, AWS Lambda), berariaz stateless jokaera duena + +**Bestela:** zerbitzari jakin batek huts eginez gero, makina akastun bat hil beharrean, aplikazioen geldialdia eragingo du. Gainera, gero eta zailagoa izango da mailaketaren elastikotasuna, zerbitzari jakin baten menpeko izanda + +🔗 [**Irakurri gehiago: izan stateless, hil zerbitzariak ia egunero**](/sections/production/bestateless.md) + +

+ +## ![✔] 5.13. Erabili ahuleziak automatikoki antzematen dituzten tresnak + +**TL;PL:** menpekotasun ezagunenek ere –Express, adibidez– badituzte (noizean behin) ahulezia ezagunak, sistema arriskuan jar ditzaketenak. Horrek konponbide erraza du, ordea, tresna komunitario eta komertzialak erabiliz gero, ahuleziak etengabe kontrolatu eta haien berri ematen dute eta (bertan edo GitHub-en) + +**Bestela:** zure kodea ahulezia eta zaurgarritasunetatik garbi mantentzeko tresna dedikaturik gabe, jarraipen estua egin beharko diezu mehatxu berriei buruz linean egiten diren argitalpenei, bide batez esanda, aspergarri samarra izaten dena + +🔗 [**Irakurri gehiago: erabili ahuleziak automatikoki antzematen dituzten tresnak**](/sections/production/detectvulnerabilities.md) + +

+ +## ![✔] 5.14. Esleitu transakzio identifikazio bat adierazpen-erregistro bakoitzari + +**TL;PL:** esleitu identifikatzaile bera –transakzio-: {balioren bat}– erregistro sarrera bakoitzari eskaera bakar baten barruan. Ondoren, erregistroetako erroreak ikuskatzean, erraz konturatuko zara zer gertatu zen aurretik eta ondoren. Zoritxarrez, hori ez da erraz lortzen Noden, haren izaera asinkronoa da eta. Ikusi kodearen adibideak beheko estekan + +**Bestela:** produkzioko erroreen erregistroa testuingururik gabe ikustean – aurretik gertatu zena, alegia –, askoz zailagoa eta motelagoa da arazoa aztertzea + +🔗 [**Irakurri gehiago: esleitu ‘TransactionId’ adierazpen erregistro bakoitzari**](/sections/production/assigntransactionid.md) + +

+ +## ![✔] 5.15. Ezarri NODE_ENV = produkzioa + +**TL;PL:** ezarri NODE_ENV ingurune aldagaia ‘produkzioa‘ edo ‘garapena‘ ataletan produkzioaren optimizazioak aktibatu beharra dagoen adierazteko; npm pakete askok uneko ingurunea zehazten dute eta haren kodea optimizatzen dute ekoizpenerako + +**Bestela:** ezaugarri soil hori gabe errendimendua asko jaits liteke. Adibidez, Express erabiltzean zerbitzarira bideratzeko `NODE_ENV` gabe, errendimendua heren bat moteltzen da + +🔗 [**Informazio gehiago: Ezarri NODE_ENV = produkzioa**](/sections/production/setnodeenv.md) + +

+ +## ![✔] 5.16. Diseinatu inplementazio automatizatuak, atomikoak eta geldialdi gabekoak + +**TL;PL:** ikerketek frogatu dute inplementazio ugari egiten dituzten taldeek ekoizpen arazo kritikoak izateko probabilitatea txikiagotzen dutela. Eskuz egin beharreko urrats arriskutsurik eta zerbitzuen geldialdirik ez duten inplementazio azkar eta automatizatuek nabarmen hobetzen dute inplementazio prozesua. Baliteke hori bera lortzea Docker eta IE tresnak, biak batera, erabiliz, inplementazio sinplifikatuari dagokionez industriaren estandarra bihurtu dira eta + +**Bestela:** inplementazio luzeak -> produkzioaren geldialdia eta gizakiak eragindako erroreak -> inplementazioan konfiantzarik ez duen taldea -> inplementazio eta funtzio gutxiago egitea + +

+ +## ![✔] 5.17. Erabili Node.jsren LTS bertsio berria + +**TL;PL:** ziurtatu Node.jsren LTS bertsioa erabiltzen ari zarela errore kritikoen zuzenketak, segurtasun eguneratzeak eta errendimenduaren hobekuntzak jasotzeko + +**Bestela:** aurkitu berri diren erroreak edo ahuleziak erabil litezke produkzioan exekutatzen den aplikazio bat ustiatzeko eta baliteke zure aplikazioa ez izatea bateragarria hainbat modulurekin eta zailagoa gertatzea hura mantentzea + +🔗 [**Irakurri gehiago: Erabili NTS.jsren LTS bertsioa**](/sections/production/LTSrelease.md) + +

+ +## ![✔] 5.18. Ez bideratu erregistrorik aplikazioaren barruan + +**TL;PL:** garatzaileek ez dituzte erregistroen helmugak aplikazio kodearen barruan kodetu behar, aplikazioa exekutatzen den inguruneak berak definitu beharko ditu eta. Garatzaileek `stdout`-ean idatzi behar dituzte erregistroak erregistratze tresna bat erabiliz, eta gero exekuzio inguruneak (edukiontzia, zerbitzaria eta abar) bideratuko du `stdout` korrontea helmuga egokira (hau da, Splunk, Graylog, ElasticSearch eta abar) + +**Bestela:** aplikazioen kudeaketaren erregistroak bideratzea === zaila da eskalatzen, erregistroen galera dakar, eskasa izaten da kezken bereizketa + +🔗 [**Irakurri gehiago: erregistroen bideraketa**](/sections/production/logrouting.md) + +

+ +## ![✔] 5.19. Instalatu zure paketeak `npm ci` erabiliz + +**TL;PL:** ziurtatu ekoizpen kodeak erabiltzen duela probak egiteko erabili dituzun paketeen bertsio berdina. Exekutatu `npm ci` zure package.json eta package-lock.json paketen menpekotasunen instalazio garbia egiteko + +**Bestela:** QAk kodea sakonki probatuko du eta produkzioan modu desberdinean jokatuko duen bertsioa onartuko du. Are okerrago, produkzio talde bateko hainbat zerbitzarik kode desberdinak exekuta ditzake + +🔗 [**Informazio gehiago: erabili npm ci**](/sections/production/installpackageswithnpmci.md) + +


+ +

⬆ Itzuli hasierara

+ +# `6. Segurtasuna` + +
+54 items +
+ +## ![✔] 6.1. Erabili linter segurtasun arauak + + + +**TL;PL:** erabili segurtasunarekin lotutako linter pluginak, [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security) bezalako segurtasun ahuleziak eta arazoak lehenbailehen antzemateko, ahal bada kodetzen ari diren bitartean. Horrek segurtasun ahuleziak atzematen lagun dezake, hala nola eval erabiltzea, bigarren mailako prozesu bat deitzea edo modulu bat inportatzea kate literal batekin (adibidez, erabiltzailearen sarrera). Egin klik 'Gehiago irakurri' atalean segurtasun liner batek antzematen dituen kode adibideak ikusteko + +**Bestela:** garapenean zehar segurtasun ahulezia zuzena izan zitekeena produkzioaren arazo nagusia bihurtzen da. Gainera, baliteke proiektuak kodeen segurtasun praktika koherenterik ez jarraitzea, ahuleziak sartzea edo urruneko biltegietan sartutako sekretu konfidentzialak sortzea + +🔗 [**Gehiago irakurri: lint arauak**](/sections/security/lintrules.md) + +

+ +## ![✔] 6.2. Mugatu aldi baterako eskaerak middleware bat erabiliz + + + +**TL;PL:** DOS erasoak oso ezagunak dira, eta nahiko erraz eragin daitezke. Ezarri abiadura muga kanpoko zerbitzu bat erabiliz, hala nola hodeiko karga orekatzaileak, hodeiko suebakiak, nginx, [rate-limiter-flexible](https://www.npmjs.com/package/rate-limiter-flexible) edo (aplikazio txikiagoak eta ez hain kritikoetarako) abiadura mugatzeko middleware bat (adibidez, [express-rate-limit](https://www.npmjs.com/package/express-rate-limit), express abiadura mugatzailea) + +**Bestela:** aplikazio batek erasoak jasan ahal ditu, haren erabiltzaileei ukatzen bazaie jaso beharko luketen zerbitzua, aplikazioa egoera txarrean dagoelako edo eskuragarri ez dagoelako + +🔗 [**Gehiago irakurri: ezarri abiadura muga**](/sections/security/limitrequests.md) + +

+ +## ![✔] 6.3 Kendu sekretuak konfigurazio fitxategietatik edo erabili paketeak enkriptatzeko + + + +**TL;PL:** ez gorde inoiz testu arrunteko sekreturik konfigurazio fitxategietan edo iturburu kodean. Horren ordez, erabili sekretuak kudeatzeko sistemak, hala nola Vault produktuak, Kubernetes / Docker Secrets edo ingurune aldagaiak. Azken baliabide gisa, iturburuko kontrolean gordetako sekretuak enkriptatu eta kudeatu egin behar dira (gako birakariak, iraungitzeak, ikuskaritza, etab.). Erabili aurre-commit/push kakoak, ustekabean sekreturik gordetzea saihesteko + +**Bestela:** iturburu kodearen kontrola publiko egin daiteke akats baten ondorioz, biltegi pribatuetan ere, eta orduan sekretu guztiak agerian geratzen dira. Kanpoko norbaitek iturburuko kontrolaren sarbidea ezagutzeak nahi gabe eragingo du erlazionatutako sistemetarako sarbideak ere ezagutzea (datu baseak, APIak, zerbitzuak, etab.) + +🔗 [**Gehiago irakurri: kudeaketa sekretua**](/sections/security/secretmanagement.md) + +

+ +## ![✔] 6.4. Saihestu kontsultak injektatzeko ahultasunak ORM / ODM liburutegiekin + + + +**TL;PL:** SQL / NoSQL injekzioa eta beste eraso maltzur batzuk ekiditeko, erabili beti ORM / ODM edo datuetatik ihes egiten duen datu baseen liburutegia, edo kontsulta parametro izendatuak edo indexatuak onartzen dituena eta espero diren erabiltzaileen sarrera balioztatzen duena. Inoiz ez erabili JavaScript txantiloien kateak edo katearen kateatzea balioak kontsultetan txertatzeko, horrek zure aplikazioa ahultasunen espektro zabalera irekitzen baitu. Node.js entzute handiko datuen liburutegi guztiek injekzio erasoen aurkako babesa dute (adibidez, [Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose)) + +**Bestela:** balidatu gabeko edo baimendu gabeko erabiltzaileen sarrerak operadorearen injekzioa ekar dezake NoSQLrako MongoDB-rekin lan egitean, eta saneamendu sistema edo ORM egokia ez erabiltzeak SQL injekzio erasoak ahalbidetuko ditu, ahultasun erraldoia sortuz + +🔗 [**Gehiago irakurri: kontsulten injekzioaren prebentzioa ORM / ODM liburutegiak erabiliz**](/sections/security/ormodmusage.md) + +

+ +## ![✔] 6.5. Segurtasuneko jardunbide egokien bilduma + +**TL;PL:** Node.jsekin zuzenean loturarik ez duen segurtasuneko aholku bilduma bat da: Noderen inplementazioa ez da hain desberdina beste edozein hizkuntzaren inplementazioaren aldean. Egin klik “irakurri gehiago” botoian sakontzeko + +🔗 [**Gehiago irakurri: segurtasuneko ohiko jardunbide egokienak**](/sections/security/commonsecuritybestpractices.md) + +

+ +## ![✔] 6.6. Doitu HTTP erantzunen izenburuak segurtasun hobea lortzeko + + + +**TL;PL:** zure aplikazioak izenburu seguruak erabili beharko lituzke erasotzaileek gune arteko scriptak (XSS), clickjacking-a eta beste eraso maltzur arruntak egitea saihesteko. Horiek erraz konfigura daitezke [helmet](https://www.npmjs.com/package/helmet) bezalako moduluak erabiliz + +**Bestela:** erasotzaileek zure aplikazioaren erabiltzaileen aurkako eraso zuzenak egin ditzakete, segurtasun ahultasun handiak sortuz + +🔗 [**Gehiago irakurri: erabili izenburu seguruak zure aplikazioan**](/sections/security/secureheaders.md) + +

+ +## ![✔] 6.7. Etengabe eta automatikoki ikuskatu ba ote dagoen erasotzen errazak diren menpekotasunak + + + +**TL;PL:** npm ekosistemarekin ohikoa da proiektu batek menpekotasun ugari izatea. Menpekotasunak beti kontrolatuta egon behar dira ahultasun berriak aurkitzen diren heinean. Erabili [npm audit](https://docs.npmjs.com/cli/audit) edo [snyk](https://snyk.io/) bezalako tresnak, erasotzen errazak diren menpekotasunen jarraipena egiteko, kontrolatzeko eta adabakiak jartzeko. Tresna horiek zure IE konfigurazioarekin integratu, erasotzen errazak diren menpekotasunenak antzemateko ekoizpenera iritsi aurretik + +**Bestela:** erasotzaile batek zure web esparrua detektatu eta ageriko ahultasun guztiei eraso ahal die + +🔗 [**Gehiago irakurri: menpekotasunen segurtasuna**](/sections/security/dependencysecurity.md) + +

+ +## ![✔] 6.8. Babestu erabiltzaileen pasahitzak / sekretuak BCrypt edo Script erabiliz + + + +**TL;PL:** pasahitzak eta sekretuak (adibidez API gakoak) gorde behar dira hash + gatz funtzio seguru bat erabiliz, esaterako, `bcrypt`edo `scrypt`; eta kasurik okerrenean, `pbkdf2` + +**Bestela:** funtzio segururik erabili gabe gordetzen diren pasahitzak eta sekretuak bortxaz erasotuak izan daitezke edo hiztegi erasoak jasan ditzakete. Azkenean agerian gera daitezke, bai eta agian zabaldu ere + +🔗 [**Gehiago irakurri: erabiltzaileen pasahitzak**](/sections/security/userpasswords.md) + +

+ +## ![✔] 6.9. Ekidin HTML, JS eta CSS irteerak + + + +**TL;PL:** arakatzailera bidaltzen diren datu ez fidagarriak bistaratu beharrean exekutatu egin daitezke, normalean cross-site-scripting (XSS) erasoa deritzona. Arindu hori datuak inoiz exekutatu behar ez diren eduki huts gisa (hau da, kodetu, ihes)esplizituki markatzen dituzten liburutegi espezializatuak erabiliz + +**Bestela:** erasotzaile batek JavaScript kodeketa kaltegarria gorde dezake zure DBn, gero bezero gizajoei dagoen moduan bidaliko zaiena + +🔗 [**Gehiago irakurri: ihes irteera**](/sections/security/escape-output.md) + +

+ +## ![✔] 6.10. Balidatu sarrerako JSON eskemak + + + +**TL;PL:** balidatu sarrerako eskaeren gorputzeko zama erabilgarria eta ziurtatu zure itxaropenak betetzen dituela; eta, haiek bete ezean, huts eragin. Ibilbide bakoitzaren balioztatze kodetze neketsua saihesteko JSONen oinarritutako balioztatze eskema arinak erabil ditzakezu, hala nola [jsonschema](https://www.npmjs.com/package/jsonschema) edo [joi](https://www.npmjs.com/package/joi) + +**Bestela:** zure eskuzabaltasunak eta ikuspegi permisiboak asko handitzen dute erasoaren tamainua, eta erasotzailea sarrera asko probatzera bultzatzen du, aplikazioa kraskatzeko konbinazio bat aurkitu arte + +🔗 [**Gehiago irakurri: balidatu sarrerako JSON eskemak**](/sections/security/validation.md) + +

+ +## ![✔] 6.11. Onartu JWTen zerrenda beltzak + + + +**TL;PL:** JSON web fitxak erabiltzean (adibidez, [Passport.js](https://github.com/jaredhanson/passport))-rekin), lehenespenez ez dago igorritako fitxen sarbidea ezeztatzeko mekanismorik. Erabiltzaileen jarduera maltzurren bat aurkitu ondoren, ez dago modurik sistemara sartzea eragozteko, baliozko fitxaren bat duten bitartean. Konpondu hori eskaera bakoitzean balioztatuko diren fitxa ezfidagarrien zerrenda beltza erabiliz + +**Bestela:** edozeinek erabil litzake iraungitako edo gaizki kokatutako fitxak, maltzurki aplikazio batera sartzeko eta fitxaren jabea ordezkatzeko + +🔗 [**Gehiago irakurri: JSON web fitxen zerrenda beltzak**](/sections/security/expirejwt.md) + +

+ +## ![✔] 6.12. Aurrea hartu baimenaren aurkako eraso basatiei + + + +**TL;PL:** oso teknika sinple eta eraginkorra da baimen saiakerak mugatzea bi metrika erabiliz: + +1. Lehenengoa, erabiltzaile beraren ID / izen eta IP helbide bakarrak jarraian huts egin duen saiakera kopurua +2. Bigarrena, IP helbide batek denbora tarte luze batean huts egin duen saiakera kopurua. Adibidez, blokeatu IP helbide bat, egun batean 100 saiakera huts egiten baditu + +**Bestela:** erasotzaile batek pasahitz automatizatuen saiakera mugagabeak egin ditzake aplikazio bateko kontu pribilegiatuetara sartzeko + +🔗 [**Gehiago irakurri: saioa hasteko saiakera kopurua mugatzea**](/sections/security/login-rate-limit.md) + +

+ +## ![✔] 6.13. Exekutatu Node.js erro ez den erabiltzaile gisa + + + +**TL;PL:** eszenatoki arrunt batean Node.js baimen mugagabeak dituen erro erabiltzaile gisa exekutatzen da. Hori da, adibidez, Docker edukiontzietako portaera lehenetsia. Gomendagarria da erro ez den erabiltzaile bat sortzea eta Docker irudian sartzea (behean azaltzen dira adibideak) edo prozesua erabiltzaile horren izenean abiaraztea "-u username" marka duen edukiontzia deituz + +**Bestela:** zerbitzarian script bat exekutatzea lortzen duten erasotzaileek botere mugagabea lortzen dute makina lokalaren gainean (adibidez, iptable aldatu eta trafikoa beren zerbitzarira bideratzea) + +🔗 [**Gehiago irakurri: exekutatu Node.js erro ez den erabiltzaile gisa**](/sections/security/non-root-user.md) + +

+ +## ![✔] 6.14. Mugatu kargaren tamaina alderantzizko proxy edo middleware bat erabiliz + + + +**TL;PL:** zenbat eta gorputzaren karga handiagoa izan, orduan eta zailagoa da zure hari bakarra lan egitea hura prozesatzean. Hori da erasotzaileek zerbitzariak belauniko jartzeko aukera ona eskaera kopuru izugarririk egin gabe (DOS / DDOS erasoak). Murriztu arriskua ertzean jasotako eskaeren gorputzaren tamaina mugatuz (adibidez, suebakia, ELB) edo [express body parser](https://github.com/expressjs/body-parser) konfiguratuz tamaina txikiko kargak bakarrik onartzeko + +**Bestela:** zure aplikazioak eskaera handiei aurre egin beharko die, eta ezingo du prozesatu egin behar duen beste lan garrantzitsua, ondorioz errendimendua gutxituz eta DOS erasoekiko ahulduz + +🔗 [**Gehiago irakurri: mugatu kargaren tamaina**](/sections/security/requestpayloadsizelimit.md) + +

+ +## ![✔] 6.15. Saihestu JavaScripten eval adierazpenak + + + +**TL;PL:** `eval` arriskutsua da, exekutatzeko garaian JavaScript kode pertsonalizatua exekutatzea baimentzen baitu. Hori ez da errendimendu arazo bat bakarrik, baizik eta segurtasun arazo garrantzitsua, erabiltzaileen sarreratik JavaScript kode gaiztoa lor daiteke eta. Halaber, `new Function constructor` ere saihestu beharra dago; eta, azkenik, `setTimeout` eta `setInterval`, ez dira inoiz pasatu behar, ezta JavaScript kode dinamikoa ere + +**Bestela:** Javascript kode gaiztoak bidea aurkitzen du `eval` testura edo JavaScript hizkuntzak denbora errealean ebaluatzeko dituen funtzioetara sartzeko, eta sarbide osoa lortuko du JavaScripten orrialdeko baimenetara. Ahultasun hori XSS eraso gisa agertzen da askotan + +🔗 [**Gehiago irakurri: saihestu JavaScript eval adierazpenak**](/sections/security/avoideval.md) + +

+ +## ![✔] 6.16. Saihestu RegEx gaiztoak zure hari bakarreko exekuzioa gainkargatzea + + + +**TL;PL:** adierazpen erregularrak, oso erabilgarriak izan arren, benetako mehatxua dira JavaScript aplikazioentzat, oro har, eta Node.js plataformarentzat, bereziki. Erabiltzaile baten sarrera prozesatzeko testuarekin bat etor dadin, gerta liteke PUZeko ziklo kopuru handia behar izatea. RegExen prozesamenduaren eraginkortasuna hain txikia izan daiteke, ezen 10 hitz balioztatzen dituen eskaera bakar batek blokea baitezake gertaeren begizta osoa 6 segundoz, eta PUZa su hartzeko moduan jarri 🔥. Hori dela eta, erasotzen errazak diren ohiko adierazpen ahulen txantiloiak antzemateko erabili hirugarrenen balidazio paketeak -esaterako, [validator.js](https://github.com/chriso/validator.js)-, zuk zeure Regex ereduak idatzi edo [safe-regex](https://github.com/substack/safe-regex) erabili gabe + +**Bestela:** gaizki idatzitako ohiko adierazpenek Regular Expression DoSen erasoak jasan ditzakete, gertaeren begizta erabat blokeatuko dutenak. Adibidez, 2017ko azaroan, RegExen erabilera gaiztoak agerian jarri zuen `moment` pakete ezagunaren ahultasuna + +🔗 [**Gehiago irakurri: saihestu RegEx gaiztoa erabiltzea**](/sections/security/regex.md) + +

+ +## ![✔] 6.17. Saihestu moduluak kargatzea aldagai bat erabiliz + + + +**TL;PL:** bide bat erabiltzailea sartu ondoren sortua ote den kezka baduzu eta horregatik parametro gisa ezarri baduzu, saihestu bide hori erabiltzea beste fitxategi bat deitzeko / inportatzeko. Arau hori, oro har, edozein fitxategitara sartzeko erabil daiteke (hau da, `fs.readFile()`) edo erabiltzailea sartu ondoren sortutako aldagai dinamikoak dituen beste baliabide konfidentzialetara sartzeko. [Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linterrek eredu horiek antzeman eta nahikoa goiz ohartaraz dezake + +**Bestela:** erabiltzaile gaiztoen sarrerak manipulatutako fitxategiak deitzeko erabiltzen den parametro batera jo dezake, adibidez, aurretik fitxategi sisteman kargatutako fitxategietara edo lehendik sisteman bazeuden fitxategietara sartzeko + +🔗 [**Gehiago irakurri: moduluaren karga segurua**](/sections/security/safemoduleloading.md) + +

+ +## ![✔] 6.18. Exekutatu kode ez segurua sandbox batean + + + +**TL;PL:** exekuzio garaian ematen den kanpoko kodea exekutatu behar duzunean (adibidez, plugina), erabili kode nagusia isolatu eta pluginetik babesten duen 'sandbox' tankerako edozein exekuzio ingurune mota. Hori lor daiteke prozesu dedikatu baten bidez (adibidez, `cluster.fork()`), zerbitzaririk gabeko ingurune bat erabiliz edo sandbox bat balitz bezala jokatzen duten npm pakete dedikatuak erabiliz + +**Bestela:** plugin batek bide ugari erabil ditzake erasotzeko, hala nola begizta infinituak erabiliz, memoria gainkargatuz eta prozesu ingurune eraso errazen aldagaiak eskuratuz + +🔗 [**Gehiago irakurri: exekutatu kode ez segurua sandbox batean**](/sections/security/sandbox.md) + +

+ +## ![✔] 6.19. Kontu handia izan bigarren mailako prozesuekin lan egitean + + + +**TL;PL:** ahal dela, saihestu bigarren mailako prozesuak, eta, hala behar izanez gero, balioztatu eta garbitu sarrera, shell injekzioko erasoak arintzeko. Hobetsi `child_process.execFile` fitxategia, definizioz komando bakarra exekutatuko duena atributu multzo batekin eta shell parametroen hedapena onartuko ez duena + +**Bestela:** bigarren mailako prozesuak ganorarik gabe erabiltzeak urruneko komandoen exekuzioa edo shell injekzioko erasoak eragin ditzake, desinfektatu gabeko sistema komando batera erabiltzaile gaiztoren bat sartu dela eta + +🔗 [**Gehiago irakurri: kontuz ibili bigarren mailako prozesuekin lan egitean**](/sections/security/childprocesses.md) + +

+ +## ![✔] 6.20. Ezkutatu bezeroen erroreen xehetasunak + + + +**TL;PL:** errore integratuen kudeatzaile lasterrek lehenespenez ezkutatzen dituzte erroreen xehetasunak. Haatik, aukera handia dago inplementa dezan errore pertsonalizatuak dituzten objektuak kudeatzeko berak daukan logika (batzuen ustez jardunbide egokia dena). Hala eginez gero, ziurtatu bezeroari errorearen objektu osoa ez itzultzea, horrek aplikazioen datu sentikorrak izan litzake eta + +**Bestela:** aplikazioaren xehetasun sentikorrak —hala nola, zerbitzariko fitxategien bideak, erabiltzen ari diren hirugarrenen moduluak eta erasotzaile batek balia ditzakeen aplikazioaren barneko beste lan fluxuak— atera daitezke pila aztarna batean aurkitutako informazioetatik + +🔗 [**Gehiago irakurri: ezkutatu bezeroaren erroreen xehetasunak**](/sections/security/hideerrors.md) + +

+ +## ![✔] 6.21. Konfiguratu 2FA npm edo Yarn-entzat + + + +**TL;PL:** garapen katearen edozein urrats MFArekin (faktore anitzeko autentifikazioarekin) babestu behar da. Iza ere, npm / Yarn aukera paregabea da garatzaile batzuen pasahitza eskuratu nahi duten erasotzaileentzat. Garatzaileen egiaztagiriak erabiliz, erasotzaileek kode gaiztoa txerta dezakete proiektu eta zerbitzuetan instalatuta dauden liburutegietan, eta, agian, sarean bertan ere, jendaurrean argitarauta badago. npm-n autentifikazioa 2 faktore bidez egin beharra ezartzeak ia zero aukera uzten die erasotzaileei zure pakete kodea aldatzeko + +**Bestela:** [ba al duzu pasahitza bahitu zuten eslint garatzailearen berri?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8) + +

+ +## ![✔] 6.22. Aldatu saioko middlewarearen ezarpenak + + + +**TL;PL:** web esparru eta teknologia bakoitzak bere ahulguneak ditu: erasotzaileei esatea zein web esparru erabiltzen dugun laguntza handia da haientzat. Saioaren middlewareen ezarpen lehenetsiak erabiltzeak eragin dezake zure moduluko eta esparruko berariazko bahiketa erasoak izatea zure aplikazioak, `X-Powered-By` izenburukoaren antzekoak. Saiatu ezkutatzen zure pila teknologkoa identifikatzen eta agerian uzten duen edozein gauza (adibidez, Node.js, express) + +**Bestela:** cookieak segurtasunik gabeko konexioen bidez bidal litezke, eta erasotzaile batek saioaren identifikazioa erabil lezake web aplikazioaren barruko esparrua eta moduluen berariazko ahultasunak ere identifikatzeko + +🔗 [**Gehiago irakurri: cookieak eta saioaren segurtasuna**](/sections/security/sessions.md) + +

+ +## ![✔] 6.23. Saihestu DOS erasoak prozesu batek noiz huts egin behar duen berariaz ezarriz + + + +**TL;PL:** Node prozesuak huts egingo du akatsak kudeatzen ez direnean. Jardunbide egokienetako askok irtetea gomendatzen dute, akats bat atzeman eta kudeatuta badago ere. Expressek, adibidez, huts egiten du errore asinkronoren bat izanez gero –blokeatze klausula batekin ibilbideak biltzen ez badituzu behintzat. Horrek oso eraso bide aproposa irekitzen die erasotzaileei, zer informaziok eragiten duen prozesuaren blokeoa jakinda, behin eta berriz eskaera bera bidaltzen baitute prozesua blokeatzea lortu arte. Horretarako ez dago berehalako erremediorik, baina teknika batzuek mina arindu dezakete: abisatu zorroztasun kritikoarekin, kontrolatu gabeko errore baten ondorioz prozesuak huts egiten duen bakoitzean, balioztatu sarrera eta saihestu prozesua blokeatuta gelditzea erabiltzailearen sarrera baliogabea delako, bildu ibilbide guztiak cacth batekin eta kontuan hartu prozesuak ez duela huts egin behar eskaera batean errore bat sortzen denean (oro har, gertatzen denaren kontra) + +**Bestela:** hau uste oneko suposizio soil bat besterik ez da. Node.js aplikazio asko edukiz gero, JSON gorputz huts bat POST eskaera guztietara pasatzen saiatzen bagara, zenbait aplikazio blokeatu egingo dira. Une horretan, eskaera bera berbidal dezakegu, aplikazioak erraz ezabatzeko + +

+ +## ![✔] 6.24. Saihestu birbideratze ez seguruak + + + +**TL;PL:** erabiltzaileen sarrerak balioztatzen ez dituzten birbideratzeek ahalbidetzen dute erasotzaileek phishing iruzurrak abiatzea, erabiltzaileen egiaztagiriak lapurtzea eta beste ekintza kaltegarri batzuk burutzea + +**Bestela:** erasotzailea ohartzen bada erabiltzaileek emandako kanpo sarrerarik ez dela balioztatzen, ahultasun hori balia dezake foroetan, sare sozialetan eta beste toki publiko batzuetan hartarako bereziki sortutako estekak argitaratzean, erabiltzaileek bertan klik egin dezaten + +🔗 [**Gehiago irakurri: saihestu birbideratze ez seguruak**](/sections/security/saferedirects.md) + +

+ +## ![✔] 6.25. Saihestu sekretuak npm erregistroan argitaratzea + + + +**TL;PL:** neurriak hartu behar dira npm erregistro publikoetan sekretuak nahi gabe argitaratzeko arriskua ekiditeko. Erabil daiteke `.npmignore` fitxategi bat karpeta edo fitxategi espezikoak zerrenda beltz batean jartzeko eta `files` matrizea `package.json` artxiboarekin erabil daiteke zerrenda zuri moduan lan egin dezan + +**Bestela:** arriskua dago norbaitek zure proiektuaren API gakoak, pasahitzak edo beste sekretu batzuk aurkitu eta erasoak egiten saiatzeko, eta horrek galera ekonomikoak, nortasun arazoak eta bestelako arriskuak sor ditzake + +🔗 [**Gehiago irakurri: saihestu sekretuak argitaratzea**](/sections/security/avoid_publishing_secrets.md) +


+ +

⬆ Itzuli hasierara

+ +# `7. Zirriborroa: errendimendua` + +## Gure laguntzaileak lanean ari dira atal honetan. [Parte hartu nahi zenuke?](https://github.com/goldbergyoni/nodebestpractices/issues/256) + +

+ +## ![✔] 7.1. Ez blokeatu gertaeraren begizta + +**TL;PL:** saihestu PUZen zeregin intentsiboak, gertaeraren begizta blokeatuko baitute. Izan ere, gertaera horietako gehienak azpiprozesu bakarrekoak dira, eta deskargatuak izango baitira azpiprozesu dedikatu batean, prozesu batean edo teknologia desberdinetan, dauden testuinguruaren arabera + +**Bestela:** gertaeraren begizta blokeatuta dagoenez, Node.jsk ezin izango du beste eskaera bat kudeatu eta, ondorioz, atzerapena eragin diezaieke erabiltzaileei. **3000 erabiltzaile erantzunaren zain daude, edukia zerbitzatzeko prest dago, baina eskaera bakar batek emaitzak berriro bidaltzea galarazten dio zerbitzariari** + +🔗 [**Gehiago irakurri: ez blokeatu gertaeraren begizta**](/sections/performance/block-loop.md) + +


+ +## ![✔] 7.2. Hobetsi jatorrizko JS metodoak Lodash bezalako erabiltzailearen baliabideak baino + +**TL;PL:** askotan zorrotzagoa da `lodash` eta `underscore` bezalako baliabide liburutegiak erabiltzea jatorrizko metodoak baino, beharrezkoak ez diren menpekotasunak eragin eta abiadura moteltzen baitu. Gogoan izan, V8 motor berria ES estandar berriekin batera, bertako metodoak hobetu egin zirela, eta gaur egun baliabide liburutegiak % 50 inguru eraginkorragoak direla liburutegi publikoak baino + +**Bestela:** errendimendu txikiagoko proiektuak mantendu beharko zenituzke, non **dagoeneko** eskura zenuena erabili beharko baitzenuke edo, fitxategi batzu gehiagoren truke, beste zenbait lerro landu + +🔗 [**Gehiago irakurri: erabiltzaileen jatorrizko baliabideak**](/sections/performance/nativeoverutil.md) + +


+ +

⬆ Itzuli hasierara

+ +# `8. Docker` + +🏅 Mila esker [Bret Fisher](https://github.com/BretFisher)-i, ondorengo praktika hauetako asko ikasi baikenituen berarengandik + +

+ +## ![✔] 8.1 Erabili etapa anitzeko konpilazioak Docker irudi finagoak eta seguruagoak lortzeko + +**TL;PL:** erabili etapa anitzeko konpilazioak beharrezko produkzio objektuak soilik kopiatzeko. Konpilazio menpekotasun eta fitxategi asko ez dira beharrezkoak zure aplikazioa exekutatzeko. Etapa anitzeko konpilazioak erabiliz gero, baliabide horiek konpilazioan zehar erabil daitezke, denboraren exekuzio inguruneak beharrezko baliabideak besterik ez duen bitartean. Etapa anitzeko konpilazioak oso modu erraza dira gehiegizko pisua kendu eta segurtasun mehatxuak saihesteko + +**Bestela:** irudi handiagoek denbora gehiago beharko dute konpilatzeko eta zabaltzeko. Eraikitzeko soilik diren tresnek ahultasunak eduki ditzakete eta eraikitze faserako soilik gordetako sekretuak filtratu daitezke + +### Etapa anitzeko eraikuntzetarako Dockerfile adibidea + +```dockerfile +FROM node:14.4.0 AS build + +COPY . . +RUN npm ci && npm run build + +FROM node:slim-14.4.0 + +USER node +EXPOSE 8080 + +COPY --from=build /home/node/app/dist /home/node/app/package.json /home/node/app/package-lock.json ./ +RUN npm ci --production + +CMD [ "node", "dist/app.js" ] +``` + +🔗 [**Gehiago irakurri: erabili etapa anitzeko konpilazioak**](/sections/docker/multi_stage_builds.md) + +


+ +# Edukiontzia autoabiatu node komandoa erabiliz, npm beharrean + +## ![✔] 8.2. Edukiontzia abiarazi 'node' komandoa erabiliz, saihestu npm hastea + +**TL;PL:** erabili `CMD ['node','server.js']` aplikazioa abiarazteko, saihestu OS seinaleak kodera pasatzen ez dituzten npm scriptak erabiltzea. Horrek arazoak izatea ekiditen du bigarren mailako prozesuetan, seinaleak kudeatzean, itxiera seguruetan eta prozesu zonbietan + +**Bestela:** seinalerik pasatzen ez denean, zure kodeak ez du inoiz izango itzalaldien berri, eta, hori gabe, ez da behar bezala itxiko, unean uneko eskaerak eta / edo datuak galduz + +[**Gehiago irakurri: Edukiontzia abiarazi 'node' komandoa erabiliz, sahiestu npm hastea**](/sections/docker/bootstrap-using-node.md) + +


+ +## ![✔] 8.3. Utzi Dockerren exekuzio denborak kudea ditzala erreplikazioa eta aktibitatea + +**TL;PL:** Dockerren exekuzio denboraren orkestratzailea erabiltzen duzunean (adibidez, Kubernetes), deitu Node.js prozesua zuzenean, prozesua errepikatzen duten bitarteko prozesuen kudeatzailerik edo koderik pertsonalizatu gabe (adibidez, PM2, Cluster modulua). Exekuzio denboraren plataformak datu kopuru eta ikusgarritasun handiena dauzka kokapenari buruzko erabakiak hartzeko: badaki zenbat prozesu behar diren, nola antolatu prozesuok eta zer egin huts eginez gero + +**Bestela:** edukiontziak huts egiten jarraituko du baliabide faltagatik, eta prozesuen kudeatzaileak behin eta berriro berrabiaraziko du, gelditu gabe. Kubernetes horretaz jabetuko balitz, beste toki zabal batera lekualda lezake + +🔗 [**Gehiago irakurri: utzi Dockerren orkestratzaileari prozesuak berrabiaraz eta erreplika ditzala**](/sections/docker/restart-and-replicate-processes.md) + +


+ +## ![✔] 8.4. Erabili .dockerignore sekretuak filtratzea ekiditeko + +**TL;DR**: erabili `.dockerignore` fitxategia, fitxategi sekretu arruntak eta garapeneko objektuak iragazten ditu eta. Horrela, sekretuak irudira ez sartzea lor dezakezu. Eta onura gehigarri bat izango duzu: eraikitzeko denbora nabarmen murriztuko da. Gainera, ziurtatu fitxategi guztiak ez direla behin eta berriro kopiatzen eta berariaz aukeratu zer kopiatu behar den Dockerren + +**Bestela**: irudira sarbidea duen edonorekin partekatuko dira `.env`, `.aws` eta `.npmrc` bezalako fitxategi sekretu pertsonal arruntak (adibidez, Docker biltegia) + +🔗 [**Gehiago irakurri: erabili .dockerignore**](/sections/docker/docker-ignore.md) + +


+ +## ![✔] 8.5. Garbitu menpekotasunak ekoizpenaren aurretik + +**TL;PL:** nahiz eta dev-menpekotasunak (dev-dependencies) batzuetan eraikuntza eta probako bizitza zikloan zehar beharrezkoak izan, azkenean ekoizpenera bidaltzen den irudiak ahalik eta txikiena izan behar du eta ez du garapeneko menpekotasunik eduki behar. Hori eginez gero, beharrezko kodea soilik bidaliko dela eta balizko erasoen kopurua (hau da, erasoaren azalera) minimizatuko dela bermatzen da, eta, hori lor daiteke menpekotasun guztiak lehenik instalatuz eta azkenean `npm ci --production` exekutatuz, beti ere etapa anitzeko eraikuntza erabiltzen denean (ikusi buleta dedikatua) + +**Bestela:** npm segurtasun arau hauste ezagun asko garapen paketeen barruan aurkitu izan dira (adibidez, [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes)) + +🔗 Gehiago irakurri: [kendu garapen menpekotasunak](/sections/docker/install-for-production.md) + +


+ +## ![✔] 8.6. Itzali arazorik gabe eta dotore + +**TL;PL:** kudeatu prozesuaren SIGTERM gertaera eta garbitu lehendik dauden konexio eta baliabide guztiak. Hori etengabeko eskaerei erantzutean egin behar da. Dockerized exekutatzen den bitartean edukiontziak ixtea ez da arraroa, baizik eta ohiko lanaren zati gisa maiz gertatzen den zerbait. Hori lortzeko ondo pentsatutako kodea prestatu beharra dago hainbat elementu koordinatuz: karga orekatzailea, mantentze konexioak, HTTP zerbitzaria eta beste baliabide batzuk + +**Bestela:** berehala hiltzeak etsita dauden milaka erabiltzaileri ez erantzutea ekarriko du + +🔗 [**Gehiago irakurri: itzalaldi dotorea**](/sections/docker/graceful-shutdown.md) + +


+ +## ![✔] 8.7. Ezarri memoria mugak Docker eta v8 erabiliz + +**TL;PL:** konfiguratu beti memoria muga bai Docker bai JavaScript exekuzio adierazgailak erabiliz. Dockerren muga beharrezkoa da edukiontzien kokapena erabakitzeko; --v8ren bandera max-old-space beharrezkoa da GC garaiz abiarazteko eta memoria erabiltzea saihesteko. Praktikan, ezarri v8rren espazio memoria zaharra edukiontziaren muga baino apur bat txikiagoa izan dadin + +**Bestela:** Dockerren definizioa beharrezkoa da eskalatutako erabakiak burutzeko eta beste herritarrak gosez hiltzea ekiditeko. V8rren mugak zehaztu gabe ere, edukiontziaren baliabideak erabiliko ditu. Argibide espliziturik gabe, baliabideen %50-60a erabiltzean huts egiten du + +🔗 [**Gehiago irakurri: ezarri memoria mugak Docker erabiliz soilik**](/sections/docker/memory-limit.md) + +


+ +## ![✔] 8.8. Planifikatu cachean biltegiratzea modu eraginkorrean + +**TL;PL:** Dockerren irudi osoa cache-tik berreraikitzea ia berehalakoa izan daiteke, zuzen eginez gero. Eguneratu ez diren argibideek Dockerfile fitxategiaren goialdean egon behar dute, eta etengabe aldatzen ari direnek (aplikazioaren kodea, esate baterako) beheko aldean egon behar dute + +**Bestela:** Docker eraikitzeak oso luze jo dezake eta baliabide asko kontsumituko ditu, nahiz eta aldaketa txikiak egin + +🔗 [**Gehiago irakurri: baliatu cachea eraikitze denborak murrizteko**](/sections/docker/use-cache-for-shorter-build-time.md) + +


+ +## ![✔] 8.9. Erabili irudiaren erreferentzia esplizitua, saihestu azken (`latest`) + +etiketa + +**TL;PL:** zehaztu irudi laburpen esplizitu bat edo etiketa baten bertsioa, inoiz ez aipatu `latest`. Garatzaileek sarritan uste izaten dute, `latest` adieraziz gero, biltegiko azken irudia eskuratuko dutela, baina ez da horrela. Laburpena erabiltzeak zerbitzuaren instantzia guztiek kode bera exekutatuko dutela bermatzen du + +Gainera, irudi etiketa bat aipatzen bada, oinarrizko irudia aldatu egin daiteke, ez baitago irudi etiketekin fidatzerik instalazio determinista bat egiteko orduan. Horren ordez, instalazioa determinista izanez gero, SHA256 laburpena erabil daiteke irudi zehatza erreferentziatzeko + +**Bestela:** oinarrizko irudi baten bertsio berri bat erabiliz gero, aldaketa handiak gerta litezke produkzioan, horrek aplikazioaren nahigabeko portaera sortuz + +🔗 [**Gehiago irakurri: ulertu irudi etiketak eta erabili "latest" etiketa kontu handiz**](/sections/docker/image-tags.md) + +


+ +## ![✔] 8.10. Hobetsi Docker oinarrizko irudi txikiagoak + +**TL;PL:** irudi handiek ahultasun gehiago izateko arriskua handitu eta baliabideen kontsumoa areagotzen dute. Docker irudi arinagoak erabiltzeak, Slim eta Alpine Linux aldaerak adibidez, arazo hori arindu egiten du + +**Bestela:** batetik, denbora gehiago beharko da irudiak eraiki, txertatu eta ateratzeko; bestetik, erabiltzaile maltzurrek eraso bektore ezezagunak erabil ditzakete; eta, azkenik, baliabide gehiago beharko dira + +🔗 [**Gehiago irakurri: hobetsi irudi txikiagoa**](/sections/docker/smaller_base_images.md) + +


+ +## ![✔] 8.11. Garbitu eraikitze faseko sekretuak, saihestu sekretuak argudioetan + +**TL;PL:** saihestu Dockerren konpilazio inguruneko sekretuak agerian geratzea. Docker irudi bat IE bezalako ingurune anitzetan eta ekoizpena bezain garbituta ez dauden erregistroetan partekatzen da normalean. Adibide tipikoa npm token da, normalean dockerfile batera pasatzen dena argumentu gisa. Token hori irudiaren barruan geratzen da denbora luzez beharrezkoa izateari utzi ondoren ere, eta erasotzaileari npm erregistro pribatura sartzeko aukera ematen dio. Hori ekidin daiteke sekretua `.npmrc` bezalako fitxategi batean kopiatuz, eta, ondoren, sekretu hori kenduz etapa anitzeko eraikuntza bat erabiliz (kontuz, eraikitze historia ere ezabatu beharko litzateke) edo bat ere aztarnarik uzten dituen Docker build-kit funtzio sekretua erabiliz + +**Bestela:** IE eta docker erregistroan sartzeko aukera duten guztiek erakundearen sekretu preziatuak ere eskuratzeko aukera izango dute onura gehigarri gisa + +🔗 [**Gehiago irakurri: garbitu eraikitze faseko sekretuak**](/sections/docker/avoid-build-time-secrets.md) + +


+ +## ![✔] 8.12. Eskaneatu irudiak ahultasun geruzen bila + +**TL;PL:** kode menpekotasunen ahultasunak egiaztatzeaz gain, eskaneatu ekoizpenera bidalitako azken irudia ere. Dockerren irudien eskanerrek kodeen menpekotasunak egiaztatzen dituzte, baina baita sistema eragilearen binarioak ere. E2E segurtasun eskaneatze horrek eremu handiago bat hartzen du eta egiaztatzen du inongo erabiltzaile maltzurrak ez duela maltzurkeriatik egin eraikitze aldian zerbait injektatuz. Ondorioz, hau exekutatzea gomendatzen da hedapenaren aurreko azken urrats gisa. Mordoska bat eskaner doako eta komertzial dago CI / CD pluginak ere eskaintzen dituztenak + +**Bestela:** baliteke zure kodeak ahultasunik ez izatea. Hala ere, baliteke oraindik ere hackeatua izatea, aplikazioek normalean erabiltzen dituzten sistema eragilearen mailako binarioen bertsioak ahultasunak dituelako (adibidez, OpenSSL, TarBall) + +🔗 [**Gehiago irakurri: Dockerren praktika arruntak**](/sections/docker/scan-images.md) + +


+ +## ![✔] 8.13 Garbitu NODE_MODULE cachea + +**TL;PL:** menpekotasunak edukiontzi batean instalatu ondoren, kendu bertako cachea. Ez du inolako zentzurik etorkizuneko instalazio azkarragoetarako menpekotasunak bikoizteak, ez baita beste instalaziorik egingo: Dockeren irudiak aldaezinak dira. Kode lerro bakarra erabiliz dozenaka MB aurrezten dira (normalean, irudiaren tamainaren % 10-50) + +**Bestela:** ekoizpenera bidaliko den irudiak % 30 gehiago pisatuko du, inoiz erabiliko ez diren fitxategiak direla eta + +🔗 [**Gehiago irakurri: garbitu NODE_MODULE cachea**](/sections/docker/clean-cache.md) + +


+ +## ![✔] 8.14. Dockeren praktika arruntak + +**TL;PL:** hemen duzu Node.jsekin zuzenean loturarik ez duen Docker aholkuen bilduma. Ez dago alderik Noderen eta beste edozein lengoaiaren inplementazioen artean. Egin klik “irakurri gehiago” botoian + +🔗 [**Gehiago irakurri: Dockeren praktika arruntak**](/sections/docker/generic-tips.md) + +


+ +## ![✔] 8.15. Garbitu zure Dockerfilea + +**TL;PL:** Linterra erabiliz zure Dockerfilea garbitzea urrats garrantzitsua da haren barruan jardunbide egokiak errespetatzen ez dituzten arazoak identifikatzeko. Docker linter espezializatu bat erabiliz errendimendu eta segurtasun hobekuntzak erraz antzematen dira, alferrikako ordu ugari aurreztea edo produkzio kodean segurtasun arazoak murriztea lortuz + +**Bestela:** okerrez, Dockerfileren sortzaileak root bat utzi zuen produkzio erabiltzaile moduan, eta jatorri ezezaguneko biltegi irudi bat ere erabili zuen. Hori liner soil batekin ekidin liteke. + +🔗 [**Gehiago irakurri: garbitu zure Dockerfilea**](/sections/docker/lint-dockerfile.md) + +


+ +

⬆ Itzuli hasierara

+ +# Mugarriak + +Gida hau mantentzeko eta eguneratuta egoteko, jarraibideak eta jardunbide egokiak eguneratzen eta hobetzen ari gara etengabe komunitatearen laguntzarekin. Proiektu honetan lagundu nahi baduzu, jarraitu gure [mugarriak](https://github.com/goldbergyoni/nodebestpractices/milestones) jarrai sartu lantaldeetan + +
+ +## Itzulpenak + +Komunitatearen ekarpena dira hemengo itzulpen guztiak eman. Oso pozik hartuko genituzke zure itzulpenak, bai dagoeneko eginda dauden testuenak zein egiten ari garen eta egingo ditugunenak + +### Amaitutako itzulpenak + +- ![BR](/assets/flags/BR.png) [Brasilgo portugalera](./README.brazilian-portuguese.md) - [Marcelo Melo](https://github.com/marcelosdm)-ren eskutik +- ![CN](/assets/flags/CN.png) [Txinera](./README.chinese.md) - [Matt Jin](https://github.com/mattjin)-ren eskutik +- ![RU](/assets/flags/RU.png) [Errusiera](./README.russian.md) - [Alex Ivanov](https://github.com/contributorpw)-ren eskutik +- ![PL](/assets/flags/PL.png) [Poloniera](./README.polish.md) - [Michal Biesiada](https://github.com/mbiesiad)-ren eskutik + +### Aribidean dauden itzulpenak + +- ![FR](/assets/flags/FR.png) [Frantsesa](https://github.com/gaspaonrocks/nodebestpractices/blob/french-translation/README.french.md) ([Eztabaidan](https://github.com/goldbergyoni/nodebestpractices/issues/129)) +- ![HE](/assets/flags/HE.png) Hebrearra ([Eztabaidan](https://github.com/goldbergyoni/nodebestpractices/issues/156)) +- ![KR](/assets/flags/KR.png) [Koreera](README.korean.md) - [Sangbeom Han](https://github.com/uronly14me)-ren eskutik ([Eztabaidan](https://github.com/goldbergyoni/nodebestpractices/issues/94)) +- ![ES](/assets/flags/ES.png) [Gaztelera](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Eztabaidan](https://github.com/goldbergyoni/nodebestpractices/issues/95)) +- ![TR](/assets/flags/TR.png) Turkiera ([Eztabaidan](https://github.com/goldbergyoni/nodebestpractices/issues/139)) +- ![EU](/assets/flags/EU.png) [Euskara](README.basque.md) - [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuestaren eskutik ([Eztabaidan](https://github.com/goldbergyoni/nodebestpractices/issues/842)) + +

+ +## Zuzendaritza Batzordea + +Ezagutu Zuzendaritza Batzordeko kideak, proiektuaren orientazioa eta etorkizunerako jarraibideak emateko elkarlanean dirautenak. Gainera, batzordeko kide bakoitza gure [Github projects](https://github.com/goldbergyoni/nodebestpractices/projects)-pean dagoen proiektu baten buru da + + + +[Yoni Goldberg](https://github.com/goldbergyoni) + + + +EEBB-etan, Europan eta Israelen, bezeroekin tamaina handiko Node.js aplikazioen sorkuntzan lan egiten duen Node.jsen inguruko aholkulari independentea. Gida honetako jardunbide egoki asko lehenengo aldiz [goldbergyoni.com](https://goldbergyoni.com)-en argitaratuak izan ziren. Jar zaitez Yoni-rekin kontatuan [@goldbergyoni](https://github.com/goldbergyoni)-en edo [me@goldbergyoni.com](mailto:me@goldbergyoni.com) helbidearen bidez + +
+ + + +[Bruno Scheufler](https://github.com/BrunoScheufler) + + +💻 full-stack web ingeniaria, Node.js eta GraphQL zalea + +
+ + + +[Kyle Martin](https://github.com/js-kyle) + + + +Full Stack Garatzailea eta Zelanda Berrian lan egiten duen Site Reliability Ingeniaria, web aplikazioen segurtasutasunean eta egituraketan, eta tamaina handiko Node.js aplikazioen sorkuntzan interesa du + +
+ + + +[Kevyn Bruyere](https://github.com/kevynb) + + +Full-stack garatzaile independentea, Ops eta automatizazioan zaletua dena + +
+ +### Steering Committee Emeriti + + + +[Sagir Khan](https://github.com/sagirk) + + + + +Javascripten eta bere ekosisteman (React, Node.js, TypeScript, GraphQL, MongoDB, eta sistemako JS/JSON edozein geruzatan eragin dezakeen edozer) aditua, munduko marka ezagunenetarako produktuak sortzen ditu web plataforma erabiliaz. Node.js Fundazioko Banakako Kidea + +
+ +## Languntzaileak + +Mila esker gure laguntzaile guztiei! 🙏 + +Gure kolaboratzaileak proiektuan maiz parte hartzen duten kideak dira, jardunbide egokiak proposatuz, gaien zerrenda ordenatuz, parte hartze eskaerak (pull request) aztertuz... Milaka pertsona Node.js aplikazioak hobeto sortzen laguntzen interesa baduzu, irakur ezazu gure [kolaboratzaile gida](/.operations/CONTRIBUTING.md) 🎉 + +| | | +| :---------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: | +| [Ido Richter (Fundatzailea)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | + +### Emeriti Kolaboratzailea + +| | +| :-------------------------------------------------------------------------------------------------------------------------: | +| [Refael Ackermann](https://github.com/refack) | + +
+ +## Parte hartu + +Open sourcen parte hartu nahi baduzu, hemen duzu aukera! Gehiago jakiteko, irakurri [parte hartu dokumentua](.operations/CONTRIBUTING.md) + +## Parte hartzaileak ✨ + +Eskerrik asko proiektu honetan parte hartu duten pertsona zoragarriei! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Kevin Rambaud

🖋

Michael Fine

🖋

Shreya Dahal

🖋

Matheus Cruz Rocha

🖋

Yog Mehta

🖋

Kudakwashe Paradzayi

🖋

t1st3

🖋

mulijordan1976

🖋

Matan Kushner

🖋

Fabio Hiroki

🖋

James Sumners

🖋

Dan Gamble

🖋

PJ Trainor

🖋

Remek Ambroziak

🖋

Yoni Jah

🖋

Misha Khokhlov

🖋

Evgeny Orekhov

🖋

-

🖋

Isaac Halvorson

🖋

Vedran Karačić

🖋

lallenlowe

🖋

Nathan Wells

🖋

Paulo Reis

🖋

syzer

🖋

David Sancho

🖋

Robert Manolea

🖋

Xavier Ho

🖋

Aaron

🖋

Jan Charles Maghirang Adona

🖋

Allen

🖋

Leonardo Villela

🖋

Michał Załęcki

🖋

Chris Nicola

🖋

Alejandro Corredor

🖋

cwar

🖋

Yuwei

🖋

Utkarsh Bhatt

🖋

Duarte Mendes

🖋

Jason Kim

🖋

Mitja O.

🖋

Sandro Miguel Marques

🖋

Gabe

🖋

Ron Gross

🖋

Valeri Karpov

🖋

Sergio Bernal

🖋

Nikola Telkedzhiev

🖋

Vitor Godoy

🖋

Manish Saraan

🖋

Sangbeom Han

🖋

blackmatch

🖋

Joe Reeve

🖋

Ryan Busby

🖋

Iman Mohamadi

🖋

Sergii Paryzhskyi

🖋

Kapil Patel

🖋

迷渡

🖋

Hozefa

🖋

Ethan

🖋

Sam

🖋

Arlind

🖋

Teddy Toussaint

🖋

Lewis

🖋

Gabriel Lidenor

🖋

Roman

🖋

Francozeira

🖋

Invvard

🖋

Rômulo Garofalo

🖋

Tho Q Luong

🖋

Burak Shen

🖋

Martin Muzatko

🖋

Jared Collier

🖋

Hilton Meyer

🖋

ChangJoo Park(박창주)

🖋

Masahiro Sakaguchi

🖋

Keith Holliday

🖋

coreyc

🖋

Maximilian Berkmann

🖋

Douglas Mariano Valero

🖋

Marcelo Melo

🖋

Mehmet Perk

🖋

ryan ouyang

🖋

Shabeer

🖋

Eduard Kyvenko

🖋

Deyvison Rocha

🖋

George Mamer

🖋

Konstantinos Leimonis

🖋

Oliver Lluberes

🌍

Tien Do

🖋

Ranvir Singh

🖋

Vadim Nicolaev

🖋 🌍

German Gamboa Gonzalez

🖋

Hafez

🖋

Chandiran

🖋

VinayaSathyanarayana

🖋

Kim Kern

🖋

Kenneth Freitas

🖋

songe

🖋

Kirill Shekhovtsov

🖋

Serge

🖋

keyrwinz

🖋

Dmitry Nikitenko

🖋

bushuai

👀 🖋

Benjamin Gruenbaum

🖋

Ezequiel

🌍

Juan José Rodríguez

🌍

Or Bin

🖋

Andreo Vieira

🖋

Michael Solomon

🖋

Jimmy Callin

🖋

Siddharth

🖋

Ryan Smith

🖋

Tom Boettger

🖋

Joaquín Ormaechea

🌍

dfrzuz

🌍

Victor Homyakov

🖋

Josh

🖋 🛡️

Alec Francis

🖋

arjun6610

🖋

Jan Osch

🖋

Thiago Rotondo Sampaio

🌍

Alexsey

🖋

Luis A. Acurero

🌍

Lucas Romano

🌍

Denise Case

🖋

Nick Ribal

🖋

0xflotus

🖋

Jonathan Chen

🖋

Dilan Srilal

🖋

vladthelittleone

🌍

Nik Osvalds

🖋

Daniel Kiss

📖
+ + + + + diff --git a/README.brazilian-portuguese.md b/README.brazilian-portuguese.md index 7b867519..48fb6e23 100644 --- a/README.brazilian-portuguese.md +++ b/README.brazilian-portuguese.md @@ -18,7 +18,7 @@
-Leia em diferentes idiomas: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), [![BR](/assets/flags/BR.png)**BR**](/README.brazilian-portuguese.md) [(![ES](/assets/flags/ES.png)**ES**, ![FR](/assets/flags/FR.png)**FR**, ![HE](/assets/flags/HE.png)**HE**, ![KR](/assets/flags/KR.png)**KR**, ![RU](/assets/flags/RU.png)**RU** e ![TR](/assets/flags/TR.png)**TR** em progresso!)](#translations) +Leia em diferentes idiomas: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), [![BR](/assets/flags/BR.png)**BR**](/README.brazilian-portuguese.md) [(![ES](/assets/flags/ES.png)**ES**, ![FR](/assets/flags/FR.png)**FR**, ![HE](/assets/flags/HE.png)**HE**, ![KR](/assets/flags/KR.png)**KR**, ![RU](/assets/flags/RU.png)**RU**, ![TR](/assets/flags/TR.png)**TR** e ![EU](/assets/flags/EU.png)**EU** em progresso!)](#translations)](#translations)
@@ -257,8 +257,7 @@ function someFunction() { } // Avoid -function someFunction() -{ +function someFunction() { // code block } ``` @@ -275,7 +274,7 @@ Não importa se você usa ponto-e-vírgula ou não para separar suas declaraçõ **TL;DR:** Use o ESLint para obter conhecimento sobre as preocupações de separação. [Prettier](https://prettier.io/) ou [Standardjs](https://standardjs.com/) podem resolver automaticamente esses problemas. -**Otherwise:** Como visto na seção anterior, o interpretador do JavaScript adiciona automaticamente um ponto-e-vírgula ao final de uma instrução, se não houver uma, ou considera uma instrução como não terminada onde deveria, o que pode levar a alguns resultados indesejáveis. Você pode usar atribuições e evitar o uso de expressões de função chamadas imediatas para evitar a maioria dos erros inesperados. +**Caso contrário:** Como visto na seção anterior, o interpretador do JavaScript adiciona automaticamente um ponto-e-vírgula ao final de uma instrução, se não houver uma, ou considera uma instrução como não terminada onde deveria, o que pode levar a alguns resultados indesejáveis. Você pode usar atribuições e evitar o uso de expressões de função chamadas imediatas para evitar a maioria dos erros inesperados. ### Exemplo de Código @@ -335,11 +334,11 @@ class SomeClassExample {} // para nomes de constantes nós usamos a palavra const e lowerCamelCase const config = { - key: 'value' + key: "value", }; // para nomes de variáveis e funções nós usamos lowerCamelCase -let someVariableExample = 'value'; +let someVariableExample = "value"; function doSomething() {} ``` @@ -374,12 +373,12 @@ function doSomething() {} ```javascript // Do -module.exports.SMSProvider = require('./SMSProvider'); -module.exports.SMSNumberResolver = require('./SMSNumberResolver'); +module.exports.SMSProvider = require("./SMSProvider"); +module.exports.SMSNumberResolver = require("./SMSNumberResolver"); // Avoid -module.exports.SMSProvider = require('./SMSProvider/SMSProvider.js'); -module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolver.js'); +module.exports.SMSProvider = require("./SMSProvider/SMSProvider.js"); +module.exports.SMSNumberResolver = require("./SMSNumberResolver/SMSNumberResolver.js"); ```

@@ -393,18 +392,18 @@ module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolve ### Exemplo de Código ```javascript -'' == '0' // false -0 == '' // true -0 == '0' // true +"" == "0"; // false +0 == ""; // true +0 == "0"; // true -false == 'false' // false -false == '0' // true +false == "false"; // false +false == "0"; // true -false == undefined // false -false == null // false -null == undefined // true +false == undefined; // false +false == null; // false +null == undefined; // true -' \t\r\n ' == 0 // true +" \t\r\n " == 0; // true ``` Todas as declarações acima false se feitas com `===`. @@ -854,7 +853,7 @@ Todas as declarações acima false se feitas com `===`. **TL;DR:** Uma técnica simples e poderosa é limitar as tentativas de autorização usando duas métricas: - + 1. A primeiro é o número de tentativas consecutivas com falha do mesmo ID/nome e endereço IP exclusivos do usuário. 2. A segundo é o número de tentativas malsucedidas de um endereço IP durante um longo período de tempo. Por exemplo, bloqueie um endereço IP se ele fizer 100 tentativas com falha em um dia. @@ -1055,6 +1054,7 @@ Todas as traduções são contribuições da comunidade. Nós ficaremos felizes - ![RU](/assets/flags/RU.png) [Russo](https://github.com/goldbergyoni/nodebestpractices/blob/russian-translation/README.russian.md) ([Discussão](https://github.com/goldbergyoni/nodebestpractices/issues/454)) - ![ES](/assets/flags/ES.png) [Espanhol](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussão](https://github.com/goldbergyoni/nodebestpractices/issues/95)) - ![TR](/assets/flags/TR.png) Turco ([Discussão](https://github.com/goldbergyoni/nodebestpractices/issues/139)) +- ![EU](/assets/flags/EU.png) [Vasco](README.basque.md) - Cortesia de [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta ([Discussão](https://github.com/goldbergyoni/nodebestpractices/issues/842))

@@ -1109,14 +1109,14 @@ Obrigado a todos nossos colaboradores! 🙏 Nossos colaboradores são membros que estão contribuindo com o repositório em base regular, sugerindo novas práticas recomendadas, triando problemas, analisando solicitações de pull e muito mais. Se você estiver interessado em nos ajudar a orientar milhares de pessoas a criar melhores aplicações Node.js, leia nossas [diretrizes de colaborador](/.operations/CONTRIBUTING.md) 🎉 | | | -| :--: | :--: | -| [Ido Richter (Founder)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | +| :---------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: | +| [Ido Richter (Founder)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | ### Colaboradores anteriores | | -| :--: | -| [Refael Ackermann](https://github.com/refack) | +| :-------------------------------------------------------------------------------------------------------------------------: | +| [Refael Ackermann](https://github.com/refack) |
diff --git a/README.chinese.md b/README.chinese.md index 01c7ff41..8d302302 100644 --- a/README.chinese.md +++ b/README.chinese.md @@ -1,970 +1,983 @@ -[✔]: assets/images/checkbox-small-blue.png - -# Node.js 最佳实践 - -

- Node.js Best Practices -

- -
- -
- 82 items Last update: June 5, 2019 Updated for Node 12.4.0 LTS -
- -
- - [![nodepractices](/assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/) -
- -# 欢迎! 首先您应该知道的三件事情: -**1. 当您读到这里,实际上您读了很多关于Node.js的优秀文章 -** 这是对Node.js最佳实践中排名最高的内容的总结和分享 - -**2. 这里是最大的汇集,且每周都在增长 -** 当前,超过50个最佳实现,样式指南,架构建议已经呈现。每天都有新的issue和PR被创建,以使这本在线书籍不断更新。我们很乐于见到您能在这里做出贡献,不管是修复一些代码的错误,或是提出绝妙的新想法。请查看我们的[milestones](https://github.com/goldbergyoni/nodebestpractices/milestones?direction=asc&sort=due_date&state=open) - -**3. 大部分的条目包含额外的信息 -** 大部分的最佳实践条目的旁边,您将发现 **🔗Read More** 链接,它将呈现给您示例代码,博客引用和更多信息 - -


- -## [目录](#table-of-contents) -1. [项目结构实践 (5) ](#1-project-structure-practices) -2. [异常处理实践 (11) ](#2-error-handling-practices) -3. [编码规范实践 (12) ](#3-code-style-practices) -4. [测试和总体质量实践 (8) ](#4-testing-and-overall-quality-practices) -5. [进入生产实践 (16) ](#5-going-to-production-practices) -6. :star: 新: [安全实践(23)](#6-security-best-practices) -7. Performance Practices ([coming soon](https://github.com/goldbergyoni/nodebestpractices/milestones?direction=asc&sort=due_date&state=open)) - - -


-

1. 项目结构实践

- -## ![✔] 1.1 组件式构建你的解决方案 - - **TL;DR:** 大型项目的最坏的隐患就是维护一个庞大的,含有几百个依赖的代码库 - 当开发人员准备整合新的需求的时候,这样一个庞然大物势必减缓了开发效率。反之,把您的代码拆分成组件,每一个组件有它自己的文件夹和代码库,并且确保每一个组件小而简单。查看正确的项目结构的例子请访问下面的 ‘更多’ 链接。 - -**否则:** 当编写新需求的开发人员逐步意识到他所做改变的影响,并担心会破坏其他的依赖模块 - 部署会变得更慢,风险更大。当所有业务逻辑没有被分开,这也会被认为很难扩展 - -🔗 [**更多: 组件结构**](/sections/projectstructre/breakintcomponents.chinese.md) - -

- -## ![✔] 1.2 分层设计组件,保持Express在特定的区域 - -**TL;DR:** 每一个组件都应该包含'层级' - 一个专注的用于接入网络,逻辑,数据的概念。这样不仅获得一个清晰的分离考量,而且使仿真和测试系统变得异常容易。尽管这是一个普通的模式,但接口开发者易于混淆层级关系,比如把网络层的对象(Express req, res)传给业务逻辑和数据层 - 这会令您的应用彼此依赖,并且只能通过Express使用。 - -**否则:** 对于混淆了网络层和其它层的应用,将不易于测试,执行CRON的任务,其它非-Express的调用者无法使用 - -🔗 [**更多: 应用分层**](/sections/projectstructre/createlayers.chinese.md) - -

- -## ![✔] 1.3 封装公共模块成为NPM的包 - -**TL;DR:** 由大量代码构成的一个大型应用中,贯彻全局的,比如日志,加密和其它类似的公共组件,应该进行封装,并暴露成一个私有的NPM包。这将使其在更多的代码库和项目中被使用变成了可能。 - -**否则:** 您将不得不重造部署和依赖的轮子 - -🔗 [**更多: 通过需求构建**](/sections/projectstructre/wraputilities.chinese.md) - -

- -## ![✔] 1.4 分离 Express 'app' and 'server' - -**TL;DR:** 避免定义整个[Express](https://expressjs.com/)应用在一个单独的大文件里, 这是一个不好的习惯 - 分离您的 'Express' 定义至少在两个文件中: API声明(app.js) 和 网络相关(WWW)。对于更好的结构,是把你的API声明放在组件中。 - -**否则:** 您的API将只能通过HTTP的调用进行测试(慢,并且很难产生测试覆盖报告)。维护一个有着上百行代码的文件也不是一个令人开心的事情。 - -🔗 [**更多: 分离 Express 'app' and 'server'**](/sections/projectstructre/separateexpress.chinese.md) - -

- -## ![✔] 1.5 使用易于设置环境变量,安全和分级的配置 - - -**TL;DR:** 一个完美无瑕的配置安装应该确保 (a) 元素可以从文件中,也可以从环境变量中读取 (b) 密码排除在提交的代码之外 (c) 为了易于检索,配置是分级的。仅有几个包可以满足这样的条件,比如[rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) 和 [convict](https://www.npmjs.com/package/convict)。 - -**否则:** 不能满足任意的配置要求将会使开发,运维团队,或者两者,易于陷入泥潭。 - -🔗 [**更多: 配置最佳实践**](/sections/projectstructre/configguide.chinese.md) - -


- -

⬆ 返回顶部

- -

2. 错误处理最佳实践

- -## ![✔] 2.1 使用 Async-Await 和 promises 用于异步错误处理 - -**TL;DR:** 使用回调的方式处理异步错误可能是导致灾难的最快的方式(a.k.a the pyramid of doom)。对您的代码来说,最好的礼物就是使用规范的promise库或async-await来替代,这会使其像try-catch一样更加简洁,具有熟悉的代码结构。 - -**否则:** Node.js回调特性, function(err, response), 是导致不可维护代码的一个必然的方式。究其原因,是由于混合了随意的错误处理代码,臃肿的内嵌,蹩脚的代码模式。 - -🔗 [**更多: 避免回调**](/sections/errorhandling/asyncerrorhandling.chinese.md) - -

- -## ![✔] 2.2 仅使用内建的错误对象 - -**TL;DR:** 很多人抛出异常使用字符串类型或一些自定义类型 - 这会导致错误处理逻辑和模块间的调用复杂化。是否您reject一个promise,抛出异常或发出(emit)错误 - 使用内建的错误对象将会增加设计一致性,并防止信息的丢失。 - - -**否则:** 调用某些模块,将不确定哪种错误类型会返回 - 这将会使恰当的错误处理更加困难。更坏的情况是,使用特定的类型描述错误,会导致重要的错误信息缺失,比如stack trace! - -🔗 [**更多: 使用内建错误对象**](/sections/errorhandling/useonlythebuiltinerror.chinese.md) - -

- -## ![✔] 2.3 区分运行错误和程序设计错误 - -**TL;DR:** 运行错误(例如, API接受到一个无效的输入)指的是一些已知场景下的错误,这类错误的影响已经完全被理解,并能被考虑周全的处理掉。同时,程序设计错误(例如,尝试读取未定义的变量)指的是未知的编码问题,影响到应用得当的重启。 - -**否则:** 当一个错误产生的时候,您总是得重启应用,但为什么要让 ~5000 个在线用户不能访问,仅仅是因为一个细微的,可以预测的,运行时错误?相反的方案,也不完美 – 当未知的问题(程序问题)产生的时候,使应用依旧可以访问,可能导致不可预测行为。区分两者会使处理更有技巧,并在给定的上下文下给出一个平衡的对策。 - -🔗 [**更多: 运行错误和程序设计错误**](/sections/errorhandling/operationalvsprogrammererror.chinese.md) - -

- -## ![✔] 2.4 集中处理错误,不要在Express中间件中处理错误 - -**TL;DR:** 错误处理逻辑,比如给管理员发送邮件,日志应该封装在一个特定的,集中的对象当中,这样当错误产生的时候,所有的终端(例如 Express中间件,cron任务,单元测试)都可以调用。 - -**否则:** 错误处理的逻辑不放在一起将会导致代码重复和非常可能不恰当的错误处理。 - -🔗 [**更多: 集中处理错误**](/sections/errorhandling/centralizedhandling.chinese.md) - -

- -## ![✔] 2.5 对API错误使用Swagger文档化 - -**TL;DR:** 让你的API调用者知道哪种错误会返回,这样他们就能完全的处理这些错误,而不至于系统崩溃。Swagger,REST API的文档框架,通常处理这类问题。 - -**否则:** 任何API的客户端可能决定崩溃并重启,仅仅因为它收到一个不能处理的错误。注意:API的调用者可能是你(在微服务环境中非常典型)。 - - -🔗 [**更多: 使用Swagger记录错误**](/sections/errorhandling/documentingusingswagger.chinese.md) - -

- -## ![✔] 2.6 当一个特殊的情况产生,停掉服务是得体的 - -**TL;DR:** 当一个不确定错误产生(一个开发错误,最佳实践条款#3) - 这就意味着对应用运转健全的不确定。一个普通的实践将是建议仔细地重启进程,并使用一些‘启动器’工具,比如Forever和PM2。 - -**否则:** 当一个未知的异常被抛出,意味着某些对象包含错误的状态(例如某个全局事件发生器由于某些内在的错误,不在产生事件),未来的请求可能失败或者行为异常。 - -🔗 [**更多: 停掉服务**](/sections/errorhandling/shuttingtheprocess.chinese.md) - -

- - - -## ![✔] 2.7 使用一个成熟的日志工具提高错误的可见性 - -**TL;DR:** 一系列成熟的日志工具,比如Winston,Bunyan和Log4J,会加速错误的发现和理解。忘记console.log吧。 - -**否则:** 浏览console的log,和不通过查询工具或者一个好的日志查看器,手动浏览繁琐的文本文件,会使你忙于工作到很晚。 - -🔗 [**更多: 使用好用的日志工具**](/sections/errorhandling/usematurelogger.chinese.md) - - -

- - -## ![✔] 2.8 使用你最喜欢的测试框架测试错误流 - -**TL;DR:** 无论专业的自动化测试或者简单的手动开发测试 - 确保您的代码不仅满足正常的场景,而且处理并且返回正确的错误。测试框架,比如Mocha & Chai可以非常容易的处理这些问题(在"Gist popup"中查看代码实例) 。 - -**否则:** 没有测试,不管自动还是手动,您不可能依赖代码去返回正确的错误。而没有可以理解的错误,那将毫无错误处理可言。 - - -🔗 [**更多: 测试错误流向**](/sections/errorhandling/testingerrorflows.chinese.md) - -

- -## ![✔] 2.9 使用APM产品发现错误和宕机时间 - -**TL;DR:** 监控和性能产品 (别名 APM) 先前一步的检测您的代码库和API,这样他们能自动的,像使用魔法一样的强调错误,宕机和您忽略的性能慢的部分。 - -**否则:** 您花了很多的力气在测量API的性能和错误,但可能您从来没有意识到真实场景下您最慢的代码块和他们对UX的影响。 - - -🔗 [**更多: 使用APM产品**](/sections/errorhandling/apmproducts.chinese.md) - -

- - -## ![✔] 2.10 捕获未处理的promise rejections - -**TL;DR:** 任何在promise中被抛出的异常将被收回和遗弃,除非开发者没有忘记去明确的处理。即使您的代码调用的是process.uncaughtException!解决这个问题可以注册到事件process.unhandledRejection。 - -**否则:** 您的错误将被回收,无踪迹可循。没有什么可以需要考虑。 - - -🔗 [**更多: 捕获未处理的promise rejection**](/sections/errorhandling/catchunhandledpromiserejection.chinese.md) - -

- -## ![✔] 2.11 快速查错,验证参数使用一个专门的库 - -**TL;DR:** 这应该是您的Express最佳实践中的一部分 – assert API输入避免难以理解的漏洞,这类漏洞以后会非常难以追踪。而验证代码通常是一件乏味的事情,除非使用一些非常炫酷的帮助库比如Joi。 - -**否则:** 考虑这种情况 – 您的功能期望一个数字参数 “Discount” ,然而调用者忘记传值,之后在您的代码中检查是否 Discount!=0 (允许的折扣值大于零),这样它将允许用户使用一个折扣。OMG,多么不爽的一个漏洞。你能明白吗? - -🔗 [**更多: 快速查错**](/sections/errorhandling/failfast.chinese.md) - -


- -

⬆ 返回顶部

- -

3. 编码风格实践

- -## ![✔] 3.1 使用ESLint - -**TL;DR:** [ESLint](https://eslint.org)是检查可能的代码错误和修复代码样式的事实上的标准,不仅可以识别实际的间距问题, 而且还可以检测严重的反模式代码, 如开发人员在不分类的情况下抛出错误。尽管ESlint可以自动修复代码样式,但其他的工具比如[prettier](https://www.npmjs.com/package/prettier)和[beautify](https://www.npmjs.com/package/js-beautify)在格式化修复上功能强大,可以和Eslint结合起来使用。 - -**否则:** 开发人员将必须关注单调乏味的间距和线宽问题, 并且时间可能会浪费在过多考虑项目的代码样式。 - -

- -## ![✔] 3.2 Node.js特定的插件 - -**TL;DR:** 除了仅仅涉及 vanilla JS 的 ESLint 标准规则,添加 Node 相关的插件,比如[eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) and [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security) - -**否则:** 许多错误的Node.js代码模式可能在检测下逃生。例如,开发人员可能需要某些文件,把一个变量作为路径名 (variableAsPath) ,这会导致攻击者可以执行任何JS脚本。Node.JS linters可以检测这类模式,并及早预警。 - -

- -## ![✔] 3.3 在同一行开始一个代码块的大括号 - -**TL;DR:** 代码块的第一个大括号应该和声明的起始保持在同一行中。 - -### 代码示例 -```javascript - // 建议 - function someFunction() { - // 代码块 - } - - // 避免 - function someFunction() - { - // 代码块 - } -``` - -**否则:** 不遵守这项最佳实践可能导致意外的结果,在Stackoverflow的帖子中可以查看到,如下: - -🔗 [**更多:** "Why does a results vary based on curly brace placement?" (Stackoverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement) - -

- -## ![✔] 3.4 不要忘记分号 - -**TL;DR:** 即使没有获得一致的认同,但在每一个表达式后面放置分号还是值得推荐的。这将使您的代码, 对于其他阅读代码的开发者来说,可读性,明确性更强。 - -**否则:** 在前面的章节里面已经提到,如果表达式的末尾没有添加分号,JavaScript的解释器会在自动添加一个,这可能会导致一些意想不到的结果。 - -

- -## ![✔] 3.5 命名您的方法 - -**TL;DR:** 命名所有的方法,包含闭包和回调, 避免匿名方法。当剖析一个node应用的时候,这是特别有用的。命名所有的方法将会使您非常容易的理解内存快照中您正在查看的内容。 - -**否则:** 使用一个核心dump(内存快照)调试线上问题,会是一项非常挑战的事项,因为你注意到的严重内存泄漏问题极有可能产生于匿名的方法。 - -

- -## ![✔] 3.6 变量、常量、函数和类的命名约定 - -**TL;DR:** 当命名变量和方法的时候,使用 ***lowerCamelCase*** ,当命名类的时候,使用 ***UpperCamelCase*** (首字母大写),对于常量,则 ***UPPERCASE*** 。这将帮助您轻松地区分普通变量/函数和需要实例化的类。使用描述性名称,但使它们尽量简短。 - -**否则:** JavaScript是世界上唯一一门不需要实例化,就可以直接调用构造函数("Class")的编码语言。因此,类和函数的构造函数由采用UpperCamelCase开始区分。 - -### 代码示例 ### -```javascript - // 使用UpperCamelCase命名类名 - class SomeClassExample () { - - // 常量使用const关键字,并使用lowerCamelCase命名 - const config = { - key: 'value' - }; - - // 变量和方法使用lowerCamelCase命名 - let someVariableExample = 'value'; - function doSomething() { - - } - - } -``` - -

- -## ![✔] 3.7 使用const优于let,废弃var - -**TL;DR:** 使用`const`意味着一旦一个变量被分配,它不能被重新分配。使用const将帮助您免于使用相同的变量用于不同的用途,并使你的代码更清晰。如果一个变量需要被重新分配,以在一个循环为例,使用`let`声明它。let的另一个重要方面是,使用let声明的变量只在定义它的块作用域中可用。 `var`是函数作用域,不是块级作用域,既然您有const和let让您随意使用,那么[不应该在ES6中使用var](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70)。 - -**否则:** 当经常更改变量时,调试变得更麻烦了。 - -🔗 [**更多: JavaScript ES6+: var, let, or const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75) - -

- -## ![✔] 3.8 先require, 而不是在方法内部 - -**TL;DR:** 在每个文件的起始位置,在任何函数的前面和外部require模块。这种简单的最佳实践,不仅能帮助您轻松快速地在文件顶部辨别出依赖关系,而且避免了一些潜在的问题。 - -**否则:** 在Node.js中,require 是同步运行的。如果从函数中调用它们,它可能会阻塞其他请求,在更关键的时间得到处理。另外,如果所require的模块或它自己的任何依赖项抛出错误并使服务器崩溃,最好尽快查明它,如果该模块在函数中require的,则可能不是这样的情况。 - -

- -## ![✔] 3.9 require 文件夹,而不是文件 - -**TL;DR:** 当在一个文件夹中开发库/模块,放置一个文件index.js暴露模块的 -内部,这样每个消费者都会通过它。这将作为您模块的一个接口,并使未来的变化简单而不违反规则。 - -**否则:** 更改文件内部结构或签名可能会破坏与客户端的接口。 - -### 代码示例 -```javascript - // 建议 - module.exports.SMSProvider = require('./SMSProvider'); - module.exports.SMSNumberResolver = require('./SMSNumberResolver'); - - // 避免 - module.exports.SMSProvider = require('./SMSProvider/SMSProvider.js'); - module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolver.js'); -``` - -

- - -## ![✔] 3.10 使用 `===` 操作符 - -**TL;DR:** 对比弱等于 `==`,优先使用严格的全等于 `===` 。`==`将在它们转换为普通类型后比较两个变量。在 `===` 中没有类型转换,并且两个变量必须是相同的类型。 - -**否则:** 与 `==` 操作符比较,不相等的变量可能会返回true。 - -### 代码示例 -```javascript -'' == '0' // false -0 == '' // true -0 == '0' // true - -false == 'false' // false -false == '0' // true - -false == undefined // false -false == null // false -null == undefined // true - -' \t\r\n ' == 0 // true -``` -如果使用`===`, 上面所有语句都将返回 false。 - -

- -## ![✔] 3.11 使用 Async Await, 避免回调 - -**TL;DR:** Node 8 LTS现已全面支持异步等待。这是一种新的方式处理异步请求,取代回调和promise。Async-await是非阻塞的,它使异步代码看起来像是同步的。您可以给你的代码的最好的礼物是用async-await提供了一个更紧凑的,熟悉的,类似try catch的代码语法。 - -**否则:** 使用回调的方式处理异步错误可能是陷入困境最快的方式 - 这种方式必须面对不停地检测错误,处理别扭的代码内嵌,难以推理编码流。 - -🔗[**更多:** async await 1.0 引导](https://github.com/yortus/asyncawait) - -

- -## ![✔] 3.12 使用 (=>) 箭头函数 - -**TL;DR:** 尽管使用 async-await 和避免方法作为参数是被推荐的, 但当处理那些接受promise和回调的老的API的时候 - 箭头函数使代码结构更加紧凑,并保持了根方法上的语义上下文 (例如 'this')。 - -**否则:** 更长的代码(在ES5方法中)更易于产生缺陷,并读起来很是笨重。 - -🔗 [**更多: 这是拥抱箭头函数的时刻**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75) - - -


- -

⬆ 返回顶部

- - -

4. 测试和总体的质量实践

- -## ![✔] 4.1 至少,编写API(组件)测试 - -**TL;DR:** 大多数项目只是因为时间表太短而没有进行任何自动化测试,或者测试项目失控而正被遗弃。因此,优先从API测试开始,这是最简单的编写和提供比单元测试更多覆盖率的事情(你甚至可能不需要编码而进行API测试,像[Postman](https://www.getpostman.com/)。之后,如果您有更多的资源和时间,继续使用高级测试类型,如单元测试、DB测试、性能测试等。 - -**否则:** 您可能需要花很长时间编写单元测试,才发现只有20%的系统覆盖率。 - -

- -## ![✔] 4.2 使用一个linter检测代码问题 - -**TL;DR:** 使用代码linter检查基本质量并及早检测反模式。在任何测试之前运行它, 并将其添加为预提交的git钩子, 以最小化审查和更正任何问题所需的时间。也可在[Section 3](https://github.com/goldbergyoni/nodebestpractices#3-code-style-practices)中查阅编码样式实践 - -**否则:** 您可能让一些反模式和易受攻击的代码传递到您的生产环境中。 - - -

- -## ![✔] 4.3 仔细挑选您的持续集成(CI)平台 - -**TL;DR:** 您的持续集成平台(cicd)将集成各种质量工具(如测试、lint),所以它应该是一个充满活力的生态系统,包含各种插件。[jenkins](https://jenkins.io/)曾经是许多项目的默认选项,因为它有最大的社区,同时也是一个非常强大的平台,这样的代价是要求一个陡峭的学习曲线。如今,使用SaaS工具,比如[CircleCI](https://circleci.com)及其他,安装一套CI解决方案,相对是一件容易的事情。这些工具允许构建灵活的CI管道,而无需管理整个基础设施。最终,这是一个鲁棒性和速度之间的权衡 - 仔细选择您支持的方案。 - -**否则:** 一旦您需要一些高级定制,选择一些细分市场供应商可能会让您停滞不前。另一方面,伴随着jenkins,可能会在基础设施设置上浪费宝贵的时间。 - -🔗 [**更多: 挑选 CI 平台**](/sections/testingandquality/citools.chinese.md) - -

- -## ![✔] 4.4 经常检查易受攻击的依赖 - -**TL;DR:** 即使是那些最有名的依赖模块,比如Express,也有已知的漏洞。使用社区和商业工具,比如 🔗 [npm audit](https://docs.npmjs.com/cli/audit) ,集成在您的CI平台上,在每一次构建的时候都会被调用,这样可以很容易地解决漏洞问题。 - -**否则:** 在没有专用工具的情况下,使代码清除漏洞,需要不断地跟踪有关新威胁的在线出版物,相当繁琐。 - -

- -## ![✔] 4.5 测试标签化 - -**TL;DR:** 不同的测试必须运行在不同的情景:quick smoke,IO-less,当开发者保存或提交一个文件,测试应该启动;完整的端到端的测试通常运行在一个新的pull request被提交之后,等等。这可以通过对测试用例设置标签,比如关键字像#cold #api #sanity,来完成。这样您可以对您的测试集进行grep,调用需要的子集。例如,这就是您通过[Mocha](https://mochajs.org/)仅仅调用sanity测试集所需要做的:mocha --grep 'sanity'。 - -**否则:** 运行所有的测试,包括执行数据库查询的几十个测试,任何时候开发者进行小的改动都可能很慢,这使得开发者不愿意运行测试。 - -

- -## ![✔] 4.6 检查测试覆盖率,它有助于识别错误的测试模式 - -**TL;DR:** 代码覆盖工具比如 [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc),很好用有3个原因:它是免费的(获得这份报告不需要任何开销),它有助于确定测试覆盖率降低的部分,以及最后但非最不重要的是它指出了测试中的不匹配:通过查看颜色标记的代码覆盖报告您可以注意到,例如,从来不会被测到的代码片段像catch语句(即测试只是调用正确的路径,而不调用应用程序发生错误时的行为)。如果覆盖率低于某个阈值,则将其设置为失败的构建。 - -**否则:** 当你的大部分代码没有被测试覆盖时,就不会有任何自动化的度量指标告诉你了。 - - - -

- -## ![✔] 4.7 检查过期的依赖包 - -**TL;DR:** 使用您的首选工具 (例如 “npm outdated” or [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) 来检测已安装的过期依赖包, 将此检查注入您的 CI 管道, 甚至在严重的情况下使构建失败。例如, 当一个已安装的依赖包滞后5个补丁时 (例如:本地版本是1.3.1 的, 存储库版本是1.3.8 的), 或者它被其作者标记为已弃用, 可能会出现严重的情况 - 停掉这次构建并防止部署此版本。 - -**否则:** 您的生产环境将运行已被其作者明确标记为有风险的依赖包 - -

- -## ![✔] 4.8 对于e2e testing,使用docker-compose - -**TL;DR:** 端对端(e2e)测试包含现场数据,由于它依赖于很多重型服务如数据库,习惯被认为是CI过程中最薄弱的环节。Docker-compose通过制定类似生产的环境,并使用一个简单的文本文件和简单的命令,轻松化解了这个问题。它为了e2e测试,允许制作所有相关服务,数据库和隔离网络。最后但并非最不重要的一点是,它可以保持一个无状态环境,该环境在每个测试套件之前被调用,然后立即消失。 - - -**否则:** 没有docker-compose,团队必须维护一个测试数据库在每一个测试环境上,包含开发机器,保持所有数据同步,这样测试结果不会因环境不同而不同。 - - -


- -

⬆ 返回顶部

- -

5. 上线实践

- -## ![✔] 5.1. 监控! - -**TL;DR:** 监控是一种在顾客之前发现问题的游戏 – 显然这应该被赋予前所未有的重要性。考虑从定义你必须遵循的基本度量标准开始(我的建议在里面),到检查附加的花哨特性并选择解决所有问题的解决方案。市场已经淹没其中。点击下面的 ‘The Gist’ ,了解解决方案的概述。 - -**否则:** 错误 === 失望的客户. 非常简单. - - -🔗 [**更多: 监控!**](/sections/production/monitoring.chinese.md) - -

- -## ![✔] 5.2. 使用智能日志增加透明度 - -**TL;DR:** 日志可以是调试语句的一个不能说话的仓库,或者表述应用运行过程的一个漂亮仪表板的驱动。从第1天计划您的日志平台:如何收集、存储和分析日志,以确保所需信息(例如,错误率、通过服务和服务器等完成整个事务)都能被提取出来。 - -**否则:** 您最终像是面对一个黑盒,不知道发生了什么事情,然后你开始重新写日志语句添加额外的信息。 - - -🔗 [**更多: 使用智能日志增加透明度**](/sections/production/smartlogging.chinese.md) - -

- -## ![✔] 5.3. 委托可能的一切(例如:gzip,SSL)给反向代理 - -**TL;DR:** Node处理CPU密集型任务,如gzipping,SSL termination等,表现糟糕。相反,使用一个 ‘真正’ 的中间件服务像Nginx,HAProxy或者云供应商的服务。 - -**否则:** 可怜的单线程Node将不幸地忙于处理网络任务,而不是处理应用程序核心,性能会相应降低。 - - -🔗 [**更多: 委托可能的一切(例如:gzip,SSL)给反向代理**](/sections/production/delegatetoproxy.chinese.md) - -

- -## ![✔] 5.4. 锁住依赖 - -**TL;DR:** 您的代码必须在所有的环境中是相同的,但是令人惊讶的是,NPM默认情况下会让依赖在不同环境下发生偏移 – 当在不同的环境中安装包的时候,它试图拿包的最新版本。克服这种问题可以利用NPM配置文件, .npmrc,告诉每个环境保存准确的(不是最新的)包的版本。另外,对于更精细的控制,使用NPM “shrinkwrap”。*更新:作为NPM5,依赖默认锁定。新的包管理工具,Yarn,也默认锁定。 - -**否则:** QA测试通过的代码和批准的版本,在生产中表现不一致。更糟糕的是,同一生产集群中的不同服务器可能运行不同的代码。 - - -🔗 [**更多: 锁住依赖**](/sections/production/lockdependencies.chinese.md) - -

- -## ![✔] 5.5. 使用正确的工具保护进程正常运行 - -**TL;DR:** 进程必须继续运行,并在失败时重新启动。对于简单的情况下,“重启”工具如PM2可能足够,但在今天的“Dockerized”世界 – 集群管理工具也值得考虑 - -**否则:** 运行几十个实例没有明确的战略和太多的工具(集群管理,docker,PM2)可能导致一个DevOps混乱 - - -🔗 [**更多: 使用正确的工具保护进程正常运行**](/sections/production/guardprocess.chinese.md) - - -

- -## ![✔] 5.6. 利用CPU多核 - -**TL;DR:** 在基本形式上,node应用程序运行在单个CPU核心上,而其他都处于空闲状态。复制node进程和利用多核,这是您的职责 – 对于中小应用,您可以使用Node Cluster和PM2. 对于一个大的应用,可以考虑使用一些Docker cluster(例如k8s,ECS)复制进程或基于Linux init system(例如systemd)的部署脚本 - -**否则:** 您的应用可能只是使用了其可用资源中的25% (!),甚至更少。注意,一台典型的服务器有4个或更多的CPU,默认的Node.js部署仅仅用了一个CPU(甚至使用PaaS服务,比如AWS beanstalk,也一样)。 - - -🔗 [**更多: 利用所有的CPU**](/sections/production/utilizecpu.chinese.md) - -

- -## ![✔] 5.7. 创建一个“维护端点” - -**TL;DR:** 在一个安全的API中暴露一组系统相关的信息,比如内存使用情况和REPL等等。尽管这里强烈建议依赖标准和作战测试工具,但一些有价值的信息和操作更容易使用代码完成。 - -**否则:** 您会发现,您正在执行许多“诊断部署” – 将代码发送到生产中,仅仅只为了诊断目的提取一些信息。 - - -🔗 [**更多: 创建一个 '维护端点'**](/sections/production/createmaintenanceendpoint.chinese.md) - -

- -## ![✔] 5.8. 使用APM产品发现错误和宕机时间 - -**TL;DR:** 监控和性能的产品(即APM)先前一步地评估代码库和API,自动的超过传统的监测,并测量在服务和层级上的整体用户体验。例如,一些APM产品可以突显导致最终用户负载过慢的事务,同时指出根本原因。 - -**否则:** 你可能会花大力气测量API性能和停机时间,也许你永远不会知道,真实场景下哪个是你最慢的代码部分,这些怎么影响用户体验。 - - -🔗 [**更多: 使用APM产品发现错误和宕机时间**](/sections/production/apmproducts.chinese.md) - - -

- - -## ![✔] 5.9. 使您的代码保持生产环境就绪 - -**TL;DR:** 在意识中抱着最终上线的想法进行编码,从第1天开始计划上线。这听起来有点模糊,所以我编写了一些与生产维护密切相关的开发技巧(点击下面的要点) - -**否则:** 一个世界冠军级别的IT/运维人员也不能拯救一个编码低劣的系统。 - - -🔗 [**更多: 使您的代码保持生产环境就绪**](/sections/production/productioncode.chinese.md) - -

- -## ![✔] 5.10. 测量和保护内存使用 - -**TL;DR:** Node.js和内存有引起争论的联系:V8引擎对内存的使用有稍微的限制(1.4GB),在node的代码里面有内存泄漏的很多途径 – 因此监视node的进程内存是必须的。在小应用程序中,你可以使用shell命令周期性地测量内存,但在中等规模的应用程序中,考虑把内存监控建成一个健壮的监控系统。 - -**否则:** 您的内存可能一天泄漏一百兆,就像曾发生在沃尔玛的一样。 - - -🔗 [**更多: 测量和保护内存使用**](/sections/production/measurememory.chinese.md) - -

- - -## ![✔] 5.11. Node外管理您的前端资源 - -**TL;DR:** 使用专门的中间件(nginx,S3,CDN)服务前端内容,这是因为在处理大量静态文件的时候,由于node的单线程模型,它的性能很受影响。 - -**否则:** 您的单个node线程将忙于传输成百上千的html/图片/angular/react文件,而不是分配其所有的资源为了其擅长的任务 – 服务动态内容 - - -🔗 [**更多: Node外管理您的前端资源**](/sections/production/frontendout.chinese.md) - -

- - -## ![✔] 5.12. 保持无状态,几乎每天都要停下服务器 - -**TL;DR:** 在外部数据存储上,存储任意类型数据(例如用户会话,缓存,上传文件)。考虑间隔地停掉您的服务器或者使用 ‘serverless’ 平台(例如 AWS Lambda),这是一个明确的强化无状态的行为。 - -**否则:** 某个服务器上的故障将导致应用程序宕机,而不仅仅是停用故障机器。此外,由于依赖特定服务器,伸缩弹性会变得更具挑战性。 - - -🔗 [**更多: 保持无状态,几乎每天都要停下服务器**](/sections/production/bestateless.chinese.md) - - -

- - -## ![✔] 5.13. 使用自动检测漏洞的工具 - -**TL;DR:** 即使是最有信誉的依赖项,比如Express,会有使系统处于危险境地的已知漏洞(随着时间推移)。通过使用社区的或者商业工具,不时的检查漏洞和警告(本地或者Github上),这类问题很容易被抑制,有些问题甚至可以立即修补。 - -**否则:** 否则: 在没有专用工具的情况下,使代码清除漏洞,需要不断地跟踪有关新威胁的在线出版物。相当繁琐。 - - -🔗 [**更多: 使用自动检测漏洞的工具**](/sections/production/detectvulnerabilities.chinese.md) - -

- - -## ![✔] 5.14. 在每一个log语句中指明 ‘TransactionId’ - -**TL;DR:** 在每一个请求的每一条log入口,指明同一个标识符,transaction-id: {某些值}。然后在检查日志中的错误时,很容易总结出前后发生的事情。不幸的是,由于Node异步的天性自然,这是不容易办到的,看下代码里面的例子 - -**否则:** 在没有上下文的情况下查看生产错误日志,这会使问题变得更加困难和缓慢去解决。 - - -🔗 [**更多: 在每一个log语句中指明 ‘TransactionId’**](/sections/production/assigntransactionid.chinese.md) - -

- - -## ![✔] 5.15. 设置NODE_ENV=production - -**TL;DR:** 设置环境变量NODE_ENV为‘production’ 或者 ‘development’,这是一个是否激活上线优化的标志 - 很多NPM的包通过它来判断当前的环境,据此优化生产环境代码。 - -**否则:** 遗漏这个简单的属性可能大幅减弱性能。例如,在使用Express作为服务端渲染页面的时候,如果未设置NODE_ENV,性能将会减慢大概三分之一! - - -🔗 [**更多: 设置NODE_ENV=production**](/sections/production/setnodeenv.chinese.md) - - -

- - -## ![✔] 5.16. 设计自动化、原子化和零停机时间部署 - -**TL;DR:** 研究表明,执行许多部署的团队降低了严重上线问题的可能性。不需要危险的手动步骤和服务停机时间的快速和自动化部署大大改善了部署过程。你应该达到使用Docker结合CI工具,使他们成为简化部署的行业标准。 - -**否则:** 长时间部署 -> 线上宕机 & 和人相关的错误 -> 团队部署时不自信 -> 更少的部署和需求 - -


- -

⬆ 返回顶部

- -

6. 安全最佳实践

- -
-53 items -
- -## ![✔] 6.1. 拥护linter安全准则 - - - -**TL;DR:** 使用安全相关的linter插件,比如[eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security),尽早捕获安全隐患或者问题,最好在编码阶段。这能帮助察觉安全的问题,比如使用eval,调用子进程,或者根据字面含义(比如,用户输入)引入模块等等。点击下面‘更多’获得一个安全linter可以检测到的代码示例。 - -**Otherwise:** 在开发过程中, 可能一个直白的安全隐患, 成为生产环境中一个严重问题。此外, 项目可能没有遵循一致的安全规范, 而导致引入漏洞, 或敏感信息被提交到远程仓库中。 - -🔗 [**更多: Lint 规范**](/sections/security/lintrules.md) - -

- -## ![✔] 6.2. 使用中间件限制并发请求 - - - -**TL;DR:** DOS攻击非常流行而且相对容易处理。使用外部服务,比如cloud负载均衡, cloud防火墙, nginx, 或者(对于小的,不是那么重要的app)一个速率限制中间件(比如[express-rate-limit](https://www.npmjs.com/package/express-rate-limit)),来实现速率限制。 - -**否则:** 应用程序可能受到攻击, 导致拒绝服务, 在这种情况下, 真实用户会遭受服务降级或不可用。 - -🔗 [**更多: 实施速率限制**](/sections/security/limitrequests.md) - -

- -## ![✔] 6.3 把机密信息从配置文件中抽离出来,或者使用包对其加密 - - - -**TL;DR:** 不要在配置文件或源代码中存储纯文本机密信息。相反, 使用诸如Vault产品、Kubernetes/Docker Secrets或使用环境变量之类的安全管理系统。最后一个结果是, 存储在源代码管理中的机密信息必须进行加密和管理 (滚动密钥(rolling keys)、过期时间、审核等)。使用pre-commit/push钩子防止意外提交机密信息。 - -**否则:** 源代码管理, 即使对于私有仓库, 也可能会被错误地公开, 此时所有的秘密信息都会被公开。外部组织的源代码管理的访问权限将无意中提供对相关系统 (数据库、api、服务等) 的访问。 - -🔗 [**更多: 安全管理**](/sections/security/secretmanagement.md) - -

- -## ![✔] 6.4. 使用 ORM/ODM 库防止查询注入漏洞 - - - -**TL;DR:** 要防止 SQL/NoSQL 注入和其他恶意攻击, 请始终使用 ORM/ODM 或database库来转义数据或支持命名的或索引的参数化查询, 并注意验证用户输入的预期类型。不要只使用JavaScript模板字符串或字符串串联将值插入到查询语句中, 因为这会将应用程序置于广泛的漏洞中。所有知名的Node.js数据访问库(例如[Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose))包含对注入漏洞的内置包含措施。 - -**否则:** 未经验证或未脱敏处理的用户输入,可能会导致操作员在使用MongoDB进行NoSQL操作时进行注入, 而不使用适当的过滤系统或ORM很容易导致SQL注入攻击, 从而造成巨大的漏洞。 - -🔗 [**更多: 使用 ORM/ODM 库防止查询注入**](/sections/security/ormodmusage.md) - -

- -## ![✔] 6.5. 通用安全最佳实际集合 - -**TL;DR:** 这些是与Node.js不直接相关的安全建议的集合-Node的实现与任何其他语言没有太大的不同。单击 "阅读更多" 浏览。 - -🔗 [**更多: 通用安全最佳实际**](/sections/security/commonsecuritybestpractices.md) - -

- -## ![✔] 6.6. 调整 HTTP 响应头以加强安全性 - - - -**TL;DR:** 应用程序应该使用安全的header来防止攻击者使用常见的攻击方式,诸如跨站点脚本(XSS)、点击劫持和其他恶意攻击。可以使用模块,比如 [helmet](https://www.npmjs.com/package/helmet)轻松进行配置。 - -**否则:** 攻击者可以对应用程序的用户进行直接攻击, 导致巨大的安全漏洞 - -🔗 [**更多: 在应用程序中使用安全的header**](/sections/security/secureheaders.md) - -

- -## ![✔] 6.7. 经常自动检查易受攻击的依赖库 - - - -**TL;DR:** 在npm的生态系统中, 一个项目有许多依赖是很常见的。在找到新的漏洞时, 应始终将依赖项保留在检查中。使用工具,类似于[npm audit](https://docs.npmjs.com/cli/audit) 或者 [snyk](https://snyk.io/)跟踪、监视和修补易受攻击的依赖项。将这些工具与 CI 设置集成, 以便在将其上线之前捕捉到易受攻击的依赖库。 - -**否则:** 攻击者可以检测到您的web框架并攻击其所有已知的漏洞。 - -🔗 [**更多: 安全依赖**](/sections/security/dependencysecurity.md) - -

- -## ![✔] 6.8. 避免使用Node.js的crypto库处理密码,使用Bcrypt - - - -**TL;DR:** 密码或机密信息(API密钥)应该使用安全的哈希+salt函数(如 "bcrypt")来存储, 因为性能和安全原因, 这应该是其JavaScript实现的首选。 - -**否则:** 在不使用安全功能的情况下,保存的密码或秘密信息容易受到暴力破解和字典攻击, 最终会导致他们的泄露。 - -🔗 [**更多: 使用Bcrypt**](/sections/security/bcryptpasswords.chinese.md) - -

- -## ![✔] 6.9. 转义 HTML、JS 和 CSS 输出 - - - -**TL;DR:** 发送给浏览器的不受信任数据可能会被执行, 而不是显示, 这通常被称为跨站点脚本(XSS)攻击。使用专用库将数据显式标记为不应执行的纯文本内容(例如:编码、转义),可以减轻这种问题。 - -**否则:** 攻击者可能会将恶意的JavaScript代码存储在您的DB中, 然后将其发送给可怜的客户端。 - -🔗 [**更多: 转义输出**](/sections/security/escape-output.md) - -

- -## ![✔] 6.10. 验证传入的JSON schemas - - - -**TL;DR:** 验证传入请求的body payload,并确保其符合预期要求, 如果没有, 则快速报错。为了避免每个路由中繁琐的验证编码, 您可以使用基于JSON的轻量级验证架构,比如[jsonschema](https://www.npmjs.com/package/jsonschema) or [joi](https://www.npmjs.com/package/joi) - -**否则:** 您疏忽和宽松的方法大大增加了攻击面, 并鼓励攻击者尝试许多输入, 直到他们找到一些组合, 使应用程序崩溃。 - -🔗 [**更多: 验证传入的JSON schemas**](/sections/security/validation.md) - -

- -## ![✔] 6.11. 支持黑名单的JWT - - - -**TL;DR:** 当使用JSON Web Tokens(例如, 通过[Passport.js](https://github.com/jaredhanson/passport)), 默认情况下, 没有任何机制可以从发出的令牌中撤消访问权限。一旦发现了一些恶意用户活动, 只要它们持有有效的标记, 就无法阻止他们访问系统。通过实现一个不受信任令牌的黑名单,并在每个请求上验证,来减轻此问题。 - -**否则:** 过期或错误的令牌可能被第三方恶意使用,以访问应用程序,并模拟令牌的所有者。 - -🔗 [**更多: 为JSON Web Token添加黑名单**](/sections/security/expirejwt.md) - -

- -## ![✔] 6.12. 限制每个用户允许的登录请求 - - - -**TL;DR:** 一类保护暴力破解的中间件,比如[express-brute](https://www.npmjs.com/package/express-brute),应该被用在express的应用中,来防止暴力/字典攻击;这类攻击主要应用于一些敏感路由,比如/admin 或者 /login,基于某些请求属性, 如用户名, 或其他标识符, 如正文参数等。 - -**否则:** 攻击者可以发出无限制的密码匹配尝试, 以获取对应用程序中特权帐户的访问权限。 - -🔗 [**更多: 限制登录频率**](/sections/security/login-rate-limit.md) - -

- -## ![✔] 6.13. 使用非root用户运行Node.js - - - -**TL;DR:** Node.js作为一个具有无限权限的root用户运行,这是一种普遍的情景。例如,在Docker容器中,这是默认行为。建议创建一个非root用户,并保存到Docker镜像中(下面给出了示例),或者通过调用带有"-u username" 的容器来代表此用户运行该进程。 - -**否则:** 在服务器上运行脚本的攻击者在本地计算机上获得无限制的权利 (例如,改变iptable,引流到他的服务器上) - -🔗 [**更多: 使用非root用户运行Node.js**](/sections/security/non-root-user.md) - -

- -## ![✔] 6.14. 使用反向代理或中间件限制负载大小 - - - -**TL;DR:** 请求body有效载荷越大, Node.js的单线程就越难处理它。这是攻击者在没有大量请求(DOS/DDOS 攻击)的情况下,就可以让服务器跪下的机会。在边缘上(例如,防火墙,ELB)限制传入请求的body大小,或者通过配置[express body parser](https://github.com/expressjs/body-parser)仅接收小的载荷,可以减轻这种问题。 - -**否则:** 您的应用程序将不得不处理大的请求, 无法处理它必须完成的其他重要工作, 从而导致对DOS攻击的性能影响和脆弱性。 - -🔗 [**更多: 限制负载大小**](/sections/security/requestpayloadsizelimit.md) - -

- -## ![✔] 6.15. 避免JavaScript的eval声明 - - - -**TL;DR:** `eval` 是邪恶的, 因为它允许在运行时执行自定义的JavaScript代码。这不仅是一个性能方面的问题, 而且也是一个重要的安全问题, 因为恶意的JavaScript代码可能来源于用户输入。应该避免的另一种语言功能是 `new Function` 构造函数。`setTimeout` 和 `setInterval` 也不应该传入动态JavaScript代码。 - -**否则:** 恶意JavaScript代码查找传入 `eval` 或其他实时判断的JavaScript函数的文本的方法, 并将获得在该页面上javascript权限的完全访问权。此漏洞通常表现为XSS攻击。 - -🔗 [**更多: 避免JavaScript的eval声明**](/sections/security/avoideval.chinese.md) - -

- -## ![✔] 6.16. 防止恶意RegEx让Node.js的单线程过载执行 - - - -**TL;DR:** 正则表达式,在方便的同时,对JavaScript应用构成了真正的威胁,特别是Node.js平台。匹配文本的用户输入需要大量的CPU周期来处理。在某种程度上,正则处理是效率低下的,比如验证10个单词的单个请求可能阻止整个event loop长达6秒,并让CPU引火烧身。由于这个原因,偏向第三方的验证包,比如[validator.js](https://github.com/chriso/validator.js),而不是采用正则,或者使用[safe-regex](https://github.com/substack/safe-regex)来检测有问题的正则表达式。 - -**否则:** 写得不好的正则表达式可能容易受到正则表达式DoS攻击的影响, 这将完全阻止event loop。例如,流行的`moment`包在2017年的11月,被发现使用了错误的RegEx用法而易受攻击。 - -🔗 [**更多: 防止恶意正则**](/sections/security/regex.md) - -

- -## ![✔] 6.17. 使用变量避免模块加载 - - - -**TL;DR:** 避免通过作为参数的路径requiring/importing另一个文件, 原因是它可能源自用户输入。此规则可扩展为访问一般文件(即:`fs.readFile()`)或使用来自用户输入的动态变量访问其他敏感资源。[Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter可以捕捉这样的模式, 并尽早提前警告。 - -**否则:** 恶意用户输入可以找到用于获得篡改文件的参数, 例如, 文件系统上以前上载的文件, 或访问已有的系统文件。 - -🔗 [**更多: 安全地加载模块**](/sections/security/safemoduleloading.chinese.md) - -

- -## ![✔] 6.18. 在沙箱中运行不安全代码 - - - -**TL;DR:** 当任务执行在运行时给出的外部代码时(例如, 插件), 使用任何类型的`沙盒`执行环境保护主代码,并隔离开主代码和插件。这可以通过一个专用的过程来实现 (例如:cluster.fork()), 无服务器环境或充当沙盒的专用npm包。 - -**否则:** 插件可以通过无限循环、内存超载和对敏感进程环境变量的访问等多种选项进行攻击 - -🔗 [**更多: 在沙箱中运行不安全代码**](/sections/security/sandbox.chinese.md) - -

- -## ![✔] 6.19. 使用子进程时要格外小心 - - - -**TL;DR:** 尽可能地避免使用子进程,如果您仍然必须这样做,验证和清理输入以减轻shell注入攻击。更喜欢使用 "child_process"。execFile 的定义将只执行具有一组属性的单个命令, 并且不允许 shell 参数扩展。倾向于使用`child_process.execFile`,从定义上来说,它将仅仅执行具有一组属性的单个命令,并且不允许shell参数扩展。 - -**否则:** 由于将恶意用户输入传递给未脱敏处理的系统命令, 直接地使用子进程可能导致远程命令执行或shell注入攻击。 - -🔗 [**更多: 处理子进程时要格外小心**](/sections/security/childprocesses.chinese.md) - -

- -## ![✔] 6.20. 隐藏客户端的错误详细信息 - - - -**TL;DR:** 默认情况下, 集成的express错误处理程序隐藏错误详细信息。但是, 极有可能, 您实现自己的错误处理逻辑与自定义错误对象(被许多人认为是最佳做法)。如果这样做, 请确保不将整个Error对象返回到客户端, 这可能包含一些敏感的应用程序详细信息。 - -**否则:** 敏感应用程序详细信息(如服务器文件路径、使用中的第三方模块和可能被攻击者利用的应用程序的其他内部工作流)可能会从stack trace发现的信息中泄露。 - -🔗 [**更多: 隐藏客户端的错误详细信息**](/sections/security/hideerrors.md) - -

- -## ![✔] 6.21. 对npm或Yarn,配置2FA - - - -**TL;DR:** 开发链中的任何步骤都应使用MFA(多重身份验证)进行保护, npm/Yarn对于那些能够掌握某些开发人员密码的攻击者来说是一个很好的机会。使用开发人员凭据, 攻击者可以向跨项目和服务广泛安装的库中注入恶意代码。甚至可能在网络上公开发布。在npm中启用2因素身份验证(2-factor-authentication), 攻击者几乎没有机会改变您的软件包代码。 - -**否则:** [Have you heard about the eslint developer who's password was hijacked?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8) - -

- -## ![✔] 6.22. 修改session中间件设置 - - - -**TL;DR:** 每个web框架和技术都有其已知的弱点-告诉攻击者我们使用的web框架对他们来说是很大的帮助。使用session中间件的默认设置, 可以以类似于`X-Powered-By`header的方式向模块和框架特定的劫持攻击公开您的应用。尝试隐藏识别和揭露技术栈的任何内容(例如:Nonde.js, express)。 - -**否则:** 可以通过不安全的连接发送cookie, 攻击者可能会使用会话标识来标识web应用程序的基础框架以及特定于模块的漏洞。 - -🔗 [**更多: cookie和session安全**](/sections/security/sessions.md) - -

- -## ![✔] 6.23. 通过显式设置进程应崩溃的情况,以避免DOS攻击 - - - -**TL;DR:** 当错误未被处理时, Node进程将崩溃。即使错误被捕获并得到处理,许多最佳实践甚至建议退出。例如, Express会在任何异步错误上崩溃 - 除非使用catch子句包装路由。这将打开一个非常惬意的攻击点, 攻击者识别哪些输入会导致进程崩溃并重复发送相同的请求。没有即时补救办法, 但一些技术可以减轻苦楚: 每当进程因未处理的错误而崩溃,都会发出警报,验证输入并避免由于用户输入无效而导致进程崩溃,并使用catch将所有路由处理包装起来,并在请求中出现错误时, 考虑不要崩溃(与全局发生的情况相反)。 - -**否则:** 这只是一个起到教育意义的假设: 给定许多Node.js应用程序, 如果我们尝试传递一个空的JSON正文到所有POST请求 - 少数应用程序将崩溃。在这一点上, 我们可以只是重复发送相同的请求, 就可以轻松地搞垮应用程序。 - -


- -

⬆ Return to top

- -# `API Practices` - -## Our contributors are working on this section. Would you like to join? - -# `Performance Practices` - -## Our contributors are working on this section. Would you like to join? - -


- -# Milestones -To maintain this guide and keep it up to date, we are constantly updating and improving the guidelines and best practices with the help of the community. You can follow our [milestones](https://github.com/goldbergyoni/nodebestpractices/milestones) and join the working groups if you want to contribute to this project. - -

- -# Contributors -## `Yoni Goldberg` -Independent Node.js consultant who works with customers at USA, Europe and Israel on building large-scale scalable Node applications. Many of the best practices above were first published on his blog post at [http://www.goldbergyoni.com](http://www.goldbergyoni.com). Reach Yoni at @goldbergyoni or me@goldbergyoni.com - -## `Ido Richter` -👨‍💻 Software engineer, 🌐 web developer, 🤖 emojis enthusiast. - -## `Refael Ackermann` [@refack](https://github.com/refack) <refack@gmail.com> (he/him) -Node.js Core Collaborator, been noding since 0.4, and have noded in multiple production sites. Founded `node4good` home of [`lodash-contrib`](https://github.com/node4good/lodash-contrib), [`formage`](https://github.com/node4good/formage), and [`asynctrace`](https://github.com/node4good/asynctrace). -`refack` on freenode, Twitter, GitHub, GMail, and many other platforms. DMs are open, happy to help. - -## `Bruno Scheufler` -💻 full-stack web developer and Node.js enthusiast. - -## `Kyle Martin` [@js-kyle](https://github.com/js-kyle) -Full Stack Developer based in New Zealand, interested in architecting and building Node.js applications to perform at global scale. Keen contributor to open source software, including Node.js Core. - - -

- -## Thank You Notes - -We appreciate any contribution, from a single word fix to a new best practice. View our contributors and [contributing documentation here!](CONTRIBUTORS.md) - -


+[✔]: assets/images/checkbox-small-blue.png + +# Node.js 最佳实践 + +

+ Node.js Best Practices +

+ +
+ +
+ 82 items Last update: June 5, 2019 Updated for Node 12.4.0 LTS +
+ +
+ + [![nodepractices](/assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/) +
+ +# 欢迎! 首先您应该知道的三件事情: +**1. 当您读到这里,实际上您读了很多关于Node.js的优秀文章 -** 这是对Node.js最佳实践中排名最高的内容的总结和分享 + +**2. 这里是最大的汇集,且每周都在增长 -** 当前,超过50个最佳实现,样式指南,架构建议已经呈现。每天都有新的issue和PR被创建,以使这本在线书籍不断更新。我们很乐于见到您能在这里做出贡献,不管是修复一些代码的错误,或是提出绝妙的新想法。请查看我们的[milestones](https://github.com/goldbergyoni/nodebestpractices/milestones?direction=asc&sort=due_date&state=open) + +**3. 大部分的条目包含额外的信息 -** 大部分的最佳实践条目的旁边,您将发现 **🔗Read More** 链接,它将呈现给您示例代码,博客引用和更多信息 + +


+ +## [目录](#table-of-contents) +1. [项目结构实践 (5) ](#1-project-structure-practices) +2. [异常处理实践 (11) ](#2-error-handling-practices) +3. [编码规范实践 (12) ](#3-code-style-practices) +4. [测试和总体质量实践 (8) ](#4-testing-and-overall-quality-practices) +5. [进入生产实践 (16) ](#5-going-to-production-practices) +6. :star: 新: [安全实践(23)](#6-security-best-practices) +7. Performance Practices ([coming soon](https://github.com/goldbergyoni/nodebestpractices/milestones?direction=asc&sort=due_date&state=open)) + + +


+

1. 项目结构实践

+ +## ![✔] 1.1 组件式构建你的解决方案 + + **TL;DR:** 大型项目的最坏的隐患就是维护一个庞大的,含有几百个依赖的代码库 - 当开发人员准备整合新的需求的时候,这样一个庞然大物势必减缓了开发效率。反之,把您的代码拆分成组件,每一个组件有它自己的文件夹和代码库,并且确保每一个组件小而简单。查看正确的项目结构的例子请访问下面的 ‘更多’ 链接。 + +**否则:** 当编写新需求的开发人员逐步意识到他所做改变的影响,并担心会破坏其他的依赖模块 - 部署会变得更慢,风险更大。当所有业务逻辑没有被分开,这也会被认为很难扩展 + +🔗 [**更多: 组件结构**](/sections/projectstructre/breakintcomponents.chinese.md) + +

+ +## ![✔] 1.2 分层设计组件,保持Express在特定的区域 + +**TL;DR:** 每一个组件都应该包含'层级' - 一个专注的用于接入网络,逻辑,数据的概念。这样不仅获得一个清晰的分离考量,而且使仿真和测试系统变得异常容易。尽管这是一个普通的模式,但接口开发者易于混淆层级关系,比如把网络层的对象(Express req, res)传给业务逻辑和数据层 - 这会令您的应用彼此依赖,并且只能通过Express使用。 + +**否则:** 对于混淆了网络层和其它层的应用,将不易于测试,执行CRON的任务,其它非-Express的调用者无法使用 + +🔗 [**更多: 应用分层**](/sections/projectstructre/createlayers.chinese.md) + +

+ +## ![✔] 1.3 封装公共模块成为NPM的包 + +**TL;DR:** 由大量代码构成的一个大型应用中,贯彻全局的,比如日志,加密和其它类似的公共组件,应该进行封装,并暴露成一个私有的NPM包。这将使其在更多的代码库和项目中被使用变成了可能。 + +**否则:** 您将不得不重造部署和依赖的轮子 + +🔗 [**更多: 通过需求构建**](/sections/projectstructre/wraputilities.chinese.md) + +

+ +## ![✔] 1.4 分离 Express 'app' and 'server' + +**TL;DR:** 避免定义整个[Express](https://expressjs.com/)应用在一个单独的大文件里, 这是一个不好的习惯 - 分离您的 'Express' 定义至少在两个文件中: API声明(app.js) 和 网络相关(WWW)。对于更好的结构,是把你的API声明放在组件中。 + +**否则:** 您的API将只能通过HTTP的调用进行测试(慢,并且很难产生测试覆盖报告)。维护一个有着上百行代码的文件也不是一个令人开心的事情。 + +🔗 [**更多: 分离 Express 'app' and 'server'**](/sections/projectstructre/separateexpress.chinese.md) + +

+ +## ![✔] 1.5 使用易于设置环境变量,安全和分级的配置 + + +**TL;DR:** 一个完美无瑕的配置安装应该确保 (a) 元素可以从文件中,也可以从环境变量中读取 (b) 密码排除在提交的代码之外 (c) 为了易于检索,配置是分级的。仅有几个包可以满足这样的条件,比如[rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) 和 [convict](https://www.npmjs.com/package/convict)。 + +**否则:** 不能满足任意的配置要求将会使开发,运维团队,或者两者,易于陷入泥潭。 + +🔗 [**更多: 配置最佳实践**](/sections/projectstructre/configguide.chinese.md) + +


+ +

⬆ 返回顶部

+ +

2. 错误处理最佳实践

+ +## ![✔] 2.1 使用 Async-Await 和 promises 用于异步错误处理 + +**TL;DR:** 使用回调的方式处理异步错误可能是导致灾难的最快的方式(a.k.a the pyramid of doom)。对您的代码来说,最好的礼物就是使用规范的promise库或async-await来替代,这会使其像try-catch一样更加简洁,具有熟悉的代码结构。 + +**否则:** Node.js回调特性, function(err, response), 是导致不可维护代码的一个必然的方式。究其原因,是由于混合了随意的错误处理代码,臃肿的内嵌,蹩脚的代码模式。 + +🔗 [**更多: 避免回调**](/sections/errorhandling/asyncerrorhandling.chinese.md) + +

+ +## ![✔] 2.2 仅使用内建的错误对象 + +**TL;DR:** 很多人抛出异常使用字符串类型或一些自定义类型 - 这会导致错误处理逻辑和模块间的调用复杂化。是否您reject一个promise,抛出异常或发出(emit)错误 - 使用内建的错误对象将会增加设计一致性,并防止信息的丢失。 + + +**否则:** 调用某些模块,将不确定哪种错误类型会返回 - 这将会使恰当的错误处理更加困难。更坏的情况是,使用特定的类型描述错误,会导致重要的错误信息缺失,比如stack trace! + +🔗 [**更多: 使用内建错误对象**](/sections/errorhandling/useonlythebuiltinerror.chinese.md) + +

+ +## ![✔] 2.3 区分运行错误和程序设计错误 + +**TL;DR:** 运行错误(例如, API接受到一个无效的输入)指的是一些已知场景下的错误,这类错误的影响已经完全被理解,并能被考虑周全的处理掉。同时,程序设计错误(例如,尝试读取未定义的变量)指的是未知的编码问题,影响到应用得当的重启。 + +**否则:** 当一个错误产生的时候,您总是得重启应用,但为什么要让 ~5000 个在线用户不能访问,仅仅是因为一个细微的,可以预测的,运行时错误?相反的方案,也不完美 – 当未知的问题(程序问题)产生的时候,使应用依旧可以访问,可能导致不可预测行为。区分两者会使处理更有技巧,并在给定的上下文下给出一个平衡的对策。 + +🔗 [**更多: 运行错误和程序设计错误**](/sections/errorhandling/operationalvsprogrammererror.chinese.md) + +

+ +## ![✔] 2.4 集中处理错误,不要在Express中间件中处理错误 + +**TL;DR:** 错误处理逻辑,比如给管理员发送邮件,日志应该封装在一个特定的,集中的对象当中,这样当错误产生的时候,所有的终端(例如 Express中间件,cron任务,单元测试)都可以调用。 + +**否则:** 错误处理的逻辑不放在一起将会导致代码重复和非常可能不恰当的错误处理。 + +🔗 [**更多: 集中处理错误**](/sections/errorhandling/centralizedhandling.chinese.md) + +

+ +## ![✔] 2.5 对API错误使用Swagger文档化 + +**TL;DR:** 让你的API调用者知道哪种错误会返回,这样他们就能完全的处理这些错误,而不至于系统崩溃。Swagger,REST API的文档框架,通常处理这类问题。 + +**否则:** 任何API的客户端可能决定崩溃并重启,仅仅因为它收到一个不能处理的错误。注意:API的调用者可能是你(在微服务环境中非常典型)。 + + +🔗 [**更多: 使用Swagger记录错误**](/sections/errorhandling/documentingusingswagger.chinese.md) + +

+ +## ![✔] 2.6 当一个特殊的情况产生,停掉服务是得体的 + +**TL;DR:** 当一个不确定错误产生(一个开发错误,最佳实践条款#3) - 这就意味着对应用运转健全的不确定。一个普通的实践将是建议仔细地重启进程,并使用一些‘启动器’工具,比如Forever和PM2。 + +**否则:** 当一个未知的异常被抛出,意味着某些对象包含错误的状态(例如某个全局事件发生器由于某些内在的错误,不在产生事件),未来的请求可能失败或者行为异常。 + +🔗 [**更多: 停掉服务**](/sections/errorhandling/shuttingtheprocess.chinese.md) + +

+ + + +## ![✔] 2.7 使用一个成熟的日志工具提高错误的可见性 + +**TL;DR:** 一系列成熟的日志工具,比如Winston,Bunyan和Log4J,会加速错误的发现和理解。忘记console.log吧。 + +**否则:** 浏览console的log,和不通过查询工具或者一个好的日志查看器,手动浏览繁琐的文本文件,会使你忙于工作到很晚。 + +🔗 [**更多: 使用好用的日志工具**](/sections/errorhandling/usematurelogger.chinese.md) + + +

+ + +## ![✔] 2.8 使用你最喜欢的测试框架测试错误流 + +**TL;DR:** 无论专业的自动化测试或者简单的手动开发测试 - 确保您的代码不仅满足正常的场景,而且处理并且返回正确的错误。测试框架,比如Mocha & Chai可以非常容易的处理这些问题(在"Gist popup"中查看代码实例) 。 + +**否则:** 没有测试,不管自动还是手动,您不可能依赖代码去返回正确的错误。而没有可以理解的错误,那将毫无错误处理可言。 + + +🔗 [**更多: 测试错误流向**](/sections/errorhandling/testingerrorflows.chinese.md) + +

+ +## ![✔] 2.9 使用APM产品发现错误和宕机时间 + +**TL;DR:** 监控和性能产品 (别名 APM) 先前一步的检测您的代码库和API,这样他们能自动的,像使用魔法一样的强调错误,宕机和您忽略的性能慢的部分。 + +**否则:** 您花了很多的力气在测量API的性能和错误,但可能您从来没有意识到真实场景下您最慢的代码块和他们对UX的影响。 + + +🔗 [**更多: 使用APM产品**](/sections/errorhandling/apmproducts.chinese.md) + +

+ + +## ![✔] 2.10 捕获未处理的promise rejections + +**TL;DR:** 任何在promise中被抛出的异常将被收回和遗弃,除非开发者没有忘记去明确的处理。即使您的代码调用的是process.uncaughtException!解决这个问题可以注册到事件process.unhandledRejection。 + +**否则:** 您的错误将被回收,无踪迹可循。没有什么可以需要考虑。 + + +🔗 [**更多: 捕获未处理的promise rejection**](/sections/errorhandling/catchunhandledpromiserejection.chinese.md) + +

+ +## ![✔] 2.11 快速查错,验证参数使用一个专门的库 + +**TL;DR:** 这应该是您的Express最佳实践中的一部分 – assert API输入避免难以理解的漏洞,这类漏洞以后会非常难以追踪。而验证代码通常是一件乏味的事情,除非使用一些非常炫酷的帮助库比如Joi。 + +**否则:** 考虑这种情况 – 您的功能期望一个数字参数 “Discount” ,然而调用者忘记传值,之后在您的代码中检查是否 Discount!=0 (允许的折扣值大于零),这样它将允许用户使用一个折扣。OMG,多么不爽的一个漏洞。你能明白吗? + +🔗 [**更多: 快速查错**](/sections/errorhandling/failfast.chinese.md) + +


+ +

⬆ 返回顶部

+ +

3. 编码风格实践

+ +## ![✔] 3.1 使用ESLint + +**TL;DR:** [ESLint](https://eslint.org)是检查可能的代码错误和修复代码样式的事实上的标准,不仅可以识别实际的间距问题, 而且还可以检测严重的反模式代码, 如开发人员在不分类的情况下抛出错误。尽管ESlint可以自动修复代码样式,但其他的工具比如[prettier](https://www.npmjs.com/package/prettier)和[beautify](https://www.npmjs.com/package/js-beautify)在格式化修复上功能强大,可以和Eslint结合起来使用。 + +**否则:** 开发人员将必须关注单调乏味的间距和线宽问题, 并且时间可能会浪费在过多考虑项目的代码样式。 + +

+ +## ![✔] 3.2 Node.js特定的插件 + +**TL;DR:** 除了仅仅涉及 vanilla JS 的 ESLint 标准规则,添加 Node 相关的插件,比如[eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) and [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security) + +**否则:** 许多错误的Node.js代码模式可能在检测下逃生。例如,开发人员可能需要某些文件,把一个变量作为路径名 (variableAsPath) ,这会导致攻击者可以执行任何JS脚本。Node.JS linters可以检测这类模式,并及早预警。 + +

+ +## ![✔] 3.3 在同一行开始一个代码块的大括号 + +**TL;DR:** 代码块的第一个大括号应该和声明的起始保持在同一行中。 + +### 代码示例 +```javascript + // 建议 + function someFunction() { + // 代码块 + } + + // 避免 + function someFunction() + { + // 代码块 + } +``` + +**否则:** 不遵守这项最佳实践可能导致意外的结果,在Stackoverflow的帖子中可以查看到,如下: + +🔗 [**更多:** "Why does a results vary based on curly brace placement?" (Stackoverflow)](https://stackoverflow.com/questions/3641519/why-does-a-results-vary-based-on-curly-brace-placement) + +

+ +## ![✔] 3.4 不要忘记分号 + +**TL;DR:** 即使没有获得一致的认同,但在每一个表达式后面放置分号还是值得推荐的。这将使您的代码, 对于其他阅读代码的开发者来说,可读性,明确性更强。 + +**否则:** 在前面的章节里面已经提到,如果表达式的末尾没有添加分号,JavaScript的解释器会在自动添加一个,这可能会导致一些意想不到的结果。 + +

+ +## ![✔] 3.5 命名您的方法 + +**TL;DR:** 命名所有的方法,包含闭包和回调, 避免匿名方法。当剖析一个node应用的时候,这是特别有用的。命名所有的方法将会使您非常容易的理解内存快照中您正在查看的内容。 + +**否则:** 使用一个核心dump(内存快照)调试线上问题,会是一项非常挑战的事项,因为你注意到的严重内存泄漏问题极有可能产生于匿名的方法。 + +

+ +## ![✔] 3.6 变量、常量、函数和类的命名约定 + +**TL;DR:** 当命名变量和方法的时候,使用 ***lowerCamelCase*** ,当命名类的时候,使用 ***UpperCamelCase*** (首字母大写),对于常量,则 ***UPPERCASE*** 。这将帮助您轻松地区分普通变量/函数和需要实例化的类。使用描述性名称,但使它们尽量简短。 + +**否则:** JavaScript是世界上唯一一门不需要实例化,就可以直接调用构造函数("Class")的编码语言。因此,类和函数的构造函数由采用UpperCamelCase开始区分。 + +### 代码示例 ### +```javascript + // 使用UpperCamelCase命名类名 + class SomeClassExample () { + + // 常量使用const关键字,并使用lowerCamelCase命名 + const config = { + key: 'value' + }; + + // 变量和方法使用lowerCamelCase命名 + let someVariableExample = 'value'; + function doSomething() { + + } + + } +``` + +

+ +## ![✔] 3.7 使用const优于let,废弃var + +**TL;DR:** 使用`const`意味着一旦一个变量被分配,它不能被重新分配。使用const将帮助您免于使用相同的变量用于不同的用途,并使你的代码更清晰。如果一个变量需要被重新分配,以在一个循环为例,使用`let`声明它。let的另一个重要方面是,使用let声明的变量只在定义它的块作用域中可用。 `var`是函数作用域,不是块级作用域,既然您有const和let让您随意使用,那么[不应该在ES6中使用var](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70)。 + +**否则:** 当经常更改变量时,调试变得更麻烦了。 + +🔗 [**更多: JavaScript ES6+: var, let, or const?** ](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75) + +

+ +## ![✔] 3.8 先require, 而不是在方法内部 + +**TL;DR:** 在每个文件的起始位置,在任何函数的前面和外部require模块。这种简单的最佳实践,不仅能帮助您轻松快速地在文件顶部辨别出依赖关系,而且避免了一些潜在的问题。 + +**否则:** 在Node.js中,require 是同步运行的。如果从函数中调用它们,它可能会阻塞其他请求,在更关键的时间得到处理。另外,如果所require的模块或它自己的任何依赖项抛出错误并使服务器崩溃,最好尽快查明它,如果该模块在函数中require的,则可能不是这样的情况。 + +

+ +## ![✔] 3.9 require 文件夹,而不是文件 + +**TL;DR:** 当在一个文件夹中开发库/模块,放置一个文件index.js暴露模块的 +内部,这样每个消费者都会通过它。这将作为您模块的一个接口,并使未来的变化简单而不违反规则。 + +**否则:** 更改文件内部结构或签名可能会破坏与客户端的接口。 + +### 代码示例 +```javascript + // 建议 + module.exports.SMSProvider = require('./SMSProvider'); + module.exports.SMSNumberResolver = require('./SMSNumberResolver'); + + // 避免 + module.exports.SMSProvider = require('./SMSProvider/SMSProvider.js'); + module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolver.js'); +``` + +

+ + +## ![✔] 3.10 使用 `===` 操作符 + +**TL;DR:** 对比弱等于 `==`,优先使用严格的全等于 `===` 。`==`将在它们转换为普通类型后比较两个变量。在 `===` 中没有类型转换,并且两个变量必须是相同的类型。 + +**否则:** 与 `==` 操作符比较,不相等的变量可能会返回true。 + +### 代码示例 +```javascript +'' == '0' // false +0 == '' // true +0 == '0' // true + +false == 'false' // false +false == '0' // true + +false == undefined // false +false == null // false +null == undefined // true + +' \t\r\n ' == 0 // true +``` +如果使用`===`, 上面所有语句都将返回 false。 + +

+ +## ![✔] 3.11 使用 Async Await, 避免回调 + +**TL;DR:** Node 8 LTS现已全面支持异步等待。这是一种新的方式处理异步请求,取代回调和promise。Async-await是非阻塞的,它使异步代码看起来像是同步的。您可以给你的代码的最好的礼物是用async-await提供了一个更紧凑的,熟悉的,类似try catch的代码语法。 + +**否则:** 使用回调的方式处理异步错误可能是陷入困境最快的方式 - 这种方式必须面对不停地检测错误,处理别扭的代码内嵌,难以推理编码流。 + +🔗[**更多:** async await 1.0 引导](https://github.com/yortus/asyncawait) + +

+ +## ![✔] 3.12 使用 (=>) 箭头函数 + +**TL;DR:** 尽管使用 async-await 和避免方法作为参数是被推荐的, 但当处理那些接受promise和回调的老的API的时候 - 箭头函数使代码结构更加紧凑,并保持了根方法上的语义上下文 (例如 'this')。 + +**否则:** 更长的代码(在ES5方法中)更易于产生缺陷,并读起来很是笨重。 + +🔗 [**更多: 这是拥抱箭头函数的时刻**](https://medium.com/javascript-scene/familiarity-bias-is-holding-you-back-its-time-to-embrace-arrow-functions-3d37e1a9bb75) + + +


+ +

⬆ 返回顶部

+ + +

4. 测试和总体的质量实践

+ +## ![✔] 4.1 至少,编写API(组件)测试 + +**TL;DR:** 大多数项目只是因为时间表太短而没有进行任何自动化测试,或者测试项目失控而正被遗弃。因此,优先从API测试开始,这是最简单的编写和提供比单元测试更多覆盖率的事情(你甚至可能不需要编码而进行API测试,像[Postman](https://www.getpostman.com/)。之后,如果您有更多的资源和时间,继续使用高级测试类型,如单元测试、DB测试、性能测试等。 + +**否则:** 您可能需要花很长时间编写单元测试,才发现只有20%的系统覆盖率。 + +

+ +## ![✔] 4.2 使用一个linter检测代码问题 + +**TL;DR:** 使用代码linter检查基本质量并及早检测反模式。在任何测试之前运行它, 并将其添加为预提交的git钩子, 以最小化审查和更正任何问题所需的时间。也可在[Section 3](https://github.com/goldbergyoni/nodebestpractices#3-code-style-practices)中查阅编码样式实践 + +**否则:** 您可能让一些反模式和易受攻击的代码传递到您的生产环境中。 + + +

+ +## ![✔] 4.3 仔细挑选您的持续集成(CI)平台 + +**TL;DR:** 您的持续集成平台(cicd)将集成各种质量工具(如测试、lint),所以它应该是一个充满活力的生态系统,包含各种插件。[jenkins](https://jenkins.io/)曾经是许多项目的默认选项,因为它有最大的社区,同时也是一个非常强大的平台,这样的代价是要求一个陡峭的学习曲线。如今,使用SaaS工具,比如[CircleCI](https://circleci.com)及其他,安装一套CI解决方案,相对是一件容易的事情。这些工具允许构建灵活的CI管道,而无需管理整个基础设施。最终,这是一个鲁棒性和速度之间的权衡 - 仔细选择您支持的方案。 + +**否则:** 一旦您需要一些高级定制,选择一些细分市场供应商可能会让您停滞不前。另一方面,伴随着jenkins,可能会在基础设施设置上浪费宝贵的时间。 + +🔗 [**更多: 挑选 CI 平台**](/sections/testingandquality/citools.chinese.md) + +

+ +## ![✔] 4.4 经常检查易受攻击的依赖 + +**TL;DR:** 即使是那些最有名的依赖模块,比如Express,也有已知的漏洞。使用社区和商业工具,比如 🔗 [npm audit](https://docs.npmjs.com/cli/audit) ,集成在您的CI平台上,在每一次构建的时候都会被调用,这样可以很容易地解决漏洞问题。 + +**否则:** 在没有专用工具的情况下,使代码清除漏洞,需要不断地跟踪有关新威胁的在线出版物,相当繁琐。 + +

+ +## ![✔] 4.5 测试标签化 + +**TL;DR:** 不同的测试必须运行在不同的情景:quick smoke,IO-less,当开发者保存或提交一个文件,测试应该启动;完整的端到端的测试通常运行在一个新的pull request被提交之后,等等。这可以通过对测试用例设置标签,比如关键字像#cold #api #sanity,来完成。这样您可以对您的测试集进行grep,调用需要的子集。例如,这就是您通过[Mocha](https://mochajs.org/)仅仅调用sanity测试集所需要做的:mocha --grep 'sanity'。 + +**否则:** 运行所有的测试,包括执行数据库查询的几十个测试,任何时候开发者进行小的改动都可能很慢,这使得开发者不愿意运行测试。 + +

+ +## ![✔] 4.6 检查测试覆盖率,它有助于识别错误的测试模式 + +**TL;DR:** 代码覆盖工具比如 [Istanbul](https://github.com/istanbuljs/istanbuljs)/[NYC](https://github.com/istanbuljs/nyc),很好用有3个原因:它是免费的(获得这份报告不需要任何开销),它有助于确定测试覆盖率降低的部分,以及最后但非最不重要的是它指出了测试中的不匹配:通过查看颜色标记的代码覆盖报告您可以注意到,例如,从来不会被测到的代码片段像catch语句(即测试只是调用正确的路径,而不调用应用程序发生错误时的行为)。如果覆盖率低于某个阈值,则将其设置为失败的构建。 + +**否则:** 当你的大部分代码没有被测试覆盖时,就不会有任何自动化的度量指标告诉你了。 + + + +

+ +## ![✔] 4.7 检查过期的依赖包 + +**TL;DR:** 使用您的首选工具 (例如 “npm outdated” or [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) 来检测已安装的过期依赖包, 将此检查注入您的 CI 管道, 甚至在严重的情况下使构建失败。例如, 当一个已安装的依赖包滞后5个补丁时 (例如:本地版本是1.3.1 的, 存储库版本是1.3.8 的), 或者它被其作者标记为已弃用, 可能会出现严重的情况 - 停掉这次构建并防止部署此版本。 + +**否则:** 您的生产环境将运行已被其作者明确标记为有风险的依赖包 + +

+ +## ![✔] 4.8 对于e2e testing,使用docker-compose + +**TL;DR:** 端对端(e2e)测试包含现场数据,由于它依赖于很多重型服务如数据库,习惯被认为是CI过程中最薄弱的环节。Docker-compose通过制定类似生产的环境,并使用一个简单的文本文件和简单的命令,轻松化解了这个问题。它为了e2e测试,允许制作所有相关服务,数据库和隔离网络。最后但并非最不重要的一点是,它可以保持一个无状态环境,该环境在每个测试套件之前被调用,然后立即消失。 + + +**否则:** 没有docker-compose,团队必须维护一个测试数据库在每一个测试环境上,包含开发机器,保持所有数据同步,这样测试结果不会因环境不同而不同。 + + +


+ +

⬆ 返回顶部

+ +

5. 上线实践

+ +## ![✔] 5.1. 监控! + +**TL;DR:** 监控是一种在顾客之前发现问题的游戏 – 显然这应该被赋予前所未有的重要性。考虑从定义你必须遵循的基本度量标准开始(我的建议在里面),到检查附加的花哨特性并选择解决所有问题的解决方案。市场已经淹没其中。点击下面的 ‘The Gist’ ,了解解决方案的概述。 + +**否则:** 错误 === 失望的客户. 非常简单. + + +🔗 [**更多: 监控!**](/sections/production/monitoring.chinese.md) + +

+ +## ![✔] 5.2. 使用智能日志增加透明度 + +**TL;DR:** 日志可以是调试语句的一个不能说话的仓库,或者表述应用运行过程的一个漂亮仪表板的驱动。从第1天计划您的日志平台:如何收集、存储和分析日志,以确保所需信息(例如,错误率、通过服务和服务器等完成整个事务)都能被提取出来。 + +**否则:** 您最终像是面对一个黑盒,不知道发生了什么事情,然后你开始重新写日志语句添加额外的信息。 + + +🔗 [**更多: 使用智能日志增加透明度**](/sections/production/smartlogging.chinese.md) + +

+ +## ![✔] 5.3. 委托可能的一切(例如:gzip,SSL)给反向代理 + +**TL;DR:** Node处理CPU密集型任务,如gzipping,SSL termination等,表现糟糕。相反,使用一个 ‘真正’ 的中间件服务像Nginx,HAProxy或者云供应商的服务。 + +**否则:** 可怜的单线程Node将不幸地忙于处理网络任务,而不是处理应用程序核心,性能会相应降低。 + + +🔗 [**更多: 委托可能的一切(例如:gzip,SSL)给反向代理**](/sections/production/delegatetoproxy.chinese.md) + +

+ +## ![✔] 5.4. 锁住依赖 + +**TL;DR:** 您的代码必须在所有的环境中是相同的,但是令人惊讶的是,NPM默认情况下会让依赖在不同环境下发生偏移 – 当在不同的环境中安装包的时候,它试图拿包的最新版本。克服这种问题可以利用NPM配置文件, .npmrc,告诉每个环境保存准确的(不是最新的)包的版本。另外,对于更精细的控制,使用NPM “shrinkwrap”。*更新:作为NPM5,依赖默认锁定。新的包管理工具,Yarn,也默认锁定。 + +**否则:** QA测试通过的代码和批准的版本,在生产中表现不一致。更糟糕的是,同一生产集群中的不同服务器可能运行不同的代码。 + + +🔗 [**更多: 锁住依赖**](/sections/production/lockdependencies.chinese.md) + +

+ +## ![✔] 5.5. 使用正确的工具保护进程正常运行 + +**TL;DR:** 进程必须继续运行,并在失败时重新启动。对于简单的情况下,“重启”工具如PM2可能足够,但在今天的“Dockerized”世界 – 集群管理工具也值得考虑 + +**否则:** 运行几十个实例没有明确的战略和太多的工具(集群管理,docker,PM2)可能导致一个DevOps混乱 + + +🔗 [**更多: 使用正确的工具保护进程正常运行**](/sections/production/guardprocess.chinese.md) + + +

+ +## ![✔] 5.6. 利用CPU多核 + +**TL;DR:** 在基本形式上,node应用程序运行在单个CPU核心上,而其他都处于空闲状态。复制node进程和利用多核,这是您的职责 – 对于中小应用,您可以使用Node Cluster和PM2. 对于一个大的应用,可以考虑使用一些Docker cluster(例如k8s,ECS)复制进程或基于Linux init system(例如systemd)的部署脚本 + +**否则:** 您的应用可能只是使用了其可用资源中的25% (!),甚至更少。注意,一台典型的服务器有4个或更多的CPU,默认的Node.js部署仅仅用了一个CPU(甚至使用PaaS服务,比如AWS beanstalk,也一样)。 + + +🔗 [**更多: 利用所有的CPU**](/sections/production/utilizecpu.chinese.md) + +

+ +## ![✔] 5.7. 创建一个“维护端点” + +**TL;DR:** 在一个安全的API中暴露一组系统相关的信息,比如内存使用情况和REPL等等。尽管这里强烈建议依赖标准和作战测试工具,但一些有价值的信息和操作更容易使用代码完成。 + +**否则:** 您会发现,您正在执行许多“诊断部署” – 将代码发送到生产中,仅仅只为了诊断目的提取一些信息。 + + +🔗 [**更多: 创建一个 '维护端点'**](/sections/production/createmaintenanceendpoint.chinese.md) + +

+ +## ![✔] 5.8. 使用APM产品发现错误和宕机时间 + +**TL;DR:** 监控和性能的产品(即APM)先前一步地评估代码库和API,自动的超过传统的监测,并测量在服务和层级上的整体用户体验。例如,一些APM产品可以突显导致最终用户负载过慢的事务,同时指出根本原因。 + +**否则:** 你可能会花大力气测量API性能和停机时间,也许你永远不会知道,真实场景下哪个是你最慢的代码部分,这些怎么影响用户体验。 + + +🔗 [**更多: 使用APM产品发现错误和宕机时间**](/sections/production/apmproducts.chinese.md) + + +

+ + +## ![✔] 5.9. 使您的代码保持生产环境就绪 + +**TL;DR:** 在意识中抱着最终上线的想法进行编码,从第1天开始计划上线。这听起来有点模糊,所以我编写了一些与生产维护密切相关的开发技巧(点击下面的要点) + +**否则:** 一个世界冠军级别的IT/运维人员也不能拯救一个编码低劣的系统。 + + +🔗 [**更多: 使您的代码保持生产环境就绪**](/sections/production/productioncode.chinese.md) + +

+ +## ![✔] 5.10. 测量和保护内存使用 + +**TL;DR:** Node.js和内存有引起争论的联系:V8引擎对内存的使用有稍微的限制(1.4GB),在node的代码里面有内存泄漏的很多途径 – 因此监视node的进程内存是必须的。在小应用程序中,你可以使用shell命令周期性地测量内存,但在中等规模的应用程序中,考虑把内存监控建成一个健壮的监控系统。 + +**否则:** 您的内存可能一天泄漏一百兆,就像曾发生在沃尔玛的一样。 + + +🔗 [**更多: 测量和保护内存使用**](/sections/production/measurememory.chinese.md) + +

+ + +## ![✔] 5.11. Node外管理您的前端资源 + +**TL;DR:** 使用专门的中间件(nginx,S3,CDN)服务前端内容,这是因为在处理大量静态文件的时候,由于node的单线程模型,它的性能很受影响。 + +**否则:** 您的单个node线程将忙于传输成百上千的html/图片/angular/react文件,而不是分配其所有的资源为了其擅长的任务 – 服务动态内容 + + +🔗 [**更多: Node外管理您的前端资源**](/sections/production/frontendout.chinese.md) + +

+ + +## ![✔] 5.12. 保持无状态,几乎每天都要停下服务器 + +**TL;DR:** 在外部数据存储上,存储任意类型数据(例如用户会话,缓存,上传文件)。考虑间隔地停掉您的服务器或者使用 ‘serverless’ 平台(例如 AWS Lambda),这是一个明确的强化无状态的行为。 + +**否则:** 某个服务器上的故障将导致应用程序宕机,而不仅仅是停用故障机器。此外,由于依赖特定服务器,伸缩弹性会变得更具挑战性。 + + +🔗 [**更多: 保持无状态,几乎每天都要停下服务器**](/sections/production/bestateless.chinese.md) + + +

+ + +## ![✔] 5.13. 使用自动检测漏洞的工具 + +**TL;DR:** 即使是最有信誉的依赖项,比如Express,会有使系统处于危险境地的已知漏洞(随着时间推移)。通过使用社区的或者商业工具,不时的检查漏洞和警告(本地或者Github上),这类问题很容易被抑制,有些问题甚至可以立即修补。 + +**否则:** 否则: 在没有专用工具的情况下,使代码清除漏洞,需要不断地跟踪有关新威胁的在线出版物。相当繁琐。 + + +🔗 [**更多: 使用自动检测漏洞的工具**](/sections/production/detectvulnerabilities.chinese.md) + +

+ + +## ![✔] 5.14. 在每一个log语句中指明 ‘TransactionId’ + +**TL;DR:** 在每一个请求的每一条log入口,指明同一个标识符,transaction-id: {某些值}。然后在检查日志中的错误时,很容易总结出前后发生的事情。不幸的是,由于Node异步的天性自然,这是不容易办到的,看下代码里面的例子 + +**否则:** 在没有上下文的情况下查看生产错误日志,这会使问题变得更加困难和缓慢去解决。 + + +🔗 [**更多: 在每一个log语句中指明 ‘TransactionId’**](/sections/production/assigntransactionid.chinese.md) + +

+ + +## ![✔] 5.15. 设置NODE_ENV=production + +**TL;DR:** 设置环境变量NODE_ENV为‘production’ 或者 ‘development’,这是一个是否激活上线优化的标志 - 很多NPM的包通过它来判断当前的环境,据此优化生产环境代码。 + +**否则:** 遗漏这个简单的属性可能大幅减弱性能。例如,在使用Express作为服务端渲染页面的时候,如果未设置NODE_ENV,性能将会减慢大概三分之一! + + +🔗 [**更多: 设置NODE_ENV=production**](/sections/production/setnodeenv.chinese.md) + + +

+ + +## ![✔] 5.16. 设计自动化、原子化和零停机时间部署 + +**TL;DR:** 研究表明,执行许多部署的团队降低了严重上线问题的可能性。不需要危险的手动步骤和服务停机时间的快速和自动化部署大大改善了部署过程。你应该达到使用Docker结合CI工具,使他们成为简化部署的行业标准。 + +**否则:** 长时间部署 -> 线上宕机 & 和人相关的错误 -> 团队部署时不自信 -> 更少的部署和需求 + +


+ +

⬆ 返回顶部

+ +

6. 安全最佳实践

+ +
+53 items +
+ +## ![✔] 6.1. 拥护linter安全准则 + + + +**TL;DR:** 使用安全相关的linter插件,比如[eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security),尽早捕获安全隐患或者问题,最好在编码阶段。这能帮助察觉安全的问题,比如使用eval,调用子进程,或者根据字面含义(比如,用户输入)引入模块等等。点击下面‘更多’获得一个安全linter可以检测到的代码示例。 + +**Otherwise:** 在开发过程中, 可能一个直白的安全隐患, 成为生产环境中一个严重问题。此外, 项目可能没有遵循一致的安全规范, 而导致引入漏洞, 或敏感信息被提交到远程仓库中。 + +🔗 [**更多: Lint 规范**](/sections/security/lintrules.md) + +

+ +## ![✔] 6.2. 使用中间件限制并发请求 + + + +**TL;DR:** DOS攻击非常流行而且相对容易处理。使用外部服务,比如cloud负载均衡, cloud防火墙, nginx, 或者(对于小的,不是那么重要的app)一个速率限制中间件(比如[express-rate-limit](https://www.npmjs.com/package/express-rate-limit)),来实现速率限制。 + +**否则:** 应用程序可能受到攻击, 导致拒绝服务, 在这种情况下, 真实用户会遭受服务降级或不可用。 + +🔗 [**更多: 实施速率限制**](/sections/security/limitrequests.md) + +

+ +## ![✔] 6.3 把机密信息从配置文件中抽离出来,或者使用包对其加密 + + + +**TL;DR:** 不要在配置文件或源代码中存储纯文本机密信息。相反, 使用诸如Vault产品、Kubernetes/Docker Secrets或使用环境变量之类的安全管理系统。最后一个结果是, 存储在源代码管理中的机密信息必须进行加密和管理 (滚动密钥(rolling keys)、过期时间、审核等)。使用pre-commit/push钩子防止意外提交机密信息。 + +**否则:** 源代码管理, 即使对于私有仓库, 也可能会被错误地公开, 此时所有的秘密信息都会被公开。外部组织的源代码管理的访问权限将无意中提供对相关系统 (数据库、api、服务等) 的访问。 + +🔗 [**更多: 安全管理**](/sections/security/secretmanagement.md) + +

+ +## ![✔] 6.4. 使用 ORM/ODM 库防止查询注入漏洞 + + + +**TL;DR:** 要防止 SQL/NoSQL 注入和其他恶意攻击, 请始终使用 ORM/ODM 或database库来转义数据或支持命名的或索引的参数化查询, 并注意验证用户输入的预期类型。不要只使用JavaScript模板字符串或字符串串联将值插入到查询语句中, 因为这会将应用程序置于广泛的漏洞中。所有知名的Node.js数据访问库(例如[Sequelize](https://github.com/sequelize/sequelize), [Knex](https://github.com/tgriesser/knex), [mongoose](https://github.com/Automattic/mongoose))包含对注入漏洞的内置包含措施。 + +**否则:** 未经验证或未脱敏处理的用户输入,可能会导致操作员在使用MongoDB进行NoSQL操作时进行注入, 而不使用适当的过滤系统或ORM很容易导致SQL注入攻击, 从而造成巨大的漏洞。 + +🔗 [**更多: 使用 ORM/ODM 库防止查询注入**](/sections/security/ormodmusage.md) + +

+ +## ![✔] 6.5. 通用安全最佳实际集合 + +**TL;DR:** 这些是与Node.js不直接相关的安全建议的集合-Node的实现与任何其他语言没有太大的不同。单击 "阅读更多" 浏览。 + +🔗 [**更多: 通用安全最佳实际**](/sections/security/commonsecuritybestpractices.md) + +

+ +## ![✔] 6.6. 调整 HTTP 响应头以加强安全性 + + + +**TL;DR:** 应用程序应该使用安全的header来防止攻击者使用常见的攻击方式,诸如跨站点脚本(XSS)、点击劫持和其他恶意攻击。可以使用模块,比如 [helmet](https://www.npmjs.com/package/helmet)轻松进行配置。 + +**否则:** 攻击者可以对应用程序的用户进行直接攻击, 导致巨大的安全漏洞 + +🔗 [**更多: 在应用程序中使用安全的header**](/sections/security/secureheaders.md) + +

+ +## ![✔] 6.7. 经常自动检查易受攻击的依赖库 + + + +**TL;DR:** 在npm的生态系统中, 一个项目有许多依赖是很常见的。在找到新的漏洞时, 应始终将依赖项保留在检查中。使用工具,类似于[npm audit](https://docs.npmjs.com/cli/audit) 或者 [snyk](https://snyk.io/)跟踪、监视和修补易受攻击的依赖项。将这些工具与 CI 设置集成, 以便在将其上线之前捕捉到易受攻击的依赖库。 + +**否则:** 攻击者可以检测到您的web框架并攻击其所有已知的漏洞。 + +🔗 [**更多: 安全依赖**](/sections/security/dependencysecurity.md) + +

+ +## ![✔] 6.8. 避免使用Node.js的crypto库处理密码,使用Bcrypt + + + +**TL;DR:** 密码或机密信息(API密钥)应该使用安全的哈希+salt函数(如 "bcrypt")来存储, 因为性能和安全原因, 这应该是其JavaScript实现的首选。 + +**否则:** 在不使用安全功能的情况下,保存的密码或秘密信息容易受到暴力破解和字典攻击, 最终会导致他们的泄露。 + +🔗 [**更多: 使用Bcrypt**](/sections/security/bcryptpasswords.chinese.md) + +

+ +## ![✔] 6.9. 转义 HTML、JS 和 CSS 输出 + + + +**TL;DR:** 发送给浏览器的不受信任数据可能会被执行, 而不是显示, 这通常被称为跨站点脚本(XSS)攻击。使用专用库将数据显式标记为不应执行的纯文本内容(例如:编码、转义),可以减轻这种问题。 + +**否则:** 攻击者可能会将恶意的JavaScript代码存储在您的DB中, 然后将其发送给可怜的客户端。 + +🔗 [**更多: 转义输出**](/sections/security/escape-output.md) + +

+ +## ![✔] 6.10. 验证传入的JSON schemas + + + +**TL;DR:** 验证传入请求的body payload,并确保其符合预期要求, 如果没有, 则快速报错。为了避免每个路由中繁琐的验证编码, 您可以使用基于JSON的轻量级验证架构,比如[jsonschema](https://www.npmjs.com/package/jsonschema) or [joi](https://www.npmjs.com/package/joi) + +**否则:** 您疏忽和宽松的方法大大增加了攻击面, 并鼓励攻击者尝试许多输入, 直到他们找到一些组合, 使应用程序崩溃。 + +🔗 [**更多: 验证传入的JSON schemas**](/sections/security/validation.md) + +

+ +## ![✔] 6.11. 支持黑名单的JWT + + + +**TL;DR:** 当使用JSON Web Tokens(例如, 通过[Passport.js](https://github.com/jaredhanson/passport)), 默认情况下, 没有任何机制可以从发出的令牌中撤消访问权限。一旦发现了一些恶意用户活动, 只要它们持有有效的标记, 就无法阻止他们访问系统。通过实现一个不受信任令牌的黑名单,并在每个请求上验证,来减轻此问题。 + +**否则:** 过期或错误的令牌可能被第三方恶意使用,以访问应用程序,并模拟令牌的所有者。 + +🔗 [**更多: 为JSON Web Token添加黑名单**](/sections/security/expirejwt.md) + +

+ +## ![✔] 6.12. 限制每个用户允许的登录请求 + + + +**TL;DR:** 一类保护暴力破解的中间件,比如[express-brute](https://www.npmjs.com/package/express-brute),应该被用在express的应用中,来防止暴力/字典攻击;这类攻击主要应用于一些敏感路由,比如/admin 或者 /login,基于某些请求属性, 如用户名, 或其他标识符, 如正文参数等。 + +**否则:** 攻击者可以发出无限制的密码匹配尝试, 以获取对应用程序中特权帐户的访问权限。 + +🔗 [**更多: 限制登录频率**](/sections/security/login-rate-limit.md) + +

+ +## ![✔] 6.13. 使用非root用户运行Node.js + + + +**TL;DR:** Node.js作为一个具有无限权限的root用户运行,这是一种普遍的情景。例如,在Docker容器中,这是默认行为。建议创建一个非root用户,并保存到Docker镜像中(下面给出了示例),或者通过调用带有"-u username" 的容器来代表此用户运行该进程。 + +**否则:** 在服务器上运行脚本的攻击者在本地计算机上获得无限制的权利 (例如,改变iptable,引流到他的服务器上) + +🔗 [**更多: 使用非root用户运行Node.js**](/sections/security/non-root-user.md) + +

+ +## ![✔] 6.14. 使用反向代理或中间件限制负载大小 + + + +**TL;DR:** 请求body有效载荷越大, Node.js的单线程就越难处理它。这是攻击者在没有大量请求(DOS/DDOS 攻击)的情况下,就可以让服务器跪下的机会。在边缘上(例如,防火墙,ELB)限制传入请求的body大小,或者通过配置[express body parser](https://github.com/expressjs/body-parser)仅接收小的载荷,可以减轻这种问题。 + +**否则:** 您的应用程序将不得不处理大的请求, 无法处理它必须完成的其他重要工作, 从而导致对DOS攻击的性能影响和脆弱性。 + +🔗 [**更多: 限制负载大小**](/sections/security/requestpayloadsizelimit.md) + +

+ +## ![✔] 6.15. 避免JavaScript的eval声明 + + + +**TL;DR:** `eval` 是邪恶的, 因为它允许在运行时执行自定义的JavaScript代码。这不仅是一个性能方面的问题, 而且也是一个重要的安全问题, 因为恶意的JavaScript代码可能来源于用户输入。应该避免的另一种语言功能是 `new Function` 构造函数。`setTimeout` 和 `setInterval` 也不应该传入动态JavaScript代码。 + +**否则:** 恶意JavaScript代码查找传入 `eval` 或其他实时判断的JavaScript函数的文本的方法, 并将获得在该页面上javascript权限的完全访问权。此漏洞通常表现为XSS攻击。 + +🔗 [**更多: 避免JavaScript的eval声明**](/sections/security/avoideval.chinese.md) + +

+ +## ![✔] 6.16. 防止恶意RegEx让Node.js的单线程过载执行 + + + +**TL;DR:** 正则表达式,在方便的同时,对JavaScript应用构成了真正的威胁,特别是Node.js平台。匹配文本的用户输入需要大量的CPU周期来处理。在某种程度上,正则处理是效率低下的,比如验证10个单词的单个请求可能阻止整个event loop长达6秒,并让CPU引火烧身。由于这个原因,偏向第三方的验证包,比如[validator.js](https://github.com/chriso/validator.js),而不是采用正则,或者使用[safe-regex](https://github.com/substack/safe-regex)来检测有问题的正则表达式。 + +**否则:** 写得不好的正则表达式可能容易受到正则表达式DoS攻击的影响, 这将完全阻止event loop。例如,流行的`moment`包在2017年的11月,被发现使用了错误的RegEx用法而易受攻击。 + +🔗 [**更多: 防止恶意正则**](/sections/security/regex.md) + +

+ +## ![✔] 6.17. 使用变量避免模块加载 + + + +**TL;DR:** 避免通过作为参数的路径requiring/importing另一个文件, 原因是它可能源自用户输入。此规则可扩展为访问一般文件(即:`fs.readFile()`)或使用来自用户输入的动态变量访问其他敏感资源。[Eslint-plugin-security](https://www.npmjs.com/package/eslint-plugin-security) linter可以捕捉这样的模式, 并尽早提前警告。 + +**否则:** 恶意用户输入可以找到用于获得篡改文件的参数, 例如, 文件系统上以前上载的文件, 或访问已有的系统文件。 + +🔗 [**更多: 安全地加载模块**](/sections/security/safemoduleloading.chinese.md) + +

+ +## ![✔] 6.18. 在沙箱中运行不安全代码 + + + +**TL;DR:** 当任务执行在运行时给出的外部代码时(例如, 插件), 使用任何类型的`沙盒`执行环境保护主代码,并隔离开主代码和插件。这可以通过一个专用的过程来实现 (例如:cluster.fork()), 无服务器环境或充当沙盒的专用npm包。 + +**否则:** 插件可以通过无限循环、内存超载和对敏感进程环境变量的访问等多种选项进行攻击 + +🔗 [**更多: 在沙箱中运行不安全代码**](/sections/security/sandbox.chinese.md) + +

+ +## ![✔] 6.19. 使用子进程时要格外小心 + + + +**TL;DR:** 尽可能地避免使用子进程,如果您仍然必须这样做,验证和清理输入以减轻shell注入攻击。更喜欢使用 "child_process"。execFile 的定义将只执行具有一组属性的单个命令, 并且不允许 shell 参数扩展。倾向于使用`child_process.execFile`,从定义上来说,它将仅仅执行具有一组属性的单个命令,并且不允许shell参数扩展。 + +**否则:** 由于将恶意用户输入传递给未脱敏处理的系统命令, 直接地使用子进程可能导致远程命令执行或shell注入攻击。 + +🔗 [**更多: 处理子进程时要格外小心**](/sections/security/childprocesses.chinese.md) + +

+ +## ![✔] 6.20. 隐藏客户端的错误详细信息 + + + +**TL;DR:** 默认情况下, 集成的express错误处理程序隐藏错误详细信息。但是, 极有可能, 您实现自己的错误处理逻辑与自定义错误对象(被许多人认为是最佳做法)。如果这样做, 请确保不将整个Error对象返回到客户端, 这可能包含一些敏感的应用程序详细信息。 + +**否则:** 敏感应用程序详细信息(如服务器文件路径、使用中的第三方模块和可能被攻击者利用的应用程序的其他内部工作流)可能会从stack trace发现的信息中泄露。 + +🔗 [**更多: 隐藏客户端的错误详细信息**](/sections/security/hideerrors.md) + +

+ +## ![✔] 6.21. 对npm或Yarn,配置2FA + + + +**TL;DR:** 开发链中的任何步骤都应使用MFA(多重身份验证)进行保护, npm/Yarn对于那些能够掌握某些开发人员密码的攻击者来说是一个很好的机会。使用开发人员凭据, 攻击者可以向跨项目和服务广泛安装的库中注入恶意代码。甚至可能在网络上公开发布。在npm中启用2因素身份验证(2-factor-authentication), 攻击者几乎没有机会改变您的软件包代码。 + +**否则:** [Have you heard about the eslint developer who's password was hijacked?](https://medium.com/@oprearocks/eslint-backdoor-what-it-is-and-how-to-fix-the-issue-221f58f1a8c8) + +

+ +## ![✔] 6.22. 修改session中间件设置 + + + +**TL;DR:** 每个web框架和技术都有其已知的弱点-告诉攻击者我们使用的web框架对他们来说是很大的帮助。使用session中间件的默认设置, 可以以类似于`X-Powered-By`header的方式向模块和框架特定的劫持攻击公开您的应用。尝试隐藏识别和揭露技术栈的任何内容(例如:Nonde.js, express)。 + +**否则:** 可以通过不安全的连接发送cookie, 攻击者可能会使用会话标识来标识web应用程序的基础框架以及特定于模块的漏洞。 + +🔗 [**更多: cookie和session安全**](/sections/security/sessions.md) + +

+ +## ![✔] 6.23. 通过显式设置进程应崩溃的情况,以避免DOS攻击 + + + +**TL;DR:** 当错误未被处理时, Node进程将崩溃。即使错误被捕获并得到处理,许多最佳实践甚至建议退出。例如, Express会在任何异步错误上崩溃 - 除非使用catch子句包装路由。这将打开一个非常惬意的攻击点, 攻击者识别哪些输入会导致进程崩溃并重复发送相同的请求。没有即时补救办法, 但一些技术可以减轻苦楚: 每当进程因未处理的错误而崩溃,都会发出警报,验证输入并避免由于用户输入无效而导致进程崩溃,并使用catch将所有路由处理包装起来,并在请求中出现错误时, 考虑不要崩溃(与全局发生的情况相反)。 + +**否则:** 这只是一个起到教育意义的假设: 给定许多Node.js应用程序, 如果我们尝试传递一个空的JSON正文到所有POST请求 - 少数应用程序将崩溃。在这一点上, 我们可以只是重复发送相同的请求, 就可以轻松地搞垮应用程序。 + +


+ +## ![✔] 6.24. 避免不安全的重定向 + + + +**TL;DR:** 不验证用户输入的重定向可使攻击者启动网络钓鱼诈骗,窃取用户凭据,以及执行其他恶意操作。 + +**否则:** 当攻击者发现你没有校验用户提供的外部输入时,他们会在论坛、社交媒体以和其他公共场合发布他们精心制作的链接来诱使用户点击,以此达到漏洞利用的目的。 + +🔗 [**阅读更多: 避免不安全的重定向**](/sections/security/saferedirects.chinese.md) + +


+ +

⬆ Return to top

+ +# `API Practices` + +## Our contributors are working on this section. Would you like to join? + +# `Performance Practices` + +## Our contributors are working on this section. Would you like to join? + +


+ +# Milestones +To maintain this guide and keep it up to date, we are constantly updating and improving the guidelines and best practices with the help of the community. You can follow our [milestones](https://github.com/goldbergyoni/nodebestpractices/milestones) and join the working groups if you want to contribute to this project. + +

+ +# Contributors +## `Yoni Goldberg` +Independent Node.js consultant who works with customers at USA, Europe and Israel on building large-scale scalable Node applications. Many of the best practices above were first published on his blog post at [http://www.goldbergyoni.com](http://www.goldbergyoni.com). Reach Yoni at @goldbergyoni or me@goldbergyoni.com + +## `Ido Richter` +👨‍💻 Software engineer, 🌐 web developer, 🤖 emojis enthusiast. + +## `Refael Ackermann` [@refack](https://github.com/refack) <refack@gmail.com> (he/him) +Node.js Core Collaborator, been noding since 0.4, and have noded in multiple production sites. Founded `node4good` home of [`lodash-contrib`](https://github.com/node4good/lodash-contrib), [`formage`](https://github.com/node4good/formage), and [`asynctrace`](https://github.com/node4good/asynctrace). +`refack` on freenode, Twitter, GitHub, GMail, and many other platforms. DMs are open, happy to help. + +## `Bruno Scheufler` +💻 full-stack web developer and Node.js enthusiast. + +## `Kyle Martin` [@js-kyle](https://github.com/js-kyle) +Full Stack Developer based in New Zealand, interested in architecting and building Node.js applications to perform at global scale. Keen contributor to open source software, including Node.js Core. + + +

+ +## Thank You Notes + +We appreciate any contribution, from a single word fix to a new best practice. View our contributors and [contributing documentation here!](CONTRIBUTORS.md) + +


+ diff --git a/README.md b/README.md index ca58bd06..92bb00c5 100644 --- a/README.md +++ b/README.md @@ -9,17 +9,16 @@
- 101 items Last update: March, 2020 Updated for Node 13.1.0 + 102 items Last update: November, 2020 Updated for Node 14.0.0

[![nodepractices](/assets/images/twitter-s.png)](https://twitter.com/nodepractices/) **Follow us on Twitter!** [**@nodepractices**](https://twitter.com/nodepractices/) -
-Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), [![BR](/assets/flags/BR.png)**BR**](/README.brazilian-portuguese.md), [![RU](/assets/flags/RU.png)**RU**](/README.russian.md), [![PL](/assets/flags/PL.png)**PL**](/README.polish.md), [![JA](/assets/flags/JA.png)**JA**](/README.japanese.md) [(![ES](/assets/flags/ES.png)**ES**, ![FR](/assets/flags/FR.png)**FR**, ![HE](/assets/flags/HE.png)**HE**, ![KR](/assets/flags/KR.png)**KR** and ![TR](/assets/flags/TR.png)**TR** in progress!)](#translations) +Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), [![BR](/assets/flags/BR.png)**BR**](/README.brazilian-portuguese.md), [![RU](/assets/flags/RU.png)**RU**](/README.russian.md), [![PL](/assets/flags/PL.png)**PL**](/README.polish.md), [![JA](/assets/flags/JA.png)**JA**](/README.japanese.md), [(![ES](/assets/flags/ES.png)**ES**, ![FR](/assets/flags/FR.png)**FR**, ![HE](/assets/flags/HE.png)**HE**, ![KR](/assets/flags/KR.png)**KR**, ![TR](/assets/flags/TR.png)**TR** and ![EU](/assets/flags/EU.png)**EU** in progress! )](#translations)
@@ -27,23 +26,21 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines # Latest Best Practices and News -- **:tada: Node.js best practices reached 50k stars**: Thank you to each and every contributor who helped turning this project into what it is today! We've got lots of plans for the time ahead, as we expand our ever-growing list of Node.js best practices even further. +- **✅ New best practice:** Bullet 2.12 by [Alexsey](https://github.com/Alexsey) shows how returning without awaiting to async functions leads to partial stacktraces. This might become a big deal when troubleshooting exceptions in productions that lack some of the execution frames -- **🎧 Podcast**: Yoni Goldberg from our team participated in the last JS Party Podcast (Very cool one!) episode to speak about Node.js best practices, [🎧 listen here](https://changelog.com/jsparty/139) +- **✅ New best practice:** Bullet 6.8 by Josh Hemphill recommends "Protect Users' Passwords/Secrets using BCrypt or Script". It contains an in-depth explanation about when and why each option suits a specific project. Don't miss this short guide with a brief overview of the various hashing options -- **:whale: Node.js + Docker best practices**: We've just release the Docker with Node.js section which includes 15 bullets about better coding techqniues with Docker - -- **🎤 A talk at OdessaJS**: We will speak about Node.js testing this week at the great [OdessaJS conference](https://odessajs.org/) +- **:whale: Node.js + Docker best practices**: We've just released the Docker with Node.js section which includes 15 bullets about better coding techniques with Docker

# Welcome! 3 Things You Ought To Know First -**1. You are, in fact, reading dozens of the best Node.js articles -** this repository is a summary and curation of the top-ranked content on Node.js best practices, as well as content written here by collaborators +**1. You are reading dozens of the best Node.js articles -** this repository is a summary and curation of the top-ranked content on Node.js best practices, as well as content written here by collaborators **2. It is the largest compilation, and it is growing every week -** currently, more than 80 best practices, style guides, and architectural tips are presented. New issues and pull requests are created every day to keep this live book updated. We'd love to see you contributing here, whether that is fixing code mistakes, helping with translations, or suggesting brilliant new ideas. See our [writing guidelines here](/.operations/writing-guidelines.md) -**3. Most best practices have additional info -** most bullets include a **🔗Read More** link that expands on the practice with code examples, quotes from selected blogs and more information +**3. Best practices have additional info -** most bullets include a **🔗Read More** link that expands on the practice with code examples, quotes from selected blogs, and more information

@@ -64,7 +61,7 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines ## ![✔] 1.1 Structure your solution by components -**TL;DR:** The worst large applications pitfall is maintaining a huge code base with hundreds of dependencies - such a monolith slows down developers as they try to incorporate new features. Instead, partition your code into components, each gets its own folder or a dedicated codebase, and ensure that each unit is kept small and simple. Visit 'Read More' below to see examples of correct project structure +**TL;DR:** The worst large applications pitfall is maintaining a huge code base with hundreds of dependencies - such a monolith slows down developers as they try to incorporate new features. Instead, partition your code into components, each gets its folder or a dedicated codebase, and ensure that each unit is kept small and simple. Visit 'Read More' below to see examples of correct project structure **Otherwise:** When developers who code new features struggle to realize the impact of their change and fear to break other dependent components - deployments become slower and riskier. It's also considered harder to scale-out when all the business units are not separated @@ -84,9 +81,9 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines ## ![✔] 1.3 Wrap common utilities as npm packages -**TL;DR:** In a large app that constitutes a large code base, cross-cutting-concern utilities like logger, encryption and alike, should be wrapped by your own code and exposed as private npm packages. This allows sharing them among multiple code bases and projects +**TL;DR:** In a large app that constitutes a large codebase, cross-cutting-concern utilities like a logger, encryption and alike, should be wrapped by your code and exposed as private npm packages. This allows sharing them among multiple codebases and projects -**Otherwise:** You'll have to invent your own deployment and dependency wheel +**Otherwise:** You'll have to invent your deployment and the dependency wheel 🔗 [**Read More: Structure by feature**](/sections/projectstructre/wraputilities.md) @@ -106,7 +103,7 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines **TL;DR:** A perfect and flawless configuration setup should ensure (a) keys can be read from file AND from environment variable (b) secrets are kept outside committed code (c) config is hierarchical for easier findability. There are a few packages that can help tick most of those boxes like [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config), and [convict](https://www.npmjs.com/package/convict). -**Otherwise:** Failing to satisfy any of the config requirements will simply bog down the development or devops team. Probably both +**Otherwise:** Failing to satisfy any of the config requirements will simply bog down the development or DevOps team. Probably both 🔗 [**Read More: configuration best practices**](/sections/projectstructre/configguide.md) @@ -138,7 +135,7 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines ## ![✔] 2.3 Distinguish operational vs programmer errors -**TL;DR:** Operational errors (e.g. API received an invalid input) refer to known cases where the error impact is fully understood and can be handled thoughtfully. On the other hand, programmer error (e.g. trying to read undefined variable) refers to unknown code failures that dictate to gracefully restart the application +**TL;DR:** Operational errors (e.g. API received an invalid input) refer to known cases where the error impact is fully understood and can be handled thoughtfully. On the other hand, programmer error (e.g. trying to read an undefined variable) refers to unknown code failures that dictate to gracefully restart the application **Otherwise:** You may always restart the application when an error appears, but why let ~5000 online users down because of a minor, predicted, operational error? the opposite is also not ideal – keeping the application up when an unknown issue (programmer error) occurred might lead to an unpredicted behavior. Differentiating the two allows acting tactfully and applying a balanced approach based on the given context @@ -168,7 +165,7 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines ## ![✔] 2.6 Exit the process gracefully when a stranger comes to town -**TL;DR:** When an unknown error occurs (a developer error, see best practice 2.3) - there is uncertainty about the application healthiness. A common practice suggests restarting the process carefully using a process management tool like [Forever](https://www.npmjs.com/package/forever) or [PM2](http://pm2.keymetrics.io/) +**TL;DR:** When an unknown error occurs (a developer error, see best practice 2.3) - there is uncertainty about the application healthiness. Common practice suggests restarting the process carefully using a process management tool like [Forever](https://www.npmjs.com/package/forever) or [PM2](http://pm2.keymetrics.io/) **Otherwise:** When an unfamiliar exception occurs, some object might be in a faulty state (e.g. an event emitter which is used globally and not firing events anymore due to some internal failure) and all future requests might fail or behave crazily @@ -198,7 +195,7 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines ## ![✔] 2.9 Discover errors and downtime using APM products -**TL;DR:** Monitoring and performance products (a.k.a APM) proactively gauge your codebase or API so they can automagically highlight errors, crashes and slow parts that you were missing +**TL;DR:** Monitoring and performance products (a.k.a APM) proactively gauge your codebase or API so they can automagically highlight errors, crashes, and slow parts that you were missing **Otherwise:** You might spend great effort on measuring API performance and downtimes, probably you’ll never be aware which are your slowest code parts under real-world scenario and how these affect the UX @@ -208,7 +205,7 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines ## ![✔] 2.10 Catch unhandled promise rejections -**TL;DR:** Any exception thrown within a promise will get swallowed and discarded unless a developer didn’t forget to explicitly handle. Even if your code is subscribed to `process.uncaughtException`! Overcome this by registering to the event `process.unhandledRejection` +**TL;DR:** Any exception thrown within a promise will get swallowed and discarded unless a developer didn’t forget to explicitly handle it. Even if your code is subscribed to `process.uncaughtException`! Overcome this by registering to the event `process.unhandledRejection` **Otherwise:** Your errors will get swallowed and leave no trace. Nothing to worry about @@ -224,6 +221,20 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines 🔗 [**Read More: failing fast**](/sections/errorhandling/failfast.md) +

+ +## ![✔] 2.12 Always await promises before returning to avoid a partial stacktrace + +**TL;DR:** Always do `return await` when returning a promise to benefit full error stacktrace. If a +function returns a promise, that function must be declared as `async` function and explicitly +`await` the promise before returning it + +**Otherwise:** The function that returns a promise without awaiting won't appear in the stacktrace. +Such missing frames would probably complicate the understanding of the flow that leads to the error, +especially if the cause of the abnormal behavior is inside of the missing function + +🔗 [**Read More: returning promises**](/sections/errorhandling/returningpromises.md) +


⬆ Return to top

@@ -244,7 +255,7 @@ Read in a different language: [![CN](/assets/flags/CN.png)**CN**](/README.chines **TL;DR:** On top of ESLint standard rules that cover vanilla JavaScript, add Node.js specific plugins like [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node), [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) and [eslint-plugin-node-security](https://www.npmjs.com/package/eslint-plugin-security) -**Otherwise:** Many faulty Node.js code patterns might escape under the radar. For example, developers might require(variableAsPath) files with a variable given as path which allows attackers to execute any JS script. Node.js linters can detect such patterns and complain early +**Otherwise:** Many faulty Node.js code patterns might escape under the radar. For example, developers might require(variableAsPath) files with a variable given as a path which allows attackers to execute any JS script. Node.js linters can detect such patterns and complain early

@@ -261,8 +272,7 @@ function someFunction() { } // Avoid -function someFunction() -{ +function someFunction() { // code block } ``` @@ -279,7 +289,7 @@ No matter if you use semicolons or not to separate your statements, knowing the **TL;DR:** Use ESLint to gain awareness about separation concerns. [Prettier](https://prettier.io/) or [Standardjs](https://standardjs.com/) can automatically resolve these issues. -**Otherwise:** As seen in the previous section, JavaScript's interpreter automatically adds a semicolon at the end of a statement if there isn't one, or considers a statement as not ended where it should, which might lead to some undesired results. You can use assignments and avoid using immediate invoked function expressions to prevent most of unexpected errors. +**Otherwise:** As seen in the previous section, JavaScript's interpreter automatically adds a semicolon at the end of a statement if there isn't one, or considers a statement as not ended where it should, which might lead to some undesired results. You can use assignments and avoid using immediately invoked function expressions to prevent most of the unexpected errors. ### Code example @@ -329,7 +339,7 @@ const count = 2 // it tries to run 2(), but 2 is not a function **TL;DR:** Use **_lowerCamelCase_** when naming constants, variables and functions and **_UpperCamelCase_** (capital first letter as well) when naming classes. This will help you to easily distinguish between plain variables/functions, and classes that require instantiation. Use descriptive names, but try to keep them short -**Otherwise:** Javascript is the only language in the world which allows invoking a constructor ("Class") directly without instantiating it first. Consequently, Classes and function-constructors are differentiated by starting with UpperCamelCase +**Otherwise:** Javascript is the only language in the world that allows invoking a constructor ("Class") directly without instantiating it first. Consequently, Classes and function-constructors are differentiated by starting with UpperCamelCase ### 3.6 Code Example @@ -339,7 +349,7 @@ class SomeClassExample {} // for const names we use the const keyword and lowerCamelCase const config = { - key: "value" + key: "value", }; // for variables and functions names we use lowerCamelCase @@ -351,7 +361,7 @@ function doSomething() {} ## ![✔] 3.7 Prefer const over let. Ditch the var -**TL;DR:** Using `const` means that once a variable is assigned, it cannot be reassigned. Preferring `const` will help you to not be tempted to use the same variable for different uses, and make your code clearer. If a variable needs to be reassigned, in a for loop, for example, use `let` to declare it. Another important aspect of `let` is that a variable declared using it is only available in the block scope in which it was defined. `var` is function scoped, not block scoped, and [shouldn't be used in ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) now that you have `const` and `let` at your disposal +**TL;DR:** Using `const` means that once a variable is assigned, it cannot be reassigned. Preferring `const` will help you to not be tempted to use the same variable for different uses, and make your code clearer. If a variable needs to be reassigned, in a for loop, for example, use `let` to declare it. Another important aspect of `let` is that a variable declared using it is only available in the block scope in which it was defined. `var` is function scoped, not block-scoped, and [shouldn't be used in ES6](https://hackernoon.com/why-you-shouldnt-use-var-anymore-f109a58b9b70) now that you have `const` and `let` at your disposal **Otherwise:** Debugging becomes way more cumbersome when following a variable that frequently changes @@ -363,11 +373,11 @@ function doSomething() {} **TL;DR:** Require modules at the beginning of each file, before and outside of any functions. This simple best practice will not only help you easily and quickly tell the dependencies of a file right at the top but also avoids a couple of potential problems -**Otherwise:** Requires are run synchronously by Node.js. If they are called from within a function, it may block other requests from being handled at a more critical time. Also, if a required module or any of its own dependencies throw an error and crash the server, it is best to find out about it as soon as possible, which might not be the case if that module is required from within a function +**Otherwise:** Requires are run synchronously by Node.js. If they are called from within a function, it may block other requests from being handled at a more critical time. Also, if a required module or any of its dependencies throw an error and crash the server, it is best to find out about it as soon as possible, which might not be the case if that module is required from within a function

-## ![✔] 3.9 Require modules by folders, opposed to the files directly +## ![✔] 3.9 Require modules by folders, as opposed to the files directly **TL;DR:** When developing a module/library in a folder, place an index.js file that exposes the module's internals so every consumer will pass through it. This serves as an 'interface' to your module and eases future changes without breaking the contract @@ -418,9 +428,9 @@ All statements above will return false if used with `===` **TL;DR:** Node 8 LTS now has full support for Async-await. This is a new way of dealing with asynchronous code which supersedes callbacks and promises. Async-await is non-blocking, and it makes asynchronous code look synchronous. The best gift you can give to your code is using async-await which provides a much more compact and familiar code syntax like try-catch -**Otherwise:** Handling async errors in callback style is probably the fastest way to hell - this style forces to check errors all over, deal with awkward code nesting and makes it difficult to reason about the code flow +**Otherwise:** Handling async errors in callback style are probably the fastest way to hell - this style forces to check errors all over, deal with awkward code nesting, and makes it difficult to reason about the code flow -🔗[**Read more:** Guide to async await 1.0](https://github.com/yortus/asyncawait) +🔗[**Read more:** Guide to async-await 1.0](https://github.com/yortus/asyncawait)

@@ -448,7 +458,7 @@ All statements above will return false if used with `===` ## ![✔] 4.2 Include 3 parts in each test name -**TL;DR:** Make the test speak at the requirements level so it's self explanatory also to QA engineers and developers who are not familiar with the code internals. State in the test name what is being tested (unit under test), under what circumstances and what is the expected result +**TL;DR:** Make the test speak at the requirements level so it's self-explanatory also to QA engineers and developers who are not familiar with the code internals. State in the test name what is being tested (unit under test), under what circumstances, and what is the expected result **Otherwise:** A deployment just failed, a test named “Add product” failed. Does this tell you what exactly is malfunctioning? @@ -458,9 +468,9 @@ All statements above will return false if used with `===` ## ![✔] 4.3 Structure tests by the AAA pattern -**TL;DR:** Structure your tests with 3 well-separated sections: Arrange, Act & Assert (AAA). The first part includes the test setup, then the execution of the unit under test and finally the assertion phase. Following this structure guarantees that the reader spends no brain CPU on understanding the test plan +**TL;DR:** Structure your tests with 3 well-separated sections: Arrange, Act & Assert (AAA). The first part includes the test setup, then the execution of the unit under test, and finally the assertion phase. Following this structure guarantees that the reader spends no brain CPU on understanding the test plan -**Otherwise:** Not only you spend long daily hours on understanding the main code, now also what should have been the simple part of the day (testing) stretches your brain +**Otherwise:** Not only you spend long daily hours on understanding the main code, but now also what should have been the simple part of the day (testing) stretches your brain 🔗 [**Read More: Structure tests by the AAA pattern**](/sections/testingandquality/aaa.md) @@ -468,7 +478,7 @@ All statements above will return false if used with `===` ## ![✔] 4.4 Detect code issues with a linter -**TL;DR:** Use a code linter to check basic quality and detect anti-patterns early. Run it before any test and add it as a pre-commit git-hook to minimize the time needed to review and correct any issue. Also check [Section 3](#3-code-style-practices) on Code Style Practices +**TL;DR:** Use a code linter to check the basic quality and detect anti-patterns early. Run it before any test and add it as a pre-commit git-hook to minimize the time needed to review and correct any issue. Also check [Section 3](#3-code-style-practices) on Code Style Practices **Otherwise:** You may let pass some anti-pattern and possible vulnerable code to your production environment. @@ -476,7 +486,7 @@ All statements above will return false if used with `===` ## ![✔] 4.5 Avoid global test fixtures and seeds, add data per-test -**TL;DR:** To prevent tests coupling and easily reason about the test flow, each test should add and act on its own set of DB rows. Whenever a test needs to pull or assume the existence of some DB data - it must explicitly add that data and avoid mutating any other records +**TL;DR:** To prevent test coupling and easily reason about the test flow, each test should add and act on its own set of DB rows. Whenever a test needs to pull or assume the existence of some DB data - it must explicitly add that data and avoid mutating any other records **Otherwise:** Consider a scenario where deployment is aborted due to failing tests, team is now going to spend precious investigation time that ends in a sad conclusion: the system works well, the tests however interfere with each other and break the build @@ -510,7 +520,7 @@ All statements above will return false if used with `===` ## ![✔] 4.9 Inspect for outdated packages -**TL;DR:** Use your preferred tool (e.g. 'npm outdated' or [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) to detect installed packages which are outdated, inject this check into your CI pipeline and even make a build fail in a severe scenario. For example, a severe scenario might be when an installed package is 5 patch commits behind (e.g. local version is 1.3.1 and repository version is 1.3.8) or it is tagged as deprecated by its author - kill the build and prevent deploying this version +**TL;DR:** Use your preferred tool (e.g. 'npm outdated' or [npm-check-updates](https://www.npmjs.com/package/npm-check-updates) to detect installed outdated packages, inject this check into your CI pipeline and even make a build fail in a severe scenario. For example, a severe scenario might be when an installed package is 5 patch commits behind (e.g. local version is 1.3.1 and repository version is 1.3.8) or it is tagged as deprecated by its author - kill the build and prevent deploying this version **Otherwise:** Your production will run packages that have been explicitly tagged by their author as risky @@ -526,7 +536,7 @@ All statements above will return false if used with `===` ## ![✔] 4.11 Refactor regularly using static analysis tools -**TL;DR:** Using static analysis tools helps by giving objective ways to improve code quality and keeps your code maintainable. You can add static analysis tools to your CI build to fail when it finds code smells. Its main selling points over plain linting are the ability to inspect quality in the context of multiple files (e.g. detect duplications), perform advanced analysis (e.g. code complexity) and follow the history and progress of code issues. Two examples of tools you can use are [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube)) and [Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate)). +**TL;DR:** Using static analysis tools helps by giving objective ways to improve code quality and keeps your code maintainable. You can add static analysis tools to your CI build to fail when it finds code smells. Its main selling points over plain linting are the ability to inspect quality in the context of multiple files (e.g. detect duplications), perform advanced analysis (e.g. code complexity), and follow the history and progress of code issues. Two examples of tools you can use are [Sonarqube](https://www.sonarqube.org/) (2,600+ [stars](https://github.com/SonarSource/sonarqube)) and [Code Climate](https://codeclimate.com/) (1,500+ [stars](https://github.com/codeclimate/codeclimate)). **Otherwise:** With poor code quality, bugs and performance will always be an issue that no shiny new library or state of the art features can fix @@ -536,7 +546,7 @@ All statements above will return false if used with `===` ## ![✔] 4.12 Carefully choose your CI platform (Jenkins vs CircleCI vs Travis vs Rest of the world) -**TL;DR:** Your continuous integration platform (CICD) will host all the quality tools (e.g test, lint) so it should come with a vibrant ecosystem of plugins. [Jenkins](https://jenkins.io/) used to be the default for many projects as it has the biggest community along with a very powerful platform at the price of complex setup that demands a steep learning curve. Nowadays, it has become much easier to set up a CI solution using SaaS tools like [CircleCI](https://circleci.com) and others. These tools allow crafting a flexible CI pipeline without the burden of managing the whole infrastructure. Eventually, it's a trade-off between robustness and speed - choose your side carefully +**TL;DR:** Your continuous integration platform (CICD) will host all the quality tools (e.g test, lint) so it should come with a vibrant ecosystem of plugins. [Jenkins](https://jenkins.io/) used to be the default for many projects as it has the biggest community along with a very powerful platform at the price of a complex setup that demands a steep learning curve. Nowadays, it has become much easier to set up a CI solution using SaaS tools like [CircleCI](https://circleci.com) and others. These tools allow crafting a flexible CI pipeline without the burden of managing the whole infrastructure. Eventually, it's a trade-off between robustness and speed - choose your side carefully **Otherwise:** Choosing some niche vendor might get you blocked once you need some advanced customization. On the other hand, going with Jenkins might burn precious time on infrastructure setup @@ -544,7 +554,7 @@ All statements above will return false if used with `===` ## ![✔] 4.13 Test your middlewares in isolation -**TL;DR:** When a middleware holds some immense logic that spans many request, it worth testing it in isolation without waking up the entire web framework. This can be easily achieved by stubbing and spying on the {req, res, next} objects +**TL;DR:** When a middleware holds some immense logic that spans many requests, it is worth testing it in isolation without waking up the entire web framework. This can be easily achieved by stubbing and spying on the {req, res, next} objects **Otherwise:** A bug in Express middleware === a bug in all or most requests @@ -734,7 +744,7 @@ All statements above will return false if used with `===`

-## ![✔] 5.19. Install your packages with `npm ci` +## ![✔] 5.19. Install your packages with `npm ci` **TL;DR:** You have to be sure that production code uses the exact version of the packages you have tested it with. Run `npm ci` to strictly do a clean install of your dependencies matching package.json and package-lock.json. Using this command is recommended in automated environments such as continuous integration pipelines. @@ -832,15 +842,15 @@ All statements above will return false if used with `===`

-## ![✔] 6.8. Avoid using the Node.js crypto library for handling passwords, use Bcrypt +## ![✔] 6.8. Protect Users' Passwords/Secrets using brypt or scrypt -**TL;DR:** Passwords or secrets (API keys) should be stored using a secure hash + salt function like `bcrypt`, that should be a preferred choice over its JavaScript implementation due to performance and security reasons. +**TL;DR:** Passwords or secrets (e.g. API keys) should be stored using a secure hash + salt function like `bcrypt`,`scrypt`, or worst case `pbkdf2`. -**Otherwise:** Passwords or secrets that are persisted without using a secure function are vulnerable to brute forcing and dictionary attacks that will lead to their disclosure eventually. +**Otherwise:** Passwords and secrets that are stored without using a secure function are vulnerable to brute forcing and dictionary attacks that will lead to their disclosure eventually. -🔗 [**Read More: Use Bcrypt**](/sections/security/bcryptpasswords.md) +🔗 [**Read More: User Passwords**](/sections/security/userpasswords.md)

@@ -868,15 +878,15 @@ All statements above will return false if used with `===`

-## ![✔] 6.11. Support blacklisting JWTs +## ![✔] 6.11. Support blocklisting JWTs -**TL;DR:** When using JSON Web Tokens (for example, with [Passport.js](https://github.com/jaredhanson/passport)), by default there's no mechanism to revoke access from issued tokens. Once you discover some malicious user activity, there's no way to stop them from accessing the system as long as they hold a valid token. Mitigate this by implementing a blacklist of untrusted tokens that are validated on each request. +**TL;DR:** When using JSON Web Tokens (for example, with [Passport.js](https://github.com/jaredhanson/passport)), by default there's no mechanism to revoke access from issued tokens. Once you discover some malicious user activity, there's no way to stop them from accessing the system as long as they hold a valid token. Mitigate this by implementing a blocklist of untrusted tokens that are validated on each request. **Otherwise:** Expired, or misplaced tokens could be used maliciously by a third party to access an application and impersonate the owner of the token. -🔗 [**Read More: Blacklist JSON Web Tokens**](/sections/security/expirejwt.md) +🔗 [**Read More: Blocklist JSON Web Tokens**](/sections/security/expirejwt.md)

@@ -1039,7 +1049,7 @@ All statements above will return false if used with `===` -**TL;DR:** Precautions should be taken to avoid the risk of accidentally publishing secrets to public npm registries. An `.npmignore` file can be used to blacklist specific files or folders, or the `files` array in `package.json` can act as a whitelist. +**TL;DR:** Precautions should be taken to avoid the risk of accidentally publishing secrets to public npm registries. An `.npmignore` file can be used to ignore specific files or folders, or the `files` array in `package.json` can act as an allow list. **Otherwise:** Your project's API keys, passwords or other secrets are open to be abused by anyone who comes across them, which may result in financial loss, impersonation, and other risks. @@ -1242,12 +1252,11 @@ In addition, referring to an image tag means that the base image is subject to c


- ## ![✔] 8.15. Lint your Dockerfile **TL;DR:** Linting your Dockerfile is an important step to identify issues in your Dockerfile which differ from best practices. By checking for potential flaws using a specialised Docker linter, performance and security improvements can be easily identified, saving countless hours of wasted time or security issues in production code. -**Otherwise:** Mistakenely the Dockerfile creator left Root as the production user, and also used an image from unknown source repository. This could be avoided with with just a simple linter. +**Otherwise:** Mistakenly the Dockerfile creator left Root as the production user, and also used an image from unknown source repository. This could be avoided with with just a simple linter. 🔗 [**Read More: Lint your Dockerfile**](/sections/docker/lint-dockerfile.md) @@ -1280,6 +1289,7 @@ All translations are contributed by the community. We will be happy to get any h - ![KR](/assets/flags/KR.png) [Korean](README.korean.md) - Courtesy of [Sangbeom Han](https://github.com/uronly14me) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/94)) - ![ES](/assets/flags/ES.png) [Spanish](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/95)) - ![TR](/assets/flags/TR.png) Turkish ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/139)) +- ![EU](/assets/flags/EU.png) [Basque](README.basque.md) - Courtesy of [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/842))

@@ -1357,6 +1367,7 @@ Our collaborators are members who are contributing to the repository on a regula
## Contributing + If you've ever wanted to contribute to open source, now is your chance! See the [contributing docs](.operations/CONTRIBUTING.md) for more information. ## Contributors ✨ @@ -1368,155 +1379,184 @@ Thanks goes to these wonderful people who have contributed to this repository! - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Kevin Rambaud

🖋

Michael Fine

🖋

Shreya Dahal

🖋

Matheus Cruz Rocha

🖋

Yog Mehta

🖋

Kudakwashe Paradzayi

🖋

t1st3

🖋

Kevin Rambaud

🖋

Michael Fine

🖋

Shreya Dahal

🖋

Matheus Cruz Rocha

🖋

Yog Mehta

🖋

Kudakwashe Paradzayi

🖋

t1st3

🖋

mulijordan1976

🖋

Matan Kushner

🖋

Fabio Hiroki

🖋

James Sumners

🖋

Dan Gamble

🖋

PJ Trainor

🖋

Remek Ambroziak

🖋

mulijordan1976

🖋

Matan Kushner

🖋

Fabio Hiroki

🖋

James Sumners

🖋

Dan Gamble

🖋

PJ Trainor

🖋

Remek Ambroziak

🖋

Yoni Jah

🖋

Misha Khokhlov

🖋

Evgeny Orekhov

🖋

-

🖋

Isaac Halvorson

🖋

Vedran Karačić

🖋

lallenlowe

🖋

Yoni Jah

🖋

Misha Khokhlov

🖋

Evgeny Orekhov

🖋

-

🖋

Isaac Halvorson

🖋

Vedran Karačić

🖋

lallenlowe

🖋

Nathan Wells

🖋

Paulo Reis

🖋

syzer

🖋

David Sancho

🖋

Robert Manolea

🖋

Xavier Ho

🖋

Aaron

🖋

Nathan Wells

🖋

Paulo Reis

🖋

syzer

🖋

David Sancho

🖋

Robert Manolea

🖋

Xavier Ho

🖋

Aaron

🖋

Jan Charles Maghirang Adona

🖋

Allen

🖋

Leonardo Villela

🖋

Michał Załęcki

🖋

Chris Nicola

🖋

Alejandro Corredor

🖋

cwar

🖋

Jan Charles Maghirang Adona

🖋

Allen

🖋

Leonardo Villela

🖋

Michał Załęcki

🖋

Chris Nicola

🖋

Alejandro Corredor

🖋

cwar

🖋

Yuwei

🖋

Utkarsh Bhatt

🖋

Duarte Mendes

🖋

Jason Kim

🖋

Mitja O.

🖋

Sandro Miguel Marques

🖋

Gabe

🖋

Yuwei

🖋

Utkarsh Bhatt

🖋

Duarte Mendes

🖋

Jason Kim

🖋

Mitja O.

🖋

Sandro Miguel Marques

🖋

Gabe

🖋

Ron Gross

🖋

Valeri Karpov

🖋

Sergio Bernal

🖋

Nikola Telkedzhiev

🖋

Vitor Godoy

🖋

Manish Saraan

🖋

Sangbeom Han

🖋

Ron Gross

🖋

Valeri Karpov

🖋

Sergio Bernal

🖋

Nikola Telkedzhiev

🖋

Vitor Godoy

🖋

Manish Saraan

🖋

Sangbeom Han

🖋

blackmatch

🖋

Joe Reeve

🖋

Ryan Busby

🖋

Iman Mohamadi

🖋

Sergii Paryzhskyi

🖋

Kapil Patel

🖋

迷渡

🖋

blackmatch

🖋

Joe Reeve

🖋

Ryan Busby

🖋

Iman Mohamadi

🖋

Sergii Paryzhskyi

🖋

Kapil Patel

🖋

迷渡

🖋

Hozefa

🖋

Ethan

🖋

Sam

🖋

Arlind

🖋

Teddy Toussaint

🖋

Lewis

🖋

Gabriel Lidenor

🖋

Hozefa

🖋

Ethan

🖋

Sam

🖋

Arlind

🖋

Teddy Toussaint

🖋

Lewis

🖋

Gabriel Lidenor

🖋

Roman

🖋

Francozeira

🖋

Invvard

🖋

Rômulo Garofalo

🖋

Tho Q Luong

🖋

Burak Shen

🖋

Martin Muzatko

🖋

Roman

🖋

Francozeira

🖋

Invvard

🖋

Rômulo Garofalo

🖋

Tho Q Luong

🖋

Burak Shen

🖋

Martin Muzatko

🖋

Jared Collier

🖋

Hilton Meyer

🖋

ChangJoo Park(박창주)

🖋

Masahiro Sakaguchi

🖋

Keith Holliday

🖋

coreyc

🖋

Maximilian Berkmann

🖋

Jared Collier

🖋

Hilton Meyer

🖋

ChangJoo Park(박창주)

🖋

Masahiro Sakaguchi

🖋

Keith Holliday

🖋

coreyc

🖋

Maximilian Berkmann

🖋

Douglas Mariano Valero

🖋

Marcelo Melo

🖋

Mehmet Perk

🖋

ryan ouyang

🖋

Shabeer

🖋

Eduard Kyvenko

🖋

Deyvison Rocha

🖋

Douglas Mariano Valero

🖋

Marcelo Melo

🖋

Mehmet Perk

🖋

ryan ouyang

🖋

Shabeer

🖋

Eduard Kyvenko

🖋

Deyvison Rocha

🖋

George Mamer

🖋

Konstantinos Leimonis

🖋

Oliver Lluberes

🌍

Tien Do

🖋

Ranvir Singh

🖋

Vadim Nicolaev

🖋

German Gamboa Gonzalez

🖋

George Mamer

🖋

Konstantinos Leimonis

🖋

Oliver Lluberes

🌍

Tien Do

🖋

Ranvir Singh

🖋

Vadim Nicolaev

🖋 🌍

German Gamboa Gonzalez

🖋

Hafez

🖋

Chandiran

🖋

VinayaSathyanarayana

🖋

Kim Kern

🖋

Kenneth Freitas

🖋

songe

🖋

Kirill Shekhovtsov

🖋

Hafez

🖋

Chandiran

🖋

VinayaSathyanarayana

🖋

Kim Kern

🖋

Kenneth Freitas

🖋

songe

🖋

Kirill Shekhovtsov

🖋

Serge

🖋

keyrwinz

🖋

Dmitry Nikitenko

🖋

bushuai

👀 🖋

Benjamin Gruenbaum

🖋

Ezequiel

🌍

Juan José Rodríguez

🌍

Serge

🖋

keyrwinz

🖋

Dmitry Nikitenko

🖋

bushuai

👀 🖋

Benjamin Gruenbaum

🖋

Ezequiel

🌍

Juan José Rodríguez

🌍

Or Bin

🖋

Andreo Vieira

🖋

Michael Solomon

🖋

Jimmy Callin

🖋

Siddharth

🖋

Ryan Smith

🖋

Tom Boettger

🖋

Or Bin

🖋

Andreo Vieira

🖋

Michael Solomon

🖋

Jimmy Callin

🖋

Siddharth

🖋

Ryan Smith

🖋

Tom Boettger

🖋

Joaquín Ormaechea

🌍

dfrzuz

🌍

Joaquín Ormaechea

🌍

dfrzuz

🌍

Victor Homyakov

🖋

Josh

🖋 🛡️

Alec Francis

🖋

arjun6610

🖋

Jan Osch

🖋

Thiago Rotondo Sampaio

🌍

Alexsey

🖋

Luis A. Acurero

🌍

Lucas Romano

🌍

Denise Case

🖋

Nick Ribal

🖋

0xflotus

🖋

Jonathan Chen

🖋

Dilan Srilal

🖋

vladthelittleone

🌍

Nik Osvalds

🖋

Daniel Kiss

📖

Forresst

🖋

Jonathan Svenheden

🖋

AustrisC

🖋

kyeongtae kim

🌍

007

🖋
- + + diff --git a/README.polish.md b/README.polish.md index 9d3accbd..2f9e7d44 100644 --- a/README.polish.md +++ b/README.polish.md @@ -18,7 +18,7 @@
-Przeczytaj także w innych językach: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), [![BR](/assets/flags/BR.png)**BR**](/README.brazilian-portuguese.md), [![RU](/assets/flags/RU.png)**RU**](/README.russian.md) [(![ES](/assets/flags/ES.png)**ES**, ![FR](/assets/flags/FR.png)**FR**, ![HE](/assets/flags/HE.png)**HE**, ![KR](/assets/flags/KR.png)**KR** i ![TR](/assets/flags/TR.png)**TR** w trakcie!)](#tłumaczenia) +Przeczytaj także w innych językach: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), [![BR](/assets/flags/BR.png)**BR**](/README.brazilian-portuguese.md), [![RU](/assets/flags/RU.png)**RU**](/README.russian.md) [(![ES](/assets/flags/ES.png)**ES**, ![FR](/assets/flags/FR.png)**FR**, ![HE](/assets/flags/HE.png)**HE**, ![KR](/assets/flags/KR.png)**KR**, ![TR](/assets/flags/TR.png)**TR**, ![EU](/assets/flags/EU.png)**EU** w trakcie! )](#tłumaczenia)
@@ -99,9 +99,9 @@ Przeczytaj także w innych językach: [![CN](/assets/flags/CN.png)**CN**](/READM ## ![✔] 1.5 Używaj konfiguracji przyjaznej środowisku, bezpiecznej i hierarchicznej - **TL;DR:** Idealne i bezbłędne ustawienie konfiguracji powinno zapewnić, że (a) klucze można odczytać z pliku ORAZ ze zmiennych środowiskowych (b) dane wrażliwe są przechowywane poza zatwierdzonym kodem (c) konfiguracja jest hierarchiczna dla łatwiejszego wyszukiwania. Istnieje kilka pakietów, które mogą pomóc zaznaczyć większość z tych pól, takich jak [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) i [convict](https://www.npmjs.com/package/convict) - - **W przeciwnym razie:** Niespełnienie któregokolwiek z wymagań konfiguracji po prostu ugrzęźnie w zespole programistów lub DevOps. Prawdopodobnie jedno i drugie +**TL;DR:** Idealne i bezbłędne ustawienie konfiguracji powinno zapewnić, że (a) klucze można odczytać z pliku ORAZ ze zmiennych środowiskowych (b) dane wrażliwe są przechowywane poza zatwierdzonym kodem (c) konfiguracja jest hierarchiczna dla łatwiejszego wyszukiwania. Istnieje kilka pakietów, które mogą pomóc zaznaczyć większość z tych pól, takich jak [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config) i [convict](https://www.npmjs.com/package/convict) + +**W przeciwnym razie:** Niespełnienie któregokolwiek z wymagań konfiguracji po prostu ugrzęźnie w zespole programistów lub DevOps. Prawdopodobnie jedno i drugie 🔗 [**Czytaj więcej: najlepsze praktyki dotyczące konfiguracji**](/sections/projectstructre/configguide.polish.md) @@ -109,7 +109,7 @@ Przeczytaj także w innych językach: [![CN](/assets/flags/CN.png)**CN**](/READM

⬆ Wróć na górę

- # `2. Procedury obsługi błędów` +# `2. Procedury obsługi błędów` ## ![✔] 2.1 Użyj Async-Await lub promises do obsługi błędów asynchronicznych @@ -256,8 +256,7 @@ function someFunction() { } // Avoid -function someFunction() -{ +function someFunction() { // code block } ``` @@ -334,11 +333,11 @@ class SomeClassExample {} // for const names we use the const keyword and lowerCamelCase const config = { - key: 'value' + key: "value", }; // for variables and functions names we use lowerCamelCase -let someVariableExample = 'value'; +let someVariableExample = "value"; function doSomething() {} ``` @@ -372,12 +371,12 @@ function doSomething() {} ```javascript // Do -module.exports.SMSProvider = require('./SMSProvider'); -module.exports.SMSNumberResolver = require('./SMSNumberResolver'); +module.exports.SMSProvider = require("./SMSProvider"); +module.exports.SMSNumberResolver = require("./SMSNumberResolver"); // Avoid -module.exports.SMSProvider = require('./SMSProvider/SMSProvider.js'); -module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolver.js'); +module.exports.SMSProvider = require("./SMSProvider/SMSProvider.js"); +module.exports.SMSNumberResolver = require("./SMSNumberResolver/SMSNumberResolver.js"); ```

@@ -391,18 +390,18 @@ module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolve ### 3.10 Przykład kodu ```javascript -'' == '0' // false -0 == '' // true -0 == '0' // true +"" == "0"; // false +0 == ""; // true +0 == "0"; // true -false == 'false' // false -false == '0' // true +false == "false"; // false +false == "0"; // true -false == undefined // false -false == null // false -null == undefined // true +false == undefined; // false +false == null; // false +null == undefined; // true -' \t\r\n ' == 0 // true +" \t\r\n " == 0; // true ``` Wszystkie powyższe instrukcje zwrócą wartość false, jeśli zostaną użyte z `===` @@ -575,7 +574,7 @@ Wszystkie powyższe instrukcje zwrócą wartość false, jeśli zostaną użyte ## ![✔] 5.4. Zablokuj zależności -**TL;DR:** Twój kod musi być identyczny we wszystkich środowiskach, ale zadziwiająco npm pozwala domyślnie dryfować zależnościom między środowiskami - podczas instalowania pakietów w różnych środowiskach próbuje pobrać najnowszą wersję łatek. Aby temu zaradzić, użyj plików konfiguracyjnych npm, .npmrc, które każą każdemu środowisku zapisać dokładną (nie najnowszą) wersję każdego pakietu. Alternatywnie, dla dokładniejszej kontroli grained, użyj „npm shrinkwrap”. \ * Aktualizacja: od NPM5 zależności są domyślnie zablokowane. Nowy menedżer pakietów w mieście, Yarn, również domyślnie nas objął +**TL;DR:** Twój kod musi być identyczny we wszystkich środowiskach, ale zadziwiająco npm pozwala domyślnie dryfować zależnościom między środowiskami - podczas instalowania pakietów w różnych środowiskach próbuje pobrać najnowszą wersję łatek. Aby temu zaradzić, użyj plików konfiguracyjnych npm, .npmrc, które każą każdemu środowisku zapisać dokładną (nie najnowszą) wersję każdego pakietu. Alternatywnie, dla dokładniejszej kontroli grained, użyj „npm shrinkwrap”. \ \* Aktualizacja: od NPM5 zależności są domyślnie zablokowane. Nowy menedżer pakietów w mieście, Yarn, również domyślnie nas objął **W przeciwnym razie:** Dział kontroli jakości dokładnie przetestuje kod i zatwierdzi wersję, która będzie zachowywać się inaczej w środowisku produkcyjnym. Co gorsza, różne serwery w tym samym klastrze produkcyjnym mogą uruchamiać inny kod @@ -733,7 +732,7 @@ Wszystkie powyższe instrukcje zwrócą wartość false, jeśli zostaną użyte -**TL;DR:** Skorzystaj z wtyczek liniowych związanych z bezpieczeństwem, takich jak [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security), aby wychwycić luki w zabezpieczeniach i problemy jak najwcześniej, najlepiej gdy są one kodowane. Może to pomóc w wykrywaniu słabych punktów bezpieczeństwa, takich jak używanie eval, wywoływanie procesu potomnego lub importowanie modułu z literałem łańcucha (np. dane wejściowe użytkownika). Kliknij „Czytaj więcej” poniżej, aby zobaczyć przykłady kodu, które zostaną złapane przez linijkę bezpieczeństwa +**TL;DR:** Skorzystaj z wtyczek liniowych związanych z bezpieczeństwem, takich jak [eslint-plugin-security](https://github.com/nodesecurity/eslint-plugin-security), aby wychwycić luki w zabezpieczeniach i problemy jak najwcześniej, najlepiej gdy są one kodowane. Może to pomóc w wykrywaniu słabych punktów bezpieczeństwa, takich jak używanie eval, wywoływanie procesu potomnego lub importowanie modułu z literałem łańcucha (np. dane wejściowe użytkownika). Kliknij „Czytaj więcej” poniżej, aby zobaczyć przykłady kodu, które zostaną złapane przez linijkę bezpieczeństwa **W przeciwnym razie:** To, co mogło być bezpośrednią słabością bezpieczeństwa podczas programowania, staje się poważnym problemem w produkcji. Ponadto projekt może nie być zgodny ze spójnymi praktykami bezpieczeństwa kodu, co prowadzi do wprowadzenia luk w zabezpieczeniach lub poufnych danych wrażliwych wrzuconych w zdalnych repozytoriach @@ -1041,11 +1040,10 @@ Wszystkie powyższe instrukcje zwrócą wartość false, jeśli zostaną użyte


- ## ![✔] 7.2. Preferuj natywne metody JS, niż narzędzia ponad powierzchnią użytkownika, takie jak Lodash - **TL;DR:** Korzystanie z bibliotek narzędziowych takich jak `lodash` i `underscore` w porównaniu z metodami natywnymi jest często bardziej karalne, ponieważ prowadzi do niepotrzebnych zależności i spowalnia działanie. - Należy pamiętać, że wraz z wprowadzeniem nowego silnika V8 wraz z nowymi standardami ES, natywne metody zostały ulepszone w taki sposób, że są teraz o około 50% wydajniejsze niż biblioteki narzędziowe. +**TL;DR:** Korzystanie z bibliotek narzędziowych takich jak `lodash` i `underscore` w porównaniu z metodami natywnymi jest często bardziej karalne, ponieważ prowadzi do niepotrzebnych zależności i spowalnia działanie. +Należy pamiętać, że wraz z wprowadzeniem nowego silnika V8 wraz z nowymi standardami ES, natywne metody zostały ulepszone w taki sposób, że są teraz o około 50% wydajniejsze niż biblioteki narzędziowe. **W przeciwnym razie:** Będziesz musiał utrzymywać mniej wydajne projekty, w których mógłbyś po prostu użyć tego, co było **już** dostępne lub zająć się kilkoma kolejnymi liniami w zamian za kilka dodatkowych plików. @@ -1053,7 +1051,6 @@ Wszystkie powyższe instrukcje zwrócą wartość false, jeśli zostaną użyte


- # Milestones Aby utrzymać ten przewodnik i aktualizować go, stale aktualizujemy i ulepszamy wytyczne i najlepsze praktyki z pomocą społeczności. Możesz śledzić nasze [kamienie milowe](https://github.com/goldbergyoni/nodebestpractices/milestones) i dołączyć do grup roboczych, jeśli chcesz przyczynić się do tego projektu @@ -1078,6 +1075,7 @@ Wszystkie tłumaczenia pochodzą od społeczności. Z przyjemnością uzyskamy w - ![KR](/assets/flags/KR.png) [Korean](README.korean.md) - Courtesy of [Sangbeom Han](https://github.com/uronly14me) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/94)) - ![ES](/assets/flags/ES.png) [Spanish](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/95)) - ![TR](/assets/flags/TR.png) Turkish ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/139)) +- ![EU](/assets/flags/EU.png) [Basque](README.basque.md) - Courtesy of [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/842))

@@ -1132,14 +1130,14 @@ Dziękujemy wszystkim wpółpracownikom! 🙏 Nasi współpracownicy są członkami, którzy regularnie współuczestniczą w repozytorium, sugerując nowe najlepsze praktyki, analizując problemy, sprawdzając pull requesty i wiele więcej. Jeśli chcesz pomóc nam poprowadzić tysiące ludzi do tworzenia lepszych aplikacji Node.js, przeczytaj nasze [wytyczne dla współpracowników](/.operations/CONTRIBUTING.md) 🎉 | | | -| :--: | :--: | -| [Ido Richter (Founder)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | +| :---------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: | +| [Ido Richter (Founder)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | ### Wcześniejsza współpraca | | -| :--: | -| [Refael Ackermann](https://github.com/refack) | +| :-------------------------------------------------------------------------------------------------------------------------: | +| [Refael Ackermann](https://github.com/refack) |
diff --git a/README.russian.md b/README.russian.md index 272e6d12..09f24d62 100644 --- a/README.russian.md +++ b/README.russian.md @@ -18,7 +18,7 @@
-Читайте на других языках: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), [![BR](/assets/flags/BR.png)**BR**](/README.brazilian-portuguese.md), [![RU](/assets/flags/RU.png)**RU**](/README.russian.md) [(![ES](/assets/flags/ES.png)**ES**, ![FR](/assets/flags/FR.png)**FR**, ![HE](/assets/flags/HE.png)**HE**, ![KR](/assets/flags/KR.png)**KR** and ![TR](/assets/flags/TR.png)**TR** in progress!)](#translations) +Читайте на других языках: [![CN](/assets/flags/CN.png)**CN**](/README.chinese.md), [![BR](/assets/flags/BR.png)**BR**](/README.brazilian-portuguese.md), [![RU](/assets/flags/RU.png)**RU**](/README.russian.md) [(![ES](/assets/flags/ES.png)**ES**, ![FR](/assets/flags/FR.png)**FR**, ![HE](/assets/flags/HE.png)**HE**, ![KR](/assets/flags/KR.png)**KR**, ![TR](/assets/flags/TR.png)**TR** and ![EU](/assets/flags/EU.png)**EU** in progress! )](#translations)
@@ -90,9 +90,9 @@ ## ![✔] 1.4 Разделяйте Express "приложение" и "сервер" -**TL;DR:** Избегайте неприятной привычки определять все приложение [Express] (https://expressjs.com/) в одном огромном файле -- разделите определение "Экспресс" как минимум на два файла: декларация API (app.js) и сетевые задачи (www). Для еще лучшей структуры локализуйте объявление API в компонентах. +**TL;DR:** Избегайте неприятной привычки определять все приложение [Express](https://expressjs.com/) в одном огромном файле -- разделите определение "Экспресс" как минимум на два файла: декларация API (app.js) и сетевые задачи (www). Для еще лучшей структуры локализуйте объявление API в компонентах. -**Иначе:** Ваш API будет доступен для тестирования только через HTTP-вызовы (медленнее и намного сложнее создавать отчеты о покрытии). Скорее всего, не составит большого труда хранить сотни строк кода в одном файле. +**Иначе:** Ваш API будет доступен для тестирования только через HTTP-вызовы (медленнее и намного сложнее создавать отчеты о покрытии). Скорее всего, вы не будете испытывать огромное удовольствие, если будете хранить сотни строк кода в одном файле. 🔗 [**Подробнее: Разделяйте Express "приложение" и "сервер"**](/sections/projectstructre/separateexpress.russian.md) @@ -102,7 +102,7 @@ **TL;DR:** Идеальная и безупречная конфигурация должна обеспечивать (а) считывание ключей из файла И из переменной среды, (б) хранение секретов вне основной кодовой базы, (в) иерархическую структуру для облегчения поиска. Есть несколько пакетов, которые могут помочь поставить галочку в большинстве таких полей, как [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config), and [convict](https://www.npmjs.com/package/convict) -**Иначе:** Невыполнение каких-либо требований к конфигурации приведет к срывам в работе разработчиков или devops командой. Вероятно, и тех и других. +**Иначе:** Невыполнение каких-либо требований к конфигурации приведет к срывам в работе разработчиков или devops-команды. А вероятно, и тех и других. 🔗 [**Подробнее: Используйте конфигурацию с учетом среды, безопасную и иерархическую конфигурацию**](/sections/projectstructre/configguide.russian.md) @@ -116,7 +116,7 @@ **TL;DR:** Обработка асинхронных ошибок в стиле обратного вызова, вероятно, является самым быстрым путем в ад (еще говорят "Callback Hell" или "The Pyramid of Doom"). Лучший подарок, который вы можете сделать своему коду, -- это использовать надежную библиотеку обещаний или async-await, что позволяет использовать более компактный и знакомый синтаксис кода, такой как try-catch. -**Иначе:** Стиль обратного вызова Node.js, функция (err, response), является многообещающим способом создания непригодного для использования кода из-за сочетания обработки ошибок со случайным кодом, чрезмерных вложений и слабых шаблонов кодирования. +**Иначе:** Callback-стиль Node.js, function(err, response), является многообещающим способом создания непригодного для использования кода из-за сочетания таких проблем, как обработка ошибок со случайным кодом, чрезмерные вложения и неудобные шаблоны проектирования. 🔗 [**Подробнее: Используйте Async-Await или обещания для асинхронной обработки ошибок**](/sections/errorhandling/asyncerrorhandling.russian.md) @@ -132,21 +132,21 @@

-## ![✔] 2.3 Различайте ошибки в работе и программировании +## ![✔] 2.3 Различайте операционные ошибки и ошибки программиста -**TL;DR:** Операционные ошибки (например, API получил неверный ввод) относятся к известным случаям, когда влияние ошибки полностью осознается и может быть обработано вдумчиво. С другой стороны, ошибка программиста (например, попытка прочитать неопределенную переменную) относится к неизвестным ошибкам кода, которые требуют изящного перезапуска приложения. +**TL;DR:** Операционные ошибки (например, API получил неверный ввод) относятся к таким случаям, когда влияние ошибки полностью осознается и может быть обработано вдумчиво. Ошибка программиста (например, попытка прочитать undefined-переменную) относится к неизвестным ошибкам, которые требуют безопасного перезапуска приложения. -**Иначе:** Вы всегда можете перезапустить приложение, когда появляется ошибка, но зачем подводить ~5000 онлайн-пользователей из-за незначительной, прогнозируемой, операционной ошибки? Обратное также не идеально -- поддержание приложения в том случае, если возникла неизвестная проблема (ошибка программиста), может привести к непредсказуемому поведению. Разграничение между ними позволяет действовать тактично и применять сбалансированный подход, основанный на данном контексте. +**Иначе:** Вы всегда можете перезапустить приложение, когда появляется ошибка, но зачем подводить ~5000 онлайн-пользователей из-за незначительной и прогнозируемой операционной ошибки? Обратное также не является идеальным -- отсутствие перезапуска приложения в случае, если возникла неизвестная проблема (ошибка программиста), может привести к непредсказуемому поведению. Понимание типа ошибки позволит действовать тактично и применять сбалансированный подход, основанный на предоставленном контексте. -🔗 [**Подробнее: Различайте операционные и программистские ошибки**](/sections/errorhandling/operationalvsprogrammererror.russian.md) +🔗 [**Подробнее: Различайте операционные ошибки и ошибки программиста**](/sections/errorhandling/operationalvsprogrammererror.russian.md)

-## ![✔] 2.4 Обрабатывате ошибки централизованно, а не в промежуточном слое Express +## ![✔] 2.4 Обрабатывате ошибки централизованно, а не в промежуточных обработчиках Express -**TL;DR:** Логика обработки ошибок, такая как уведомление по почте администратора или ведение журнала, должна быть заключена в выделенный и централизованный объект, который вызывается всеми конечными точками (например, промежуточные слои Express, задания cron, модульное тестирование) при возникновении ошибки. +**TL;DR:** Логика обработки ошибок, например, как уведомление по почте администратора или ведение журнала, должна быть инкапсулирована в выделенный и централизованный объект, который вызывается всеми точками входа (обработчиками Express, cron-задачами, юнит-тестами) при возникновении ошибки. -**Иначе:** Необработка ошибок в одном месте приведет к дублированию кода и, возможно, к ошибкам, обработанным неправильно. +**Иначе:** Отсутствие обработки ошибок в едином месте приведет к дублированию кода и, возможно, к неверной обработке ошибок. 🔗 [**Подробнее: Обрабатывайте ошибки централизованно. Не в промежуточных слоях**](/sections/errorhandling/centralizedhandling.russian.md) @@ -222,6 +222,21 @@


+

⬆ Return to top

+ +## ![✔] 2.12 Для полноты стектрейсов всегда делайте await промисам прежде чем вернуть их из функции + +**TL;DR:** Дабы не иметь пропусков вызовов в стектрейсах, при возвращении промисов всегда +выполняйте `return await`. Если функция возвращает промис то эта функция обязана быть объявлена +как `async` и явно разрешить промис через `await` прежде чем +вернуть его + +**Иначе:** Функция возвращающая неразрешенный промис будет отсутствовать в стектрейсе. Такие +пропуски, вероятнее всего, усложнят процесс понимания пути возникновения ошибки, особенно если +причина ненормального поведения как раз в отсутствующей функции и находится + +🔗 [**Подробнее: возвращение промисов**](/sections/errorhandling/returningpromises.russian.md) +

⬆ К началу

# `3. Практики стиля кода` @@ -257,8 +272,7 @@ function someFunction() { } // Избегайте -function someFunction() -{ +function someFunction() { // code block } ``` @@ -335,11 +349,11 @@ class SomeClassExample {} // для константы мы используем служебное слово const и lowerCamelCase const config = { - key: 'value' + key: "value", }; // для переменных и функций мы используем lowerCamelCase -let someVariableExample = 'value'; +let someVariableExample = "value"; function doSomething() {} ``` @@ -373,12 +387,12 @@ function doSomething() {} ```javascript // Делайте так -module.exports.SMSProvider = require('./SMSProvider'); -module.exports.SMSNumberResolver = require('./SMSNumberResolver'); +module.exports.SMSProvider = require("./SMSProvider"); +module.exports.SMSNumberResolver = require("./SMSNumberResolver"); // Избегайте -module.exports.SMSProvider = require('./SMSProvider/SMSProvider.js'); -module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolver.js'); +module.exports.SMSProvider = require("./SMSProvider/SMSProvider.js"); +module.exports.SMSNumberResolver = require("./SMSNumberResolver/SMSNumberResolver.js"); ```

@@ -392,18 +406,18 @@ module.exports.SMSNumberResolver = require('./SMSNumberResolver/SMSNumberResolve ### Пример кода ```javascript -'' == '0' // false -0 == '' // true -0 == '0' // true +"" == "0"; // false +0 == ""; // true +0 == "0"; // true -false == 'false' // false -false == '0' // true +false == "false"; // false +false == "0"; // true -false == undefined // false -false == null // false -null == undefined // true +false == undefined; // false +false == null; // false +null == undefined; // true -' \t\r\n ' == 0 // true +" \t\r\n " == 0; // true ``` Все приведенные выше операторы вернут false, если используются с `===`. @@ -448,7 +462,7 @@ null == undefined // true **Иначе:** Развертывание только что прошло, тест под названием "Добавить продукт" не прошел. Это говорит вам, что именно работает со сбоями? -🔗 [**Подробнее: Включите 3 части в каждое название теста**](/sections/testingandquality/3-parts-in-name.russian.md) +🔗 [**Подробнее: Включите 3 части в каждое название теста**](/sections/testingandquality/3-parts-in-name.russian.md)

@@ -1042,7 +1056,6 @@ null == undefined // true


- ## ![✔] 7.2. Предпочитайте нативные методы JS, а не пользовательские утилиты типа Lodash **TL;DR:** Часто более утомительно использовать служебные библиотеки, такие как `lodash` и `underscore`, по сравнению с нативными методами, так как это приводит к ненужным зависимостям и снижению производительности. @@ -1054,7 +1067,6 @@ null == undefined // true


- # Вехи Чтобы поддерживать это руководство и обновлять его, мы постоянно обновляем и совершенствуем рекомендации и лучшие практики с помощью сообщества. Вы можете следить за нашими [вехами](https://github.com/goldbergyoni/nodebestpractices/milestones) и присоединиться к рабочим группам, если хотите внести свой вклад в этот проект. @@ -1078,6 +1090,7 @@ null == undefined // true - ![KR](/assets/flags/KR.png) [Korean](README.korean.md) - Любезно предоставлено [Sangbeom Han](https://github.com/uronly14me) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/94)) - ![ES](/assets/flags/ES.png) [Spanish](https://github.com/goldbergyoni/nodebestpractices/blob/spanish-translation/README.spanish.md) ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/95)) - ![TR](/assets/flags/TR.png) Turkish ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/139)) +- ![EU](/assets/flags/EU.png) [Basque](README.basque.md) - Любезно предоставлено [Ane Diaz de Tuesta](https://github.com/anediaz) & Joxefe Diaz de Tuesta ([Discussion](https://github.com/goldbergyoni/nodebestpractices/issues/842))

@@ -1132,14 +1145,14 @@ null == undefined // true Наши соавторы являются участниками, которые регулярно вносят свой вклад в хранилище, предлагая новые лучшие практики, разбирая проблемы, просматривая запросы на изменение и многое другое. Если вы заинтересованы в том, чтобы помочь нам научить тысячи людей создавать более качественные приложения Node.js, ознакомьтесь с нашими [руководством для соавторов](/.operations/CONTRIBUTING.md) 🎉 | | | -| :--: | :--: | -| [Ido Richter (Founder)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | +| :---------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: | +| [Ido Richter (Founder)](https://github.com/idori) | [Keith Holliday](https://github.com/TheHollidayInn) | ### Прошлые соавторы | | -| :--: | -| [Refael Ackermann](https://github.com/refack) | +| :-------------------------------------------------------------------------------------------------------------------------: | +| [Refael Ackermann](https://github.com/refack) |
diff --git a/assets/flags/EU.png b/assets/flags/EU.png new file mode 100644 index 00000000..ef4e2c64 Binary files /dev/null and b/assets/flags/EU.png differ diff --git a/assets/images/error-handling-flow.png b/assets/images/error-handling-flow.png new file mode 100644 index 00000000..a1b3ca6b Binary files /dev/null and b/assets/images/error-handling-flow.png differ diff --git a/sections/codestylepractices/eslint_prettier.basque.md b/sections/codestylepractices/eslint_prettier.basque.md new file mode 100644 index 00000000..384ecf1d --- /dev/null +++ b/sections/codestylepractices/eslint_prettier.basque.md @@ -0,0 +1,32 @@ +# Erabili ESLint eta Prettier + +### ESLint eta Prettier alderatzen + +Kode hau formateatzen baduzu ESLint erabiliz, abisu bat besterik ez dizu emango luzeegia dela esanez (zure `max-len` ezarpenaren arabera). Prettierrek zure order automatikoki formateatuko du. + + +```javascript +foo( + argudioBenetanLuzea(), + aiAmaParametroPiloPiloa(), + hauGarbituBeharkoNuke(), + benetanOraindikBesteBat(), + txantxetanZabiltzaEzta() +); +``` + +```javascript +foo( + argudioBenetanLuzea(), + aiAmaParametroPiloPiloa(), + hauGarbituBeharkoNuke(), + benetanOraindikBesteBat(), + txantxetanZabiltzaEzta() +); +``` + +Iturria: [https://github.com/prettier/prettier-eslint/issues/101](https://github.com/prettier/prettier-eslint/issues/101) + +### ESLint eta Prettier integratzen + +ESLint eta Prettier kodearen formateatze funtzionalitateetan gainjar daitezke, baina erraz konbina daitezke [prettier-eslint](https://github.com/prettier/prettier-eslint), [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier), eta [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) bezalako liburutegiekin. Haien arteko ezberdintasunei buruzko informazio gehiago nahi izanez gero, [hemen](https://stackoverflow.com/questions/44690308/whats-the-difference-between-prettier-eslint-eslint-plugin-prettier-and-eslint) begira dezakezu esteka diff --git a/sections/docker/avoid-build-time-secrets.chinese.md b/sections/docker/avoid-build-time-secrets.chinese.md new file mode 100644 index 00000000..9f97e138 --- /dev/null +++ b/sections/docker/avoid-build-time-secrets.chinese.md @@ -0,0 +1,92 @@ +# 清理编译过程中的秘钥,避免使用秘钥作为参数 + +

+ +### 一段解释 + +Docker映像不仅仅是一堆文件,而是展示构建期间所发生的层级关系。在普通场景中,开发人员在构建过程中需要知道npm令牌(主要是对于私有registry)- 会通过把令牌作为构建参数来传递,但这种实现是错误的。这可能看起来是没什么问题,并且安全,但此令牌可以从开发人员机器中的Docker历史记录、Docker registry和CI中获得。获取到该令牌的攻击者就能够拥有写入此组织私有npm registry的权限。还有两个更安全的替代方法:完美无瑕的一个替代方案是使用Docker --secret功能(截至2020年7月还在实验阶段),它只允许在构建期间挂载(mount)文件。第二种方法是使用带args的多阶段(multi-stage)构建,然后只将必要的文件复制到生产环境。后一种技术将不会同时一起提供秘钥与镜像,但秘钥将出现在本地Docker的历史记录中 - 对大多数组织来说,这通常被认为足够安全。 + +

+ +### 代码示例 – 使用Docker挂载秘钥(实验功能但稳定) + +
+ +Dockerfile + +``` +# syntax = docker/dockerfile:1.0-experimental + +FROM node:12-slim +WORKDIR /usr/src/app +COPY package.json package-lock.json ./ +RUN --mount=type=secret,id=npm,target=/root/.npmrc npm ci + +# 剩余部分 +``` + +
+ +

+ +### 代码示例 – 使用多阶段(multi-stage build)安全构建 + +
+ +Dockerfile + +``` + +FROM node:12-slim AS build +ARG NPM_TOKEN +WORKDIR /usr/src/app +COPY . /dist +RUN echo "//registry.npmjs.org/:\_authToken=\$NPM_TOKEN" > .npmrc && \ + npm ci --production && \ + rm -f .npmrc + +FROM build as prod +COPY --from=build /dist /dist +CMD ["node","index.js"] + +# ARG和.npmrc在最终的镜像中不会出现,但会在Docker daemon的未打标签(un-tagged)镜像列表中找到它们 - 确保删除他们 +``` + +
+ +

+ +### 代码示例 反模式 - 使用构建参数 + +
+ +Dockerfile + +``` + +FROM node:12-slim +ARG NPM_TOKEN +WORKDIR /usr/src/app +COPY . /dist +RUN echo "//registry.npmjs.org/:\_authToken=\$NPM_TOKEN" > .npmrc && \ + npm ci --production && \ + rm -f .npmrc + +# 在拷贝命令的同时删除.npmrc文件不会在layer里面保存它, 但在镜像历史里面还是会找到它 + +CMD ["node","index.js"] +``` + +
+ +

+ +### 博客引用: "秘钥不会保存在最终的Docker中" + +摘自博客, [Alexandra Ulsh](https://www.alexandraulsh.com/2019/02/24/docker-build-secrets-and-npmrc/?fbclid=IwAR0EAr1nr4_QiGzlNQcQKkd9rem19an9atJRO_8-n7oOZXwprToFQ53Y0KQ) + +> 在2018年11月,Docker18.09在docker构建过程中引入一个新的标志(flag)--secret。它允许用户通过一个文件传递秘钥到Docker包中(build)。这些秘钥不会保存在最终的Docker镜像,中间镜像和镜像提交历史里面。借助构建参数secret,您现在可以使用私有npm包安全地构建Docker映像,而无需构建参数和多阶段(multi-stage)构建。 + +``` + +``` diff --git a/sections/docker/bootstrap-using-node.chinese.md b/sections/docker/bootstrap-using-node.chinese.md new file mode 100644 index 00000000..48df2340 --- /dev/null +++ b/sections/docker/bootstrap-using-node.chinese.md @@ -0,0 +1,85 @@ +# 使用node命令而不是npm启动容器 + +## 一段解释 + +我们经常看到开发者使用`CMD 'npm start'`启动app的代码示例。这是一个不好的做法。因为`npm`不会向您的app转发信号(signals),这将阻止应用优雅关闭(graceful shutdown),(见[/sections/docker/graceful-shutdown.md])。如果您使用了子进程(child-processes),在意外关闭时则无法正确清理它们,将僵尸进程留在主机上。同时,`npm start`也导致无意义的增加一个额外进程。使用`CMD ['node','server.js']`启动您的应用吧。假如您的应用使用了子进程(child-processes),也可以使用`TINI`作为入口(entrypoint)。 + +### 代码示例 - 启动Node + +```dockerfile + +FROM node:12-slim AS build + + +WORKDIR /usr/src/app +COPY package.json package-lock.json ./ +RUN npm ci --production && npm clean cache --force + +CMD ["node", "server.js"] +``` + + +### 代码示例 - 使用Tiny作为入口(ENTRYPOINT) + +```dockerfile + +FROM node:12-slim AS build + +# 使用子进程(child-processes)的情况下,添加Tini +ENV TINI_VERSION v0.19.0 +ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini +RUN chmod +x /tini + +WORKDIR /usr/src/app +COPY package.json package-lock.json ./ +RUN npm ci --production && npm clean cache --force + +ENTRYPOINT ["/tini", "--"] + +CMD ["node", "server.js"] +``` + +### 反模式 + +使用npm start +```dockerfile + +FROM node:12-slim AS build +WORKDIR /usr/src/app +COPY package.json package-lock.json ./ +RUN npm ci --production && npm clean cache --force + +# 不要这么做! +CMD "npm start" +``` + +在同一字符串命令里面使用node,将启动一个bash/ash脚本进程去执行您的命令。它和使用`npm`的效果类似。 + +```dockerfile + +FROM node:12-slim AS build +WORKDIR /usr/src/app +COPY package.json package-lock.json ./ +RUN npm ci --production && npm clean cache --force + +# 不要这么做,它将启动bash +CMD "node server.js" +``` + +使用npm启动,这里是进程树: +``` +$ ps falx + UID PID PPID COMMAND + 0 1 0 npm + 0 16 1 sh -c node server.js + 0 17 16 \_ node server.js +``` +额外的两个进程没有任何好处。 + +来源: + + +https://maximorlov.com/process-signals-inside-docker-containers/ + + +https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md#handling-kernel-signals \ No newline at end of file diff --git a/sections/docker/bootstrap-using-node.md b/sections/docker/bootstrap-using-node.md index 283fd3c1..7437b9d4 100644 --- a/sections/docker/bootstrap-using-node.md +++ b/sections/docker/bootstrap-using-node.md @@ -47,7 +47,7 @@ Using npm start FROM node:12-slim AS build WORKDIR /usr/src/app COPY package.json package-lock.json ./ -RUN npm ci --production && npm clean cache --force +RUN npm ci --production && npm cache clean --force # don’t do that! CMD "npm start" diff --git a/sections/docker/multi_stage_builds.md b/sections/docker/multi_stage_builds.md index eccba3bf..8aae43cc 100644 --- a/sections/docker/multi_stage_builds.md +++ b/sections/docker/multi_stage_builds.md @@ -19,8 +19,10 @@ Let's imagine the following directory structure - README.md ``` -Your [.dockerignore](/sections/docker/dockerignore.md) will already filter out files that won't be needed for building and running your application. +Your [.dockerignore](../docker/docker-ignore.md) will already filter out files that won't be needed for building and running your application. + +sections/docker/docker-ignore.md ``` # Don't copy in existing node_modules, we'll fetch our own node_modules diff --git a/sections/errorhandling/apmproducts.basque.md b/sections/errorhandling/apmproducts.basque.md new file mode 100644 index 00000000..50b8642a --- /dev/null +++ b/sections/errorhandling/apmproducts.basque.md @@ -0,0 +1,27 @@ +# Aurkitu erroreak eta jardunik gabeko uneak APM produktuak erabiliz + +### Azalpen paragrafoa + +Salbuespena != Errorea. Erroreen kudeaketa tradizionalak kodearekin erlazionatutako arazotzat hartzen ditu salbuespenak, baina aplikazioen erroreak formularioko kode bide motelen, APIen jardunik gabeko uneen eta baliabide konputazionalen gabezien ondorio izan daitezke. Horra non APM produktuak oso erabilgarriak diren, 'lurperatutako' askotariko gaiak modu proaktiboan detektatzeko aukera ematen baitute gutxieneko konfigurazioarekin. APM produktuen ohiko funtzionalitateen artean daude, adibidez, HTTP APIak erroreak bidaltzen dituenean alerta jotzea, APIaren erantzunaren denbora aurretik zehaztutako denbora muga baino luzeagoa denean antzematea, ‘kode usainak’ hautematea, monitorizazio zerbitzariaren baliabideentzako funtzionalitateak, operazio inteligentziadun panelak (dashboard) IT metrikekin eta beste funtzionalitate batzuk oso erabilgarriak direnak. Hornitzaile gehienek dohaineko plana eskaintzen dute. + +### Wikipedia APMri buruz + +Informazioaren teknologien eta sistemen kudeaketaren alorretan, Application Performance Management (APM) software aplikazioen errendimendu eta erabilgarritasunaren monitorizazio eta kudeaketa da. APM aplikazioen errendimendu arazo konplexuak atzeman eta diagnostikatzen saiatzen da, esperotako zerbitzu maila mantentzeko. APM "IT metrikak negozioaren esanahira ([hau da,] balioa)" itzultzea da. Produktu eta segmentu nagusiak. APM "IT metrikak negozioaren esanahira ([hau da,] balioa)" itzultzea da. Produktu eta segmentu nagusiak. + +### APM merkatua ulertzen + +APM produktuek 3 segmentu nagusi dituzte: + +1. Webgune edo APIen monitorizazioa, martxan egondako denbora eta errendimuendua HTTP eskaeren bidez etengabe monitorizatzen dituzten kanpo zerbitzuak. Minutu gutxi batzuetan ezar daiteke. Hurrengo hauek dira aukeratutako lehiakide batzuk: [Pingdom](https://www.pingdom.com/), [Uptime Robot](https://uptimerobot.com/), eta [New Relic](https://newrelic.com/application-monitoring) + +2. Kodearen instrumentazioa, kode motelaren atzematea, salbuespenen estadistikak, errendimenduaren monitorizazioa eta holako beste funtzionalitate batzuk erabiltzeko agente bat aplikazioan txertatzea eskatzen duen produktu familia da. Hurrengo hauek dira aukeratutako lehiakide batzuk: New Relic, App Dynamics + +3. Adimen operatiboaren panela produktuen linea bat da, operazio taldeari metrika eta eduki aukeratuak eskaintzen dizkiona eta aplikazioaren errendimendua zein den jakitera behartzen duena. Horrek informazio iturri anitz (aplikazioen erregistroak, DB erregistroak, zerbitzarien erregistroa, etab.) eta aurrez aurreko arbelaren diseinua batzea eskatzen du. Hurrengo hauek dira aukeratutako lehiakide batzuk: [Datadog](https://www.datadoghq.com/), [Splunk](https://www.splunk.com/), [Zabbix](https://www.zabbix.com/) + +### Adibidea: UpTimeRobot.Com: webguneak monitorizatzeko panela + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/uptimerobot.jpg "Webgune monitorizazio aurreko panela") + +### Adibidea: AppDynamics.Com: hasieratik amaierarainoko monitorizazioa kode instrumentazioarekin konbinatutakoa + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/app-dynamics-dashboard.png "kode instrumentazioarekin konbinatutako hasieratik amaierarainoko monitorizazioa") diff --git a/sections/errorhandling/asyncerrorhandling.basque.md b/sections/errorhandling/asyncerrorhandling.basque.md new file mode 100644 index 00000000..790fd139 --- /dev/null +++ b/sections/errorhandling/asyncerrorhandling.basque.md @@ -0,0 +1,119 @@ +# Erabili Async-Await edo errore asinkronoak kudeatzeko promesak + +### Azalpen paragrafoa + +Callbackak ez dira kudea errazak programatzaile gehienek ez dituzte ondo ezagutzen eta. Callbackek etengabeko errore egiaztatzea eskatzen dute, kode korapilotsua jasanaraziz eta kodigoaren fluxuaren ulergarritasuna zailduz. BlueBird, async, eta Q bezalako promesa liburutegiek kodigo estilo estandarra RETURN eta THROW erabiliz paketatzen dute, programaren fluxua kontrolatzeko. Zehazki, kodigo nagusia funtzio bakoitzean erroreak kuadeatzetik askatzea ahalbidetzen duen try-catch errore kudeaketa estilo gogokoena onartzen dute + +### Kode adibidea: promesen erabilera erroreak antzemateko + +```javascript +return aFuntzioa() + .then(bFuntzioa) + .then(cFuntzioa) + .then(dFuntzioa) + .catch((errorea) => logger.error(errorea)) + .then(betiExekutatuFuntzioHau); +``` + +### Kode adibidea: async/awaiten erabilera erroreak antzemateko + +```javascript +async function exekutatuAtazaAsinkronoBat() { + try { + const aBalioa = await aFuntzioa(); + const bBalioa = await bFuntzioa(aBalioa); + const cBalioa = await cFuntzioa(bBalioa); + return await dFuntzioa(cBalioa); + } catch (errorea) { + logger.error(errorea); + } finally { + await betiExekutatuFuntzioHau(); + } +} +``` + +### Anti ereduaren kode adibidea: callbackaren estiloko errore kudeaketa + +
+Javascript + +```javascript +datuakEskuratu(parametrorenBat, function (errorea, emaitza) { + if (errorea !== null) { + // bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu + datuGehiagoEskuratu(a, function (errorea, emaitza) { + if (errorea !== null) { + // bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu + datuGehiagoEskuratu(b, function (c) { + datuGehiagoEskuratu(d, function (e) { + if (errorea !== null) { + // ulertu duzu ideia? + } + }); + }); + } + }); + } +}); +``` + +
+ +
+Typescript + +```typescript +datuakEskuratu( + parametrorenBat, + function (errorea: Error | null, aEmaitza: ResultA) { + if (errorea !== null) { + // bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu + datuGehiagoEskuratu( + aEmaitza, + function (errorea: Error | null, bEmaitza: ResultB) { + if (errorea !== null) { + // bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu + datuGehiagoEskuratu(bEmaitza, function (cEmaitza: ResultC) { + datuGehiagoEskuratu( + cEmaitza, + function (errorea: Error | null, d: ResultD) { + if (errorea !== null) { + // ulertu duzu ideia? + } + } + ); + }); + } + } + ); + } + } +); +``` + +
+ +### Blogeko aipua: "Promesekin arazo bat dugu" + +pouchdb.com blogetik hartua + +> ……Izatez, callbackek zerbait oraindik maltzurragoa egiten dute: pilaz gabetzen gaituzte, programazio lengoaietan sarri egintzat jotzen duguna. Kodea pila gabe idaztea kotxe bat freno pedalik gabe gidatzea bezala da: ez zara konturatzen zein puntura arte +behar duzun erabiltzen saiatu eta ez dagoela konturatzen zaren momentura arte. Promesen helburu nagusia da asinkronoa (async) erabiltzean galdutako lengoaien oinarri guztiak berreskuratzea: return, throw eta pila. Baina promesak modu egokian erabiltzen jakin beharra dago beraiei probetxua ateratzeko. + +### Blogeko aipua: "Promesen metodoa askoz ere trinkoagoa da" + +gosquared.com blogetik hartua + +> ………Promesen metodoa askoz ere trinkoagoa, argiagoa eta idatzeko azkarragoa da. Errore edo salbuespen bat gertatzen bada, .catch() kudeatzaile bakar batek maneiatzen du.Errore guztiak kudeatzeko leku bakarra edukitzeak erroreen egiaztatzea lanaren fase bakoitzean idatzi beharrik ez dagoela adierazten du. + +### Blogeko aipua: "Promisak jatorrizko ES6 dira, eta sorgailuekin erabil daitezke" + +StrongLoop blogetik hartua + +> ….Callbackek erroreen kudeaketa istorio kaskarra dute. Promesak hobeak dira. Promesekin, erabili Expressen errore kudeaketa kapsulatua eta horrela salbuespenen bat ez antzemateko aukerak murriztuko dituzu. Promesak jatorriz ES6ak dira, eta generatzaileekin eta ES7ren async/await bezalako proposamenekin erabil daitezke Babel bezalako konpilatzaileetan. + +### Blogeko aipua: "Ohiko fluxu kontrol erregularren egitura guzti horiek guztiz apurtuta daude" + +Benno’s blogetik hartua + +> ……Asinkronoaren, hau da, callbacketan oinarritutako programazioaren gauza hoberenetako bat da ohituta zauden fluxu kontrol erregularren egitura guzti horiek guztiz apurtuta daudela. Hala ere, salbuespenen kudeaketa da niretzat apurtuen dagoena. Javascriptek nahiko try…catch egitura ezaguna hornitzen du. Salbuespenen arazoa da, erroreak pila batean ekiditeko aukera ona eman arren, errorea beste pila batean gertatzen bada guztiz alferrikakoak izaten bukatzen dutela… diff --git a/sections/errorhandling/asyncerrorhandling.russian.md b/sections/errorhandling/asyncerrorhandling.russian.md index 24fbc7d0..5cf3ad2c 100644 --- a/sections/errorhandling/asyncerrorhandling.russian.md +++ b/sections/errorhandling/asyncerrorhandling.russian.md @@ -2,7 +2,7 @@ ### Объяснение в один абзац -Обратные вызовы плохо масштабируются, так как большинство программистов не знакомы с ними. Они заставляют проверять ошибки повсюду, имеют дело с неприятным вложением кода и затрудняют анализ потока кода. Библиотеки Promise, такие как BlueBird, async и Q, упаковывают стандартный стиль кода, используя RETURN и THROW для управления потоком программы. В частности, они поддерживают любимый стиль обработки ошибок try-catch, который позволяет освободить путь к основному коду от ошибок в каждой функции +Обратные вызовы плохо масштабируются, так как большинство программистов не знакомы с ними. Они заставляют проверять ошибки повсюду, иметь дело с неприятной вложенностью кода и затрудняют анализ потока кода. Библиотеки обещаний (promise), такие как BlueBird, async и Q, упаковывают стандартный стиль кода, используя RETURN и THROW для управления потоком программы. В частности, они поддерживают наилучший стиль обработки ошибок try-catch, который позволяет освободить основной код от обработки ошибок в каждой функции. ### Пример кода – использование обещаний для отлова ошибок @@ -15,7 +15,6 @@ return functionA() .then(alwaysExecuteThisFunction) ``` - ### Пример кода - использование async/await для отлова ошибок ```javascript @@ -34,7 +33,7 @@ async function executeAsyncTask () { } ``` -### Антипаттерн. Обработка ошибок в стиле обратного вызова +### Антипаттерн. Обработка ошибок в callback-стиле
Javascript @@ -42,14 +41,14 @@ async function executeAsyncTask () { ```javascript getData(someParameter, function(err, result) { if(err !== null) { - // do something like calling the given callback function and pass the error + // вызываем коллбек функцию и передаем ошибку getMoreData(a, function(err, result) { if(err !== null) { - // do something like calling the given callback function and pass the error + // вызываем коллбек функцию и передаем ошибку getMoreData(b, function(c) { getMoreData(d, function(e) { if(err !== null ) { - // you get the idea? + // вы поняли идею? } }) }); @@ -66,14 +65,14 @@ getData(someParameter, function(err, result) { ```typescript getData(someParameter, function(err: Error | null, resultA: ResultA) { if(err !== null) { - // do something like calling the given callback function and pass the error + // вызываем коллбек функцию и передаем ошибку getMoreData(resultA, function(err: Error | null, resultB: ResultB) { if(err !== null) { - // do something like calling the given callback function and pass the error + // вызываем коллбек функцию и передаем ошибку getMoreData(resultB, function(resultC: ResultC) { getMoreData(resultC, function(err: Error | null, d: ResultD) { if(err !== null) { - // you get the idea? + // вы поняли идею? } }) }); @@ -90,20 +89,20 @@ getData(someParameter, function(err: Error | null, resultA: ResultA) { > … На самом деле, обратные вызовы делают что-то еще более зловещее: они лишают нас стека, что мы обычно принимаем как должное в языках программирования. Написание кода без стека очень похоже на вождение автомобиля без педали тормоза: вы не понимаете, насколько сильно оно вам нужно, пока не дойдете до него, а его там нет. Весь смысл обещаний состоит в том, чтобы вернуть нам языковые основы, которые мы потеряли при асинхронности: возврат, выброс и стек. Но вы должны знать, как правильно использовать обещания, чтобы воспользоваться ими. -### Цитата блога: "Метод обещаний гораздо более компактен" +### Цитата блога: "Подход с обещаниями гораздо более компактен" Из блога gosquared.com -> … Метод обещаний гораздо компактнее, понятнее и быстрее для написания. Если ошибка или исключение происходят в любом из операций, они обрабатываются одним обработчиком .catch(). Наличие единого места для обработки всех ошибок означает, что вам не нужно писать проверку ошибок для каждого этапа работы. +> … Подход с обещаниями гораздо компактнее, понятнее и быстрее для написания. Если ошибка или исключение происходят в любой из операций, они обрабатываются одним обработчиком .catch(). Наличие единого места для обработки всех ошибок означает, что вам не нужно писать проверку ошибок для каждого этапа работы. -### Цитата блога: "Обещания являются родными ES6, могут использоваться с генераторами" +### Цитата блога: "Обещания являются нативными в ES6, могут использоваться с генераторами" Из блога StrongLoop -> … Обратные вызовы имеют паршивую историю обработки ошибок. Обещания лучше. Объедините встроенную обработку ошибок в Express с обещаниями и значительно снизьте вероятность возникновения необработанного исключения. Обещания являются родными ES6, могут использоваться с генераторами, а предложения ES7, такие как async/await, через компиляторы, такие как Babel. +> … Обратные вызовы имеют паршивую историю обработки ошибок. Обещания лучше. Объедините встроенную обработку ошибок в Express с обещаниями и значительно снизьте вероятность возникновения необработанного исключения. Обещания являются нативными в ES6, могут использоваться с генераторами, а proposals из ES7, такие как async/await, могут использоваться через компиляторы, такие как Babel. ### Цитата из блога: "Все те обычные конструкции управления потоком, к которым вы привыкли, полностью разрушены" Из блога Бенно -> … Одно из лучших преимуществ асинхронного программирования на основе обратного вызова состоит в том, что в основном все эти обычные конструкции управления потоком, к которым вы привыкли, полностью разрушены. Тем не менее, я считаю, что больше всего разрушения коснулись обработки исключений. Javascript предоставляет довольно знакомую конструкцию try…catch для работы с исключениями. Проблема с исключениями состоит в том, что они обеспечивают отличный способ сокращения ошибок в стеке вызовов, но в конечном итоге оказываются совершенно бесполезными, если ошибка происходит в другом стеке… +> … Одно из лучших преимуществ асинхронного программирования на основе обратного вызова состоит в том, что в основном все эти обычные конструкции управления потоком, к которым вы привыкли, полностью разрушены. Тем не менее, я считаю, что больше всего разрушения коснулась обработка исключений. Javascript предоставляет довольно знакомую конструкцию try…catch для работы с исключениями. Проблема с исключениями состоит в том, что они обеспечивают отличный способ сокращения ошибок в стеке вызовов, но в конечном итоге оказываются совершенно бесполезными, если ошибка происходит в другом стеке… \ No newline at end of file diff --git a/sections/errorhandling/catchunhandledpromiserejection.basque.md b/sections/errorhandling/catchunhandledpromiserejection.basque.md new file mode 100644 index 00000000..aa92e5e3 --- /dev/null +++ b/sections/errorhandling/catchunhandledpromiserejection.basque.md @@ -0,0 +1,88 @@ +# Atzeman kudeatu gabeko agintzen arbuioak + +

+ +### Azalpen paragrafoa + +Normalean, Node.js/Express aplikazio kode moderno gehienek promesen barruan funtzionatzen dute, .then kudeatzailearen, callback funtzio baten edota catch bloke baten barruan. Harrigarria bada ere, garatzaile batek .catch klausula bat gehitu zuela gogoratu ezean, leku hauetan jaurtitako erroreak ez dira uncaughtException ebentu kudeatzaileaz kudeatuak izaten, eta desagertu egiten dira. Noderen bertsio berrienek ohartarazpen mezu bat gehitu dute tratatu gabeko errefusa agertzen denean; egia da horrek, gauzak ondo ez doazenean, ohartzen lagun dezakeela, baina argi dago ez dela erroreak kudeatzeko modu egokia. Konponbide samurrena da ez ahaztea promesa kateko dei bakoitzaren barruan .catch klausula erabiltzen eta errore kudeatzaile zentralizatu batera desbideratzea. Hala ere, hauskorra da erroreak kudeatzeko estrategia garatzailearen diziplinan soilik oinarritzea. Ondorioz, oso gomendagarria da atzera egite dotorea erabiltzea eta `process.on('unhandledRejection', callback)`ra harpidetzea, horrek ziurtatuko baitu promesa erroreek, bere tratamendua izango dutela, lokalki kudeatzen ez badira. + +

+ +### Kode adibidea: errore hauek ez ditu inolako errore kudeatzailek atzemango (unhandledRejection-ek izan ezik) + +```javascript +DAL.berreskuratuErabiltzaileaIdBidez(1).then((johnSnow) => { + // errore hau desagertu egingo da + if (johnSnow.bizirikDago === false) throw new Error("ahhhh"); +}); +``` + +

+ +### Kode adibidea: kudeatu gabeko eta baztertutako promesak atzematen + +
+Javascript + +```javascript +process.on("unhandledRejection", (arrazoia, p) => { + // Kudeatu gabeko baztertutako promesa bat harrapatu dut, + // iada kudeatu gabeko erroreentzat atzera-egite kudeatzailea dugunez (begiratu beherago), + // utzi jaurtitzen eta utzi berari hori kudeatzen + throw arrazoia; +}); + +process.on("uncaughtException", (errorea) => { + // Aurretik inoiz kudeatu gabeko errorea jaso berri dut, hau kudeatzeko eta berrekite bat beharrezkoa den erabakitzeko garaia da + erroreKudeaketa.kudeatzailea.erroreaKudeatu(errorea); + if (!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea)) + process.exit(1); +}); +``` + +
+ +
+Typescript + +```typescript +process.on("unhandledRejection", (arrazioa: string, p: Promise) => { + // Kudeatu gabeko baztertutako promesa bat harrapatu dut, + // iada kudeatu gabeko erroreentzat atzera-egite kudeatzailea dugunez (begiratu beherago), + // utzi jaurtitzen eta utzi berari hori kudeatzen + throw arrazoia; +}); + +process.on("uncaughtException", (errorea: Error) => { + // Aurretik inoiz kudeatu gabeko errorea jaso berri dut, hau kudeatzeko eta berrekite bat beharrezkoa den erabakitzeko garaia da + erroreKudeaketa.kudeatzailea.erroreaKudeatu(errorea); + if (!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea)) + process.exit(1); +}); +``` + +
+ +

+ +### Blogeko aipua: ""Erroreren bat egiteko gai bazara, momenturen batean egin egingo duzu" + +James Nelson blogetik hartua + +> Proba dezagun zure ulermena. Hauetako zeinek uste duzu erakutsiko duela errore bat kontsolan? + +```javascript +Promise.resolve("agindutako balioa").then(() => { + throw new Error("errorea"); +}); + +Promise.reject("errore balioa").catch(() => { + throw new Error("errorea"); +}); + +new Promise((resolve, reject) => { + throw new Error("errorea"); +}); +``` + +> Ez dakit zer pentsatzen duzun, baina nire erantzuna da guztietan bistaratuko dela erroreren bat, eta errealitatea da JavaScript ingurune moderno gehienek kasu hauetako batentzat ere ez dituztela erroreak bistaratuko. Gizakien arazoa da, erroreen bat egiteko gai bazara, momenturen batean egingo duzula. Hori argi edukita, begibistakoa dirudi gauzak diseinatu behar direla erroreen erruz ahalik eta gutxien hondatzeko, eta horrek erroreak beti kudeatu beharra dagoela esan nahi du, alde batera utzi beharrean. diff --git a/sections/errorhandling/centralizedhandling.basque.md b/sections/errorhandling/centralizedhandling.basque.md new file mode 100644 index 00000000..8c43c3fa --- /dev/null +++ b/sections/errorhandling/centralizedhandling.basque.md @@ -0,0 +1,175 @@ +# Kudeatu erroreak gune bakar batean, Express middleware erabili partez + +### Azalpen paragrafoa + +Errore kudeaketarako ardura bakarreko objektu bat ez izateak, errore garrantzitsuak ezkutatzeko aukerak ugaritzen ditu kudeaketa ezegoki baten eraginpean. Errore kudeaketarako objektua, errorea begibistako bihurtzearen arduradun da, adibidez, egoki formateatutako erregistro batean idatziz, ebentuak [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), edota [Raygun](https://raygun.com/) bezalako monitorizazio sistemaren batera bidaliz. [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers) bezalako web framework gehienak, errore kudeaketa middleware mekanismo bat proposatzen dute. Errore kudeaketa fluxu tipiko bat hau izan daiteke: moduluren batek errore bat jaurtitzen du -> API routerrak errorea harrapatzen du -> errorea middlewarera hedatzen du, (adibidez Express edo KOA), zeinek erroreak harrapatzeko ardura duen -> errore kudeatzaile zentralizatu bati deitzen zaio -> middlewareari esaten zaio ia errore hau konfiantzazkoa den (ez operazio errorea) aplikazioa dotoreki berrekiteko. Kontutan izan Express midelwarean erroreak kudeatzea praktika arrunta dela, okerra izan arren. Hau egiteak ez ditu kontutan hartzen weba ez diren bestelako interfazeetako erroreak. + +### Kode adibidea: ohiko errore fluxua + +
+Javascript + +```javascript +// DAL (Data Access Layer) geruza, ez ditugu erroreak hemen kudeatzen +DB.gehituDokumentua(bezeroBerria, (errorea, emaitza) => { + if (errorea) + throw new Error('Errore azalpen bikaina dator hemen', bestelako parametro erabilgarri batzuk) +}); + +// API bide kodea, errore sinkrono eta asinkronoak harrapatu eta middlewarera desbideratzen ditugu hemen +try { + bezeroZerbitzua.gehituBerria(req.body).then((emaitza) => { + res.status(200).json(emaitza); + }).catch((errorea) => { + next(errorea) + }); +} +catch (errorea) { + next(errorea); +} + +// Errore-kudeaketa middlewarea, errore kudeatzaile zentralizatuari uzten diogu errore kudeaketa +app.use(async (errorea, req, res, next) => { + const operazioErroreaDa = await erroreKudeatzailea.kudeatuErrorea(errorea); + if (!operazioErroreaDa) { + next(errorea); + } +}); +``` + +
+ +
+Typescript + +```typescript +// DAL (Data Access Layer) geruza, ez ditugu erroreak hemen kudeatzen +DB.gehituDokumentua(bezeroBerria, (errorea: Error, emaitza: Result) => { + if (errorea) + throw new Error('Errore azalpen bikaina dator hemen', bestelako parametro erabilgarri batzuk) +}); + +// API bide kodea, errore sinkrono eta asinkronoak harrapatu eta middlewarera desbideratzen ditugu hemen +try { + bezeroZerbitzua.gehituBerria(req.body).then((emaitza: Result) => { + res.status(200).json(emaitza); + }).catch((errorea: Error) => { + next(errorea) + }); +} +catch (errorea) { + next(errorea); +} + +// Errore-kudeaketa middlewarea, errore kudeatzaile zentralizatuari uzten diogu errore kudeaketa +app.use(async (errorea: Error, req: Request, res: Response, next: NextFunction) => { + const operazioErroreaDa = await erroreKudeatzailea.kudeatuErrorea(errorea); + if (!operazioErroreaDa) { + next(errorea); + } +}); +``` + +
+ +### Kode adibidea: erroreen kudeaketa ardura bakarreko objektuekin + +
+Javascript + +```javascript +module.exports.kudeatzailea = new erroreKudeatzailea(); + +function erroreKudeatzailea() { + this.erroreaKudeatu = async (errorea) => { + await logger.erroreaErregistratu(errorea); + await kritikoaBadaAdministrariariPostaElektronikoaBidali; + await kritikoaBadaOperazioZerrendanGorde; + await erabakiIaOperazioErroreaDen; + }; +} +``` + +
+ +
+Typescript + +```typescript +class ErroreKudeatzailea { + public async erroreaKudeatu(errorea: Error): Promise { + await logger.erroreaErregistratu(errorea); + await kritikoaBadaAdministrariariPostaElektronikoaBidali(); + await kritikoaBadaOperazioZerrendanGorde(); + await erabakiIaOperazioErroreaDen(); + } +} + +export const kudeatzailea = new ErroreKudeatzailea(); +``` + +
+ +### Anti ereduaren kode adibidea: kudeatu erroreak middleware barruan + +
+Javascript + +```javascript +// zuzeneko errore kudeaketa middlewarean, Cron atazak eta frogatze erroreak kudeatuko dituena? +app.use((errorea, req, res, next) => { + logger.erroreaErregistratu(errorea); + if (errorea.larritasuna == erroreak.altua) { + posta.postaElektronikoaBidali( + konfigurazioa.administrariPostaElektronikoa, + "Errore kritikoa gertatu da", + errorea + ); + } + if (!errorea.operazioErroreaDa) { + next(errorea); + } +}); +``` + +
+ +
+Typescript + +```typescript +// zuzeneko errore kudeaketa middlewarean, Cron atazak eta frogatze erroreak kudeatuko dituena? +app.use((errorea: Error, req: Request, res: Response, next: NextFunction) => { + logger.erroreaErregistratu(errorea); + if (errorea.larritasuna == erroreak.altua) { + posta.postaElektronikoaBidali( + konfigurazioa.administrariPostaElektronikoa, + "Errore kritikoa gertatu da", + errorea + ); + } + if (!errorea.operazioErroreaDa) { + next(errorea); + } +}); +``` + +
+ +### Blogeko aipua: "Batzuetan maila baxuagoek beren deitzaileari errorea bidaltzea baino ezer praktikoagorik ezin dute egin" + +Joyent blogeko “Node.js errore kudeaketa" hitz gako bati esker sailkatua + +> …Errore bera pilaren maila askotan kudeatzen bukatuko duzu. Hau gertatzen da maila baxuenek beren deitzaileei (eta beste haiek beren deitzaileei, etab.) errorea bidaltzea baino beste ezer egokiagorik ezin dutenean egin. Askotan, soilik goi mailako deitzaileak daki zein den erantzun zuzena, ia ahalegin operazio berria den, erabiltzaileari errorearen berri eman behar dion, edo beste edozer. Baina horrek ez du esan nahi errore guztiak goi mailako callback bakar bati jakinarazi behar dizkiozunik, callback horrek ere errorea zein testuingurutan gertatu den ez daki eta… + +### Blogeko aipua: "Errore bakoitza bakarka kudeatzea bikoizte galanta izan daiteke" + +JS Recipes blogeko “Node.js errore kudeaketa" 17 hitz gakori esker sailkatua + +> ……Hackathoneko Starter api.js kontrolatzaile bakarrean, 79 errore objektu inguru daude. Errore bakoitza bakarka kudeatzeak kodea ikaragarri bikoiztea eragin dezake. Hurrengo egin dezakezun gauza hoberena da errore kudeaketa logika Express middleware bati uztea… + +### Blogeko aipua: "HTTP erroreak ezin dira zure datu basearen kodean egon" + +Daily JS blogeko “Node.js errore kudeaketa" 14 hitz gakori esker sailkatua + +> ……Errore objektuetan ezaugarri erabilgarriak zehaztu beharko zenituzke, baina ezaugarri horiek tinko erabiliz. Eta, ez gurutzatu korronteak: HTTP erroreak ezin dira zure datu basearen kodean egon. Edota, nabigatzaile garatzaileentzat, Ajax erroreak zerbitzariarekin hitz egiten duten kodean egon daitezke, baina Mustache txantiloiak prozesatzen dituen koderik ez… diff --git a/sections/errorhandling/centralizedhandling.korean.md b/sections/errorhandling/centralizedhandling.korean.md index 097a9922..a8b43baf 100644 --- a/sections/errorhandling/centralizedhandling.korean.md +++ b/sections/errorhandling/centralizedhandling.korean.md @@ -1,10 +1,10 @@ -# Handle errors centrally. Not within middlewares +# 에러를 미들웨어에서 처리하지 말고 한군데에서 집중적으로 처리해라 -### One Paragraph Explainer +### 한문단 설명 -Without one dedicated object for error handling, greater are the chances of important errors hiding under the radar due to improper handling. The error handler object is responsible for making the error visible, for example by writing to a well-formatted logger, sending events to some monitoring product like [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), or [Raygun](https://raygun.com/). Most web frameworks, like [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), provide an error handling middleware mechanism. A typical error handling flow might be: Some module throws an error -> API router catches the error -> it propagates the error to the middleware (e.g. Express, KOA) who is responsible for catching errors -> a centralized error handler is called -> the middleware is being told whether this error is an untrusted error (not operational) so it can restart the app gracefully. Note that it’s a common, yet wrong, practice to handle errors within Express middleware – doing so will not cover errors that are thrown in non-web interfaces. +에러 처리를 위한 전용 객체가 없으면 잘못된 처리로 인해 중요한 에러가 숨어있을 가능성이 더 커진다. 예를 들어, 에러 처리 객체는 [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), 또는 [Raygun](https://raygun.com/))와 같은 모니터링 프로그램에 이벤트를 보내 에러를 가시적으로 만드는 역할을 한다. [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers),와 같은 대부분의 웹 프레임워크는 미들웨어 메커니즘 에러처리를 제공한다. 일반적인 에러 처리 흐름은 다음과 같다: 일부 모듈이 에러를 던진다 -> API 라우터가 에러를 잡는다 -> 에러를 에러 검출을 담당하는 미들웨어(예: Express, KOA)에 전달한다 -> 중앙 에러 처리기가 호출된다 -> 미들웨어는 이 에러가 신뢰할 수 없는 에러인지(작동하지 않음) 알려 앱을 정상적으로 재시작 할 수 있다. Express 미들웨어 내에서 오류를 처리하는 것이 일반적이지만 잘못된 관습이다 – 이렇게 하면 웹 이외의 인터페이스에 발생하는 에러를 해결 할 수 없다. -### Code Example – a typical error flow +### 코드 예시 – 일반적인 에러 흐름 ```javascript // DAL layer, we don't handle errors here @@ -34,7 +34,7 @@ app.use(async (err, req, res, next) => { }); ``` -### Code example – handling errors within a dedicated object +### 코드 예시 – 전용 객체에서 에러 처리 ```javascript module.exports.handler = new errorHandler(); @@ -49,7 +49,7 @@ function errorHandler() { } ``` -### Code Example – Anti Pattern: handling errors within the middleware +### 코드 예시 – 좋지않은 패턴: 미들웨어에서 에러 처리 ```javascript // middleware handling the error directly, who will handle Cron jobs and testing errors? @@ -64,20 +64,20 @@ app.use((err, req, res, next) => { }); ``` -### Blog Quote: "Sometimes lower levels can’t do anything useful except propagate the error to their caller" +### 블로그 인용: "때로 하위 레벨은 호출자에게 전달하는 것 외에 쓸모있는 일을 할 수 없다" -From the blog Joyent, ranked 1 for the keywords “Node.js error handling” +Joyent 블로그에서 "Node.js 에러 처리" 키워드 1위에 위치했다 -> …You may end up handling the same error at several levels of the stack. This happens when lower levels can’t do anything useful except propagate the error to their caller, which propagates the error to its caller, and so on. Often, only the top-level caller knows what the appropriate response is, whether that’s to retry the operation, report an error to the user, or something else. But that doesn’t mean you should try to report all errors to a single top-level callback, because that callback itself can’t know in what context the error occurred… +> …스택의 여러 레벨에서 동일한 오류를 처리할 수 있다. 이는 하위 레벨 수준에서 에러를 호출자에게 전달하는 것 외에는 쓸모있는 작업을 수행 할 수 없을 때 발생한다. 종종, 최상위 레벨 호출자만이 적절한 응답, 작업을 재시도할지, 사용자에게 에러를 보고할지, 또는 다른 작업을 수행할지를 알 수 있다. 그러나 모든 에러를 최상위 레벨에 보고해야 한다는 의미는 아니다, 왜냐하면 콜백 자체는 어떤 맥락에서 에러가 발생했는지 알 수 없기 때문이다… -### Blog Quote: "Handling each err individually would result in tremendous duplication" +### 블로그 인용: "각 에러를 개별적으로 처리하면 엄청난 중복이 발생할 수 있다" -From the blog JS Recipes ranked 17 for the keywords “Node.js error handling” +JS Recipes 블로그에서 "Node.js 에러 처리" 키워드 17위에 위치했다 -> ……In Hackathon Starter api.js controller alone, there are over 79 occurrences of error objects. Handling each err individually would result in a tremendous amount of code duplication. The next best thing you can do is to delegate all error handling logic to an Express middleware… +> ……Hackathon Starter api.js 컨트롤러에서만 79개 이상의 오류 객체가 있다. 각 에러를 개별적으로 처리하면 엄청난 중복이 발생할 수 있다. 다음으로 가장 좋은 방법은 모든 에러 처리 로직을 Express 미들웨어에 위임하는 것이다… -### Blog Quote: "HTTP errors have no place in your database code" +### 블로그 인용: "HTTP 에러는 데이터베이스 코드에 포함되지 않는다" -From the blog Daily JS ranked 14 for the keywords “Node.js error handling” +Daily JS 블로그에서 "Node.js 에러 처리" 키워드 14위에 위치했다 -> ……You should set useful properties in error objects, but use such properties consistently. And, don’t cross the streams: HTTP errors have no place in your database code. Or for browser developers, Ajax errors have a place in the code that talks to the server, but not code that processes Mustache templates… +> ……에러 객체에 유용한 속성을 설정해야 하지만, 이런 속성은 일관되게 사용해야 한다. 그리고, 스트림을 넘지 마라: HTTP 에러는 데이터베이스 코드에 포함되지 않는다. 또한 브라우저 개발자의 경우, Ajax 에러는 서버와 통신하는 코드가 있지만, 머스테치(Mustache) 템플릿을 처리하는 코드는 아니다… \ No newline at end of file diff --git a/sections/errorhandling/centralizedhandling.md b/sections/errorhandling/centralizedhandling.md index 1d184626..4073459e 100644 --- a/sections/errorhandling/centralizedhandling.md +++ b/sections/errorhandling/centralizedhandling.md @@ -2,7 +2,7 @@ ### One Paragraph Explainer -Without one dedicated object for error handling, greater are the chances of important errors hiding under the radar due to improper handling. The error handler object is responsible for making the error visible, for example by writing to a well-formatted logger, sending events to some monitoring product like [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), or [Raygun](https://raygun.com/). Most web frameworks, like [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), provide an error handling middleware mechanism. A typical error handling flow might be: Some module throws an error -> API router catches the error -> it propagates the error to the middleware (e.g. Express, KOA) who is responsible for catching errors -> a centralized error handler is called -> the middleware is being told whether this error is an untrusted error (not operational) so it can restart the app gracefully. Note that it’s a common, yet wrong, practice to handle errors within Express middleware – doing so will not cover errors that are thrown in non-web interfaces. +Without one dedicated object for error handling, greater are the chances for inconsistent errors handling: Errors thrown within web requests might get handled differently from those raised during the startup phase and those raised by scheduled jobs. This might lead to some types of errors that are being mismanaged. This single error handler object is responsible for making the error visible, for example, by writing to a well-formatted logger, firing metrics using some monitoring product (like [Prometheus](https://prometheus.io/), [CloudWatch](https://aws.amazon.com/cloudwatch/), [DataDog](https://www.datadoghq.com/), and [Sentry](https://sentry.io/)) and to decide whether the process should crash. Most web frameworks provide an error catching middleware mechanism - A typical mistake is to place the error handling code within this middleware. By doing so, you won't be able to reuse the same handler for errors that are caught in different scenarios like scheduled jobs, message queue subscribers, and uncaught exceptions. Consequently, the error middleware should only catch errors and forward them to the handler. A typical error handling flow might be: Some module throws an error -> API router catches the error -> it propagates the error to the middleware (e.g. or to other mechanism for catching request-level error) who is responsible for catching errors -> a centralized error handler is called. ### Code Example – a typical error flow @@ -30,11 +30,16 @@ catch (error) { // Error handling middleware, we delegate the handling to the centralized error handler app.use(async (err, req, res, next) => { - const isOperationalError = await errorHandler.handleError(err); - if (!isOperationalError) { - next(err); - } + await errorHandler.handleError(err, res);//The error handler will send a response }); + +process.on("uncaughtException", error => { + errorHandler.handleError(error); + }); + + process.on("unhandledRejection", (reason) => { + errorHandler.handleError(reason); + }); ```
@@ -62,11 +67,16 @@ catch (error) { // Error handling middleware, we delegate the handling to the centralized error handler app.use(async (err: Error, req: Request, res: Response, next: NextFunction) => { - const isOperationalError = await errorHandler.handleError(err); - if (!isOperationalError) { - next(err); - } +await errorHandler.handleError(err, res); }); + +process.on("uncaughtException", (error:Error) => { + errorHandler.handleError(error); + }); + + process.on("unhandledRejection", (reason) => { + errorHandler.handleError(reason); + }); ``` @@ -80,11 +90,10 @@ app.use(async (err: Error, req: Request, res: Response, next: NextFunction) => { module.exports.handler = new errorHandler(); function errorHandler() { - this.handleError = async (err) => { - await logger.logError(err); - await sendMailToAdminIfCritical; - await saveInOpsQueueIfCritical; - await determineIfOperationalError; + this.handleError = async (error, responseStream) => { + await logger.logError(error); + await fireMonitoringMetric(error); + await crashIfUntrustedErrorOrSendResponse(error, responseStream); }; } ``` @@ -95,12 +104,11 @@ function errorHandler() { ```typescript class ErrorHandler { - public async handleError(err: Error): Promise { - await logger.logError(err); - await sendMailToAdminIfCritical(); - await saveInOpsQueueIfCritical(); - await determineIfOperationalError(); - }; + public async handleError(err: Error, responseStream: Response): Promise { + await logger.logError(error); + await fireMonitoringMetric(error); + await crashIfUntrustedErrorOrSendResponse(error, responseStream); + }; } export const handler = new ErrorHandler(); @@ -145,6 +153,10 @@ app.use((err: Error, req: Request, res: Response, next: NextFunction) => { ``` + ### Illustration: The error handling actors and flow +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/error-handling-flow.png "Error handling flow") + + ### Blog Quote: "Sometimes lower levels can’t do anything useful except propagate the error to their caller" From the blog Joyent, ranked 1 for the keywords “Node.js error handling” diff --git a/sections/errorhandling/centralizedhandling.russian.md b/sections/errorhandling/centralizedhandling.russian.md index e0cc92ce..30329ba9 100644 --- a/sections/errorhandling/centralizedhandling.russian.md +++ b/sections/errorhandling/centralizedhandling.russian.md @@ -2,7 +2,7 @@ ### Объяснение в один абзац -Без специального выделенного объекта для обработки ошибок больше шансов на то, что важные ошибки скрываются под радаром из-за неправильного обращения. Объект обработчика ошибок отвечает за отображение ошибки, например, путем записи в хорошо отформатированный регистратор, отправки событий в некоторые продукты мониторинга, такие как [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/) или [Raygun](https://raygun.com/). Большинство веб-фреймворков, таких как [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), предоставляют механизм промежуточного программного обеспечения для обработки ошибок. Типичный поток обработки ошибок может быть следующим: какой-то модуль выдает ошибку -> маршрутизатор API перехватывает ошибку -> он передает ошибку промежуточному программному обеспечению (например, Express, KOA), которое отвечает за перехват ошибок -> вызывается централизованный обработчик ошибок -> промежуточному программному обеспечению сообщается, является ли эта ошибка ненадежной (не работающей), чтобы она могла корректно перезапустить приложение. Обратите внимание, что обычная, но неправильная практика - обрабатывать ошибки в промежуточном программном обеспечении Express - это не распространяется на ошибки, возникающие в не-веб-интерфейсах. +Без выделенного объекта для обработки ошибок есть больше шансов на то, что ошибки потеряются с радара из-за их неправильной обработки. Объект обработчика ошибок отвечает за отображение ошибки, например, путем записи в логгер, отправки событий в сервисы мониторинга, такие как [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/) или [Raygun](https://raygun.com/). Большинство веб-фреймворков, таких как [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), предоставляют механизм обработки ошибок с помощью функций промежуточной обработки (**middlewares**). Типичный поток обработки ошибок может выглядеть следующим образом: какой-то модуль выдает ошибку -> API-маршрутизатор перехватывает ошибку -> он передает ошибку функции промежуточной обработки (Express, KOA), которая отвечает за перехват ошибок -> вызывается централизованный обработчик ошибок -> функции промежуточной обработки передается информация о том, что является ли эта ошибка ненадежной (необрабатываемой), чтобы она могла корректно перезапустить приложение. Обратите внимание, что обычная, но неправильная практика - обрабатывать ошибки в функции промежуточной обработки Express - это не распространяется на ошибки, возникающие в не-веб-интерфейсах. ### Пример кода - типичный поток ошибок @@ -10,13 +10,14 @@ Javascript ```javascript -// DAL layer, we don't handle errors here +// DAL-слой, мы не обрабатываем ошибки тут DB.addDocument(newCustomer, (error, result) => { if (error) throw new Error('Great error explanation comes here', other useful parameters) }); -// API route code, we catch both sync and async errors and forward to the middleware +// код API-маршрутизатора, мы обрабатываем как sync +// так и async ошибки и переходим к middleware try { customerService.addNew(req.body).then((result) => { res.status(200).json(result); @@ -28,7 +29,7 @@ catch (error) { next(error); } -// Error handling middleware, we delegate the handling to the centralized error handler +// Обработка ошибок в middleware, мы делегируем обработку централизованному обработчику ошибок app.use(async (err, req, res, next) => { const isOperationalError = await errorHandler.handleError(err); if (!isOperationalError) { @@ -42,13 +43,14 @@ app.use(async (err, req, res, next) => { Typescript ```typescript -// DAL layer, we don't handle errors here +// DAL-слой, мы не обрабатываем ошибки тут DB.addDocument(newCustomer, (error: Error, result: Result) => { if (error) throw new Error('Great error explanation comes here', other useful parameters) }); -// API route code, we catch both sync and async errors and forward to the middleware +// код API-маршрутизатора, мы обрабатываем как sync +// так и async ошибки и переходим к middleware try { customerService.addNew(req.body).then((result: Result) => { res.status(200).json(result); @@ -60,7 +62,7 @@ catch (error) { next(error); } -// Error handling middleware, we delegate the handling to the centralized error handler +// Обработка ошибок в middleware, мы делегируем обработку централизованному обработчику ошибок app.use(async (err: Error, req: Request, res: Response, next: NextFunction) => { const isOperationalError = await errorHandler.handleError(err); if (!isOperationalError) { @@ -82,9 +84,9 @@ module.exports.handler = new errorHandler(); function errorHandler() { this.handleError = async (err) { await logger.logError(err); - await sendMailToAdminIfCritical; - await saveInOpsQueueIfCritical; - await determineIfOperationalError; + await sendMailToAdminIfCritical(err); + await saveInOpsQueueIfCritical(err); + await determineIfOperationalError(err); }; } ``` @@ -97,9 +99,9 @@ function errorHandler() { class ErrorHandler { public async handleError(err: Error): Promise { await logger.logError(err); - await sendMailToAdminIfCritical(); - await saveInOpsQueueIfCritical(); - await determineIfOperationalError(); + await sendMailToAdminIfCritical(err); + await saveInOpsQueueIfCritical(err); + await determineIfOperationalError(err); }; } @@ -108,13 +110,14 @@ export const handler = new ErrorHandler(); -### Пример кода - антипаттерн: обработка ошибок в промежуточном программном обеспечении +### Пример кода - антипаттерн: обработка ошибок в middleware
Javascript ```javascript -// middleware handling the error directly, who will handle Cron jobs and testing errors? +// middleware, обрабатывающий ошибки напрямую. +// А кто будет обрабатывать ошибки возникшие в Cron или при юнит-тестировании? app.use((err, req, res, next) => { logger.logError(err); if (err.severity == errors.high) { @@ -132,7 +135,8 @@ app.use((err, req, res, next) => { Typescript ```typescript -// middleware handling the error directly, who will handle Cron jobs and testing errors? +// middleware, обрабатывающий ошибки напрямую. +// А кто будет обрабатывать ошибки возникшие в Cron или при юнит-тестировании? app.use((err: Error, req: Request, res: Response, next: NextFunction) => { logger.logError(err); if (err.severity == errors.high) { @@ -145,20 +149,20 @@ app.use((err: Error, req: Request, res: Response, next: NextFunction) => { ```
-### Цитата из блога: "Иногда нижние уровни не могут сделать ничего полезного, кроме как сообщить об ошибке вызывающей стороне" +### Цитата из блога: "Иногда нижние слои не могут сделать ничего полезного, кроме как сообщить об ошибке вызывающему слою" -Из блога Joyent, занимающий 1 место по ключевым словам "Обработка ошибок Node.js" +Из блога Joyent, занимающего 1 место по ключевым словам "Обработка ошибок Node.js" -> … Вы можете обработать одну и ту же ошибку на нескольких уровнях стека. Это происходит, когда нижние уровни не могут сделать ничего полезного, кроме как передать ошибку вызывающей стороне, которая передает ошибку своей вызывающей стороне, и так далее. Зачастую только вызывающий пользователь верхнего уровня знает, что является подходящим ответом: попытка повторить операцию, сообщить пользователю об ошибке или что-то еще. Но это не значит, что вы должны пытаться сообщать обо всех ошибках в один обратный вызов верхнего уровня, потому что сам этот обратный вызов не может знать, в каком контексте произошла ошибка … +> … Вы можете обработать одну и ту же ошибку на нескольких слоях. Это происходит, когда нижние слои не могут сделать ничего полезного, кроме как передать ошибку вызывающему слою, который передаст ошибку своему вызывающему слою, и так далее. Зачастую только самый верхний слой знает, что является подходящим действием на ошибку: попытка повторить операцию, сообщить пользователю об ошибке или что-то еще. Но это не значит, что вы должны пытаться сообщать обо всех ошибках в один верхний callback, потому что этот callback не может знать, в каком контексте произошла ошибка … -### Цитата из блога: "Обработка каждой ошибки по отдельности приведет к огромному дублированию" +### Цитата из блога: "Обработка каждой ошибки по отдельности приведет к ужасному дублированию" -Из блога JS Recipes, занимающий 17 место по ключевым словам "Обработка ошибок Node.js" +Из блога JS Recipes, занимающего 17 место по ключевым словам "Обработка ошибок Node.js" -> … Только в контроллере api.js Hackathon Starter имеется более 79 случаев появления объектов ошибок. Обработка каждой ошибки в отдельности привела бы к огромному количеству дублирования кода. Следующее, что вы можете сделать, это делегировать всю логику обработки ошибок в промежуточное ПО Express … +> … Только в контроллере api.js Hackathon Starter имеется более 79 объектов ошибок. Обработка каждой ошибки в отдельности привела бы к ужасному дублированию кода. Следующее, что вы можете сделать, это делегировать всю логику обработки ошибок в middleware Express … ### Цитата из блога: "В коде вашей базы данных нет места ошибкам HTTP" Из блога Daily JS, занимающем 14 место по ключевым словам "Обработка ошибок Node.js" -> … Вы должны установить полезные свойства в объектах ошибок, но использовать их последовательно. И не пересекайте потоки: в коде вашей базы данных нет места ошибкам HTTP. Или для разработчиков браузеров, ошибки Ajax имеют место в коде, который общается с сервером, но не в коде, который обрабатывает шаблоны усов … +> … Вы должны добавлять полезные свойства в объекты ошибок, но использовать их согласовано. И не пересекайте логику: в коде вашей базы данных нет места ошибкам HTTP. Или, например, для frontend-разработчиков, ошибки Ajax имеют место в коде, который общается с сервером, но не в коде, который работает с шаблонами Mustache … diff --git a/sections/errorhandling/documentingusingswagger.basque.md b/sections/errorhandling/documentingusingswagger.basque.md new file mode 100644 index 00000000..aaf33ee1 --- /dev/null +++ b/sections/errorhandling/documentingusingswagger.basque.md @@ -0,0 +1,53 @@ +# Dokumentatu API erroreak OpenAPI (aurretik Swagger bezala ezagutua) edo GraphQL-ren laguntzarekin + +### Azalpen paragrafoa + +REST APIek HTTP estatus kodigoak erabiliz bueltatzen dituzte emaitzak. APIaren erabiltzailearentzat guztiz beharrezkoa da APIaren egituraren eta baita ere errore posibleen berri izatea, erabiltzaileak errorea atzeman eta kontu handiz kudea dezake eta. Adibidez, zure APIaren dokumentazioak aurrez azaldu behar du 409 HTTP estatus kodea bueltatzen dela bezeroaren izena iada existitzen denean (APIak bezero berriak gordetzen dituela ziurtzat joz), APIaren erabiltzaileak egoera bakoitzerako bistaratze egokiena proposa dezan. OpenAPI (aintzina Swagger) APIaren dokumentaziorako eskema bat zehazten duen estandar bat da, dokumentazioa online modu errazean sortzea ahalbidetzen duten tresna ekosistema bat proposatuz. Begiratu hurrengo pantailako argazkiak beherago + +Dagoeneko GraphQL erabiltzen baduzu zure APIaren helburuetarako, zure eskemak iada zorrozki bermatzen du zein errorek zein itxura eduki beharko luketen ([dokumentuan laburbilduta](https://facebook.github.io/graphql/June2018/#sec-Errors)) eta nola kudeatu beharko liratekeen zure bezero tresnekin Gainera, komentarioz osatutako dokumentazioa ere gehi zenezake. + + +### GraphQL errore baten adibidea + +> Adibide honek [SWAPI](https://graphql.org/swapi-graphql) erabiltzen du, Star Warsen APIa. + +```graphql +# huts egin beharko luke id ez baita zuzena +{ + filmea(id: "1ZmlsbXM6MQ==") { + izenburua + } +} +``` + +```json +{ + "erroreak": [ + { + "mezua": "Ez dago sarrerarik cache lokalean https://swapi.co/api/films/.../-rentzat", + "lekuak": [ + { + "ilara": 2, + "zutabea": 3 + } + ], + "bidea": [ + "filmea" + ] + } + ], + "datuak": { + "filmea": null + } +} +``` + +### Blogeko aipua: "Zure deitzaileei zein errore gertatu diren esan behar diezu" + +Joyent blogeko “Node.js erregistratzea“ hitz gako bati esker sailkatua + + > Erroreak nola kudeatu behar diren aztertu dugu, baina funtzio berri bat idazten ari zarenean, nola bidaltzen dizkiozu erroreak zure funtzioa deitu duen kodeari? …Zein errore gerta litezkeen edo haiekk zer esan nahi duten ez badakizu, esan nahi du zure programa ezin litekeela zuzena izan, txiripaz izan ezean. Beraz, funtzio berri bat idazten ari bazara, zure deitzailei zein errore gerta litezkeen eta haiek zer esan nahi duten esan behar diezu… + +### Tresna erabilgarria: Swagger Online Dokumentazio Sortzailea + +![Swagger API Eskema](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/swaggerDoc.png "APIen errore kudeaketa") diff --git a/sections/errorhandling/documentingusingswagger.md b/sections/errorhandling/documentingusingswagger.md index 3341b0c1..b91e7d05 100644 --- a/sections/errorhandling/documentingusingswagger.md +++ b/sections/errorhandling/documentingusingswagger.md @@ -1,8 +1,8 @@ -# Document API errors using Swagger or GraphQL +# Document API errors using OpenAPI Specification (earlier known as Swagger) or GraphQL ### One Paragraph Explainer -REST APIs return results using HTTP status codes, it’s absolutely required for the API user to be aware not only about the API schema but also about potential errors – the caller may then catch an error and tactfully handle it. For example, your API documentation might state in advance that HTTP status 409 is returned when the customer name already exists (assuming the API register new users) so the caller can correspondingly render the best UX for the given situation. Swagger is a standard that defines the schema of API documentation offering an eco-system of tools that allow creating documentation easily online, see print screens below +REST APIs return results using HTTP status codes, it’s absolutely required for the API user to be aware not only about the API schema but also about potential errors – the caller may then catch an error and tactfully handle it. For example, your API documentation might state in advance that HTTP status 409 is returned when the customer name already exists (assuming the API register new users) so the caller can correspondingly render the best UX for the given situation. OpenAPI (eka Swagger) is a standard that defines the schema of API documentation offering an eco-system of tools that allow creating documentation easily online, see print screens below If you have already adopted GraphQL for your API endpoints, your schema already contains strict guarantees as to what errors should look like ([outlined in the spec](https://facebook.github.io/graphql/June2018/#sec-Errors)) and how they should be handled by your client-side tooling. In addition, you can also supplement them with comment-based documentation. diff --git a/sections/errorhandling/failfast.basque.md b/sections/errorhandling/failfast.basque.md new file mode 100644 index 00000000..c481e6a4 --- /dev/null +++ b/sections/errorhandling/failfast.basque.md @@ -0,0 +1,71 @@ +# Huts egin azkar, balidatu argudioak liburutegi dedikatu baten laguntzarekin + +### Azalpen paragrafoa + +Denok dakigu argudioak egiaztatzea eta azkar huts egitea garrantzitsua dela ezkutuko erroreak ekiditeko (ikusi ereduaren aurkako kodearen adibidea behean). Bestela, irakurri zerbait programazio esplizituaren eta babes programazioaren gainean. Errealitatean, hori ekiditeko ohitura daukagu, kodea idazteak suposatzen duen gogaikarritasuna dela eta (adibidez pentsatu posta elektronikoa eta datak bezalako alorrak dituen JSON objektu hierarkiko bat balioztatzea). Joi eta Validator bezalako liburutegiek asko leuntzen dute lan hori. + +### Wikipedia: programazio defentsiboa + +Programazio defentsiboa softwarea eta iturburu kodea hobetzeko ikuspuntua da, kalitate orokorrari dagokionez, software errore eta arazo kopurua murriztuz. Iturburu kodea ulergarria izango bada, irakurgarria eta ulergarria izan behar da kode auditoria batean onartua izan dadin. Softwarea aurreikusteko moduko eran jokatzeko egin behar da, ustekabeko sarrerak edo erabiltzaile ekintzak gertatu arren. + +### Kode adibidea: balioztatu JSON sarrera koplexua ‘Joi’ erabiliz + +```javascript +var kideEskema = Joi.object().keys({ + pasahitza: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/), + jaioteguna: Joi.number().integer().min(1900).max(2013), + postaElektronikoa: Joi.string().email(), +}); + +function kideBerriaGehitu(kideBerria) { + // lehenengo baieztapena dator + Joi.assert(kideBerria, kideEskema); //jaurti balioztatzeak huts egiten badu + // bestelako logika hemen +} +``` + +### Anti eredua: balioztatze ezak errore kaskarrak dakartza + +
+Javascript + +```javascript +// deskontua positiboa bada, bidali erabiltzailea bere deskontu tiketak inprimatzera +function bidaliDeskontuTiketakInprimatzera(httpResponse, kidea, deskontua) { + if (deskontua != 0) { + httpResponse.redirect(`/deskontuInpresioBistaratzea/${kidea.id}`); + } +} + +bidaliDeskontuTiketakInprimatzera(httpResponse, kiderenBat); +// deskontu parametroa pasatzea ahaztuta, orduan zergatik bidali da erabiltzailea deskontu pantailara? +``` + +
+ +
+Typescript + +```typescript +// deskontua positiboa bada bidali erabiltzailea bere deskontu tiketak inprimatzera +function bidaliDeskontuTiketakInprimatzera( + httpResponse: Response, + kidea: Member, + deskontua: number +) { + if (deskontua != 0) { + httpResponse.redirect(`/deskontuInpresioBistaratzea/${kidea.id}`); + } +} + +bidaliDeskontuTiketakInprimatzera(httpResponse, kiderenBat, -12); +// deskontu parametro negatiboa pasatu dugu, We passed a negative parameter discount, orduan zergatik bidali da erabiltzailea deskontu pantailara? +``` + +
+ +### Blogeko aipua: "Errore hauek zuzenean jaurti beharko zenituzke" + +Joyent blogetik hartua + +> Kasu degeneratu bat da norbaitek funtzio asinkrono bat callback gabe deitzea atzera deirik egin gabe. Errore horiek berehala jaurti beharko zenituzke programa apurtuta baitago eta hori arazteak gutxienez pila arrastoa eta errorearen lekuko fitxategia berreskuratzea eskatzen du. Hori egiteko, funtzioaren hasieran argudio guztien motak balioztatzea gomendatzen dugu. diff --git a/sections/errorhandling/operationalvsprogrammererror.basque.md b/sections/errorhandling/operationalvsprogrammererror.basque.md new file mode 100644 index 00000000..95f102c8 --- /dev/null +++ b/sections/errorhandling/operationalvsprogrammererror.basque.md @@ -0,0 +1,100 @@ +# Bereizi eragiketa erroreak eta programazio erroreak + +### Azalpen paragrafoa + +Ondorengo bi errore mota hauek bereizteak zure aplikazioaren matxura denbora gutxitu eta programazio errore eroak ekiditen lagunduko dizu. Batetik, eragiketa erroreak daude, gertatutako arazoa eta haren ondorioak ulertzen dituzunean (adibidez, HTTP zerbitzu bati egindako deiak huts egitea, konexio arazoak direla eta. Bestetik, errorea zergatik eta nondik etorri den ez dakizun egoerei programatze errore deritze (balio zehaztugabe bat irakurtzen saiatzen den kodea edo memoria ihes egiten dion datu basea izan daitezke). Eragiketa erroreak besteen aldean kudea errazak dira, eta normalean nahikoa izaten da errorea erregistratzea. Gauzak konplikatuagoak izan daitezke garatzaile errore bat tupustean agertzen denean, aplikazioa egoera aldakorrean aurki baitaiteke. Horrelakoetan, aplikazioa berrabiarazi baino irtenbide hoberik ez duzu + +### Kode adibidea: erroreak eragiketa errore (konfiantzazko) bihurtu + +
+Javascript + +```javascript +// errore objektu bat eragiketa errore bihurtu +const nireErrorea = new Error( + "Nola gehi dezaket produktu bat baliorik ez duenean?" +); +nireErrorea.funtzionatzenDu = true; + +// edota errore eraikitzaile zentralizaturen bat erabiltzen baduzu (begiratu beste adibide batzuk "Erabili soilik “Errorea” objektu kapsulatua", 2.2, atalean) +class AppErrorea { + constructor(ohikoMota, deskribapena, funtzionatzenDu) { + Error.call(this); + Error.captureStackTrace(this); + this.ohikoMota = ohikoMota; + this.deskribapena = deskribapena; + this.funtzionatzenDu = funtzionatzenDu; + } +} + +throw new AppErrorea( + erroreKudeatzailea.ohikoErroreak.SarreraOkerra, + "Deskribatu hemen gertatutakoa", + true +); +``` + +
+ +
+Typescript + +```typescript +// errore eraikitzaile zentralizatu batzuk (begiratu beste adibide batzuk "Erabili soilik “Errorea” objektu kapsulatua", 2.2, atalean) +export class AppErrorea extends Error { + public readonly ohikoMota: string; + public readonly funtzionatzenDu: boolean; + + constructor( + ohikoMota: string, + description: string, + funtzionatzenDu: boolean + ) { + super(description); + + Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain + + this.ohikoMota = ohikoMota; + this.funtzionatzenDu = funtzionatzenDu; + + Error.atzemanErrorePila(this); + } +} + +// errore objektu bat eragiketa errore bihurtu (true) +throw new AppErrorea( + erroreKudeatzailea.ohikoErroreak.SarreraOkerra, + "Deskribatu hemen gertatutakoa", + true +); +``` + +
+ +### Blogeko aipua: "Programatzaileen erroreak programazio erroreak dira programan" + +Joyent blogeko “Node.js errore kudeaketa" hitz gako bati esker sailkatua + +> …Programatzaile erroreak gainditzeko modurik hoberena berehala huts eragitea da. Huts egiteren bat gertatzean automatikoki berrekingo dituen berrekite sistemaren bat erabiliz exekutatu beharko zenituzte zure programak. Berrekite sistemei esker, huts egitea da modurik azkarrena programatzaile errore iragankorrak gertatzean zerbitzua berreskuratzeko modu fidagarrian… + +### Blogeko aipua: "Alde egiteko modu segururik ez dago zehaztugabeko egoera hauskorrik sortu gabe" + +Node.js dokumentazio ofizialetik hartua + +> …Throw-ek JavaScripten nola funtzionatzen duen kontuan izanda, ez dago ia inoiz ataza bati modu seguruan “bertan behera utzitako puntuan segida ematerik” erreferentziak galdu gabe edota bestelako egoera hauskor zehaztugaberik sortu gabe. Jaurtitako erroreei erantzuteko modurik seguruena prozesua gelditzea da. Jakina, web zerbitzari arruntetan, konexio ugari eduki ahal ditzakezu irekita, eta ez da zentzuzkoa tupustean haiek ixtea beste batek eragindako errore batengatik. Planteamendu hoberena da errorea bidali duen eskariari errore erantzun bat bidaltzea, besteei beren atazak bukatzeko denbora emanez, eta eskari berriei kasu egiteari utzi prozesu horretan. + +### Blogeko aipua: "Bestela zure aplikazioaren egoera arriskuan jar dezakezu" + +debugable.com blogetik, “Node.js harrapatu gabeko exzepzioa" 3 hitz gakori esker sailkatua + +> …Beraz, baldin eta benetan egiten ari zarena jakiten baduzu, “uncaughtException” exzepzio ebentua jaso ostean zure zerbitzuaren berrekite dotorea egin beharko zenuke. Bestela, zure aplikazioaren egoera arriskuan jar dezakezu, edota haren liburutegiak aldakor bihurtuarazi, mota guztietako errore zoroak eraginez… + +### Blogeko aipua: "Errore kudeaketaren inguruko hiru ideia eskola daude" + +JS Recipes blogetik hartua + +> …Errore kudeaketaren inguruko hiru ideia eskola daude: + +1. Utzi aplikazioak huts egin dezan eta ondoren berrekin. +2. Kudeatu errore posible guztiak kudeatu eta inoiz ez huts egin. +3. Bien arteko planteamendu bat. diff --git a/sections/errorhandling/operationalvsprogrammererror.korean.md b/sections/errorhandling/operationalvsprogrammererror.korean.md index a6175c23..3d263886 100644 --- a/sections/errorhandling/operationalvsprogrammererror.korean.md +++ b/sections/errorhandling/operationalvsprogrammererror.korean.md @@ -1,10 +1,10 @@ -# Distinguish operational vs programmer errors +# 동작상의 에러 vs 프로그래머 에러 -### One Paragraph Explainer +### 한문단 설명 -Distinguishing the following two error types will minimize your app downtime and helps avoid crazy bugs: Operational errors refer to situations where you understand what happened and the impact of it – for example, a query to some HTTP service failed due to connection problem. On the other hand, programmer errors refer to cases where you have no idea why and sometimes where an error came from – it might be some code that tried to read an undefined value or DB connection pool that leaks memory. Operational errors are relatively easy to handle – usually logging the error is enough. Things become hairy when a programmer error pops up, the application might be in an inconsistent state and there’s nothing better you can do than to restart gracefully +다음 두 가지의 에러 유형을 구별하면 앱 다운타임(downtime)을 최소화하고 심각한 버그를 방지하는데 도움이 될 것이다: 동작 오류는 발생한 일과 영향에 대해 어떤 상황인지 말한다 – 예를 들면, 연결 문제로 인한 일부 HTTP 서비스 쿼리 실패가 있다. 반면에, 프로그래머 에러는 어디에서 에러가 발생했는지 왜 발생했는지 모르는 경우를 말한다 – 이것은 정의되지 않은 값이나 메모리 누수되는 데이터베이스 연결 풀(connection pool)을 읽으려는 코드일 수 있다. 동작 상의 에러는 비교적 다루기 쉽다 – 보통은 에러를 기록하면 충분하다. 프로그래머 에러가 발생하면, 응용 프로그램이 일관된 상태가 아닐 수도 있으며 이 땐 다시 시작하는 것보다 더 좋은 방법은 없다 -### Code Example – marking an error as operational (trusted) +### 코드 예시 – 동작상의 에러 표시 (신뢰됨) ```javascript // marking an error object as operational @@ -26,29 +26,29 @@ throw new AppError(errorManagement.commonErrors.InvalidInput, "Describe here wha ``` -### Blog Quote: "Programmer errors are bugs in the program" +### 블로그 인용: "프로그램에서 프로그래머 에러는 버그다" -From the blog, Joyent ranked 1 for the keywords “Node.js error handling” +Joyent 블로그에서 "Node.js 에러 처리" 키워드 1위에 위치했다 - > …The best way to recover from programmer errors is to crash immediately. You should run your programs using a restarter that will automatically restart the program in the event of a crash. With a restarter in place, crashing is the fastest way to restore reliable service in the face of a transient programmer error… + > …프로그래머 에러를 복구하는 가장 좋은 방법은 즉시 충돌하는 것이다. 충돌 시 자동으로 프로그램을 다시 시작하는 리스타터(restarter)를 사용하여 프로그램을 실행해야 한다. 리스타터(restarter)를 사용하는 경우, 일시적인 프로그래머 오류에 직면하면 신뢰할 수 있는 서비스를 복구하는 가장 빠른 방법은 충돌이다… -### Blog Quote: "No safe way to leave without creating some undefined brittle state" +### 블로그 인용: "정의되지 않은 취약 상태를 만들지 않고 떠나는 안전한 방법은 없다" -From Node.js official documentation +Node.js 공식문서에서 - > …By the very nature of how throw works in JavaScript, there is almost never any way to safely “pick up where you left off”, without leaking references, or creating some other sort of undefined brittle state. The safest way to respond to a thrown error is to shut down the process. Of course, in a normal web server, you might have many connections open, and it is not reasonable to abruptly shut those down because an error was triggered by someone else. The better approach is to send an error response to the request that triggered the error while letting the others finish in their normal time, and stop listening for new requests in that worker. + > …자바스크립트에서 던지기(throw) 방식의 특성상, 정의되지 않은 종류의 취약 상태를 만들거나 참조 누수 없이는, 안전하게 "중단한 곳에서 픽업(pick up)" 할 수 있는 방법은 거의 없다. 던져진 에러를 처리하는 가장 안전한 방법은 프로세스를 종료하는 것이다. 물론, 일반적인 웹 서버에서는 많은 연결이 열려 있을 수 있으며, 다른 누군가에 의해 오류가 발생했을 수도 있기 때문에 갑자기 연결을 종료하는 것은 적절하지 않다. 더 나은 방법은 다른 사람들이 정상적인 시간에 완료할 수 있도록 하면서 에러를 발생시킨 요청에 대한 에러 응답을 보내고, 새 요청에 대한 응답을 중지하는 것이다. -### Blog Quote: "Otherwise you risk the state of your application" +### 블로그 인용: "그렇지 않으면 당신의 애플리케이션 상태가 위험해질 수 있음" -From the blog, debugable.com ranked 3 for the keywords “Node.js uncaught exception” +debugable.com 블로그에서 "Node.js 예상치 못한 예외 처리" 키워드 3위에 위치했다 - > …So, unless you really know what you are doing, you should perform a graceful restart of your service after receiving an “uncaughtException” exception event. Otherwise, you risk the state of your application, or that of 3rd party libraries to become inconsistent, leading to all kinds of crazy bugs… + > …그래서, 당신이 정말로 무엇을 하고 있는 지 모른다면, "예상치 못한 예외 처리(uncaughtException)" 예외 이벤트를 받은 후 서비스를 다시 시작해야한다. 그렇지 않으면, 애플리케이션 상태나 제 3자 라이브러리의 상태가 일관되지 않아 모든 종류의 심각한 버그가 발생할 위험이 있다… -### Blog Quote: "There are three schools of thoughts on error handling" +### 블로그 인용: "에러 처리에는 주로 세 가지 방법이 있다" -From the blog: JS Recipes +JS Recipes 블로그에서 -> …There are primarily three schools of thoughts on error handling: -1. Let the application crash and restart it. -2. Handle all possible errors and never crash. -3. A balanced approach between the two +> …에러 처리에는 주로 세 가지 방법이 있다: +1. 애플리케이션을 중지하고 다시 시작하기. +2. 가능한 모든 에러를 처리하고 충돌하지 않게 하기. +3. 이 두가지 사이의 균형잡힌 접근 \ No newline at end of file diff --git a/sections/errorhandling/operationalvsprogrammererror.russian.md b/sections/errorhandling/operationalvsprogrammererror.russian.md index 544dbd3c..bfb78c40 100644 --- a/sections/errorhandling/operationalvsprogrammererror.russian.md +++ b/sections/errorhandling/operationalvsprogrammererror.russian.md @@ -1,20 +1,20 @@ -# Различайте операционные и программистские ошибки +# Различайте операционные ошибки и ошибки программиста ### Объяснение в один абзац -Различение следующих двух типов ошибок минимизирует время простоя вашего приложения и помогает избежать сумасшедших ошибок: Операционные ошибки относятся к ситуациям, когда вы понимаете, что произошло, и влияние этого - например, запрос к какой-либо службе HTTP не выполнен из-за проблемы с подключением. С другой стороны, ошибки программиста относятся к случаям, когда вы не знаете, почему, а иногда и откуда возникла ошибка - это может быть какой-то код, который пытался прочитать неопределенное значение или пул соединений с БД, который приводит к утечке памяти. Операционные ошибки относительно легко обрабатываются - обычно достаточно регистрации ошибки. Вещи становятся неприятными, когда появляется ошибка программиста, приложение может быть в несовместимом состоянии, и нет ничего лучше, чем перезапуск изящно. +Разделение ошибок на эти два типа минимизирует время простоя вашего приложения и помогает избежать сумасшедших ошибок: операционные ошибки относятся к ситуациям, когда вы понимаете происходящее и влияние ошибки на программу. Например, запрос к какой-нибудь службе HTTP не выполнен из-за проблемы с подключением. С другой стороны, ошибки программиста относятся к случаям, когда вы не знаете, почему, а иногда и откуда возникла ошибка - это может быть какой-то код, который пытался прочитать undefined-значение или код, который использует пул соединений с БД и приводит к утечке памяти. Операционные ошибки относительно легко обрабатываются - обычно достаточно логирования ошибки. Хуже становиться, когда появляется ошибка программиста, приложение может быть в несогласованном состоянии, и все, что вы можете сделать - перезапустить приложение. -### Пример кода - пометка ошибки как рабочей (доверенной) +### Пример кода - помечаем ошибку как операционную (доверенную)
Javascript ```javascript -// marking an error object as operational -const myError = new Error('How can I add new product when no value provided?'); +// помечаем объект ошибки, как операционный +const myError = new Error('Как мы можем добавить продукт, если значение не задано?'); myError.isOperational = true; -// or if you're using some centralized error factory (see other examples at the bullet "Use only the built-in Error object") +// или, если вы используете централизированную фабрику ошибок (смотрите другие примеры в статье "Используйте только встроенный объект Error") class AppError { constructor (commonType, description, isOperational) { Error.call(this); @@ -25,7 +25,7 @@ class AppError { } }; -throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true); +throw new AppError(errorManagement.commonErrors.InvalidInput, 'Описываем, что произошло', true); ```
@@ -34,7 +34,7 @@ throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here wha Typescript ```typescript -// some centralized error factory (see other examples at the bullet "Use only the built-in Error object") +// или, если вы используете централизированную фабрику ошибок (смотрите другие примеры в статье "Используйте только встроенный объект Error") export class AppError extends Error { public readonly commonType: string; public readonly isOperational: boolean; @@ -42,7 +42,7 @@ export class AppError extends Error { constructor(commonType: string, description: string, isOperational: boolean) { super(description); - Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain + Object.setPrototypeOf(this, new.target.prototype); // восстанавливаем цепочку прототипов this.commonType = commonType; this.isOperational = isOperational; @@ -51,7 +51,7 @@ export class AppError extends Error { } } -// marking an error object as operational (true) +// помечаем объект ошибки, как операционный (true) throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true); ``` @@ -59,27 +59,27 @@ throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here wha ### Цитата блога: "Ошибки программиста - это ошибки в программе" -Из блога Джойент, занявшему 1 место по ключевым словам "Обработка ошибок Node.js" +Из блога Джойент, занявшего 1 место по ключевым словам "Обработка ошибок Node.js" -> … Лучший способ исправить ошибки программиста - это сразу же аварийно завершить работу. Вы должны запустить свои программы, используя перезапуск, который автоматически перезапустит программу в случае сбоя. С перезапуском на месте сбой является самым быстрым способом восстановления надежного сервиса перед лицом временной ошибки программиста … +> … Лучший способ исправить ошибки программиста - это сразу же аварийно завершить работу. Вы должны запускать свои программы, используя сервис перезапуска, который автоматически будет перезапускать программу в случае сбоя. Сервис перезапуска является самым простым способом надежного восстановления сервиса при возникновении временной ошибки программиста… -### Цитата из блога: "Нет безопасного способа уйти, не создав неопределенного хрупкого состояния" +### Цитата из блога: "Нет безопасного способа продолжить без возникновения хрупкого undefined-состояния системы" Из официальной документации Node.js -> … По самой природе того, как throw работает в JavaScript, почти никогда не существует способа безопасно "выбрать то, на чем остановился", без утечки ссылок или создания какого-либо другого неопределенного хрупкого состояния. Самый безопасный способ отреагировать на возникшую ошибку - завершить процесс. Конечно, на обычном веб-сервере у вас может быть открыто много подключений, и нет смысла внезапно закрывать их, потому что кто-то еще вызвал ошибку. Лучший подход - отправить ответ об ошибке на запрос, который вызвал ошибку, позволяя остальным завершить работу в обычное время, и прекратить прослушивание новых запросов этого работника. +> …По самой природе того, как throw работает в JavaScript, почти всегда нет способа безопасно "начать оттуда, где мы остановились", без утечки ссылок или создания другого undefined-состояния. Самый безопасный способ отреагировать на возникшую ошибку - завершить процесс. Конечно, на обычном веб-сервере у вас может быть открыто много подключений, и нет смысла внезапно закрывать все, потому что кто-то другой выбросил ошибку. Лучший вариант - отправить ответ об ошибке на запрос, который ее вызвал, позволяя остальным завершить работу в удобное время, и после прекратить прослушивание новых запросов в воркере, в котором возникла ошибка. ### Цитата блога: "В противном случае вы рискуете состоянием вашего приложения" Из блога debugable.com, занявшего 3 место по ключевым словам "Node.js uncaught exception" -> … Итак, если вы действительно не знаете, что делаете, вам следует выполнить постепенный перезапуск службы после получения события исключения "uncaughtException". В противном случае вы рискуете привести к несогласованности состояния вашего приложения или сторонних библиотек, что приведет к всевозможным сумасшедшим ошибкам … +> …Итак, если вы действительно не знаете, что делаете, вам следует выполнить постепенный перезапуск службы после получения события исключения "uncaughtException". В противном случае вы рискуете привести к несогласованности состояния вашего приложения или сторонних библиотек, что приведет к всевозможным сумасшедшим ошибкам… ### Цитата блога: "Есть три школы мысли об обработке ошибок" Из блога: JS Recipes -> … Существует три основных направления работы с ошибками: +> …Существует три основных направления работы с ошибками: 1. Дайте приложению упасть и перезапустите его. -2. Обрабатывайте все возможные ошибоки и никогда не роняйте. -3. Сбалансированный подход между двумя предыдущими. +2. Обрабатывайте все возможные ошибоки и никогда не роняйте сервис. +3. Сбалансированный подход между двумя предыдущими. \ No newline at end of file diff --git a/sections/errorhandling/returningpromises.basque.md b/sections/errorhandling/returningpromises.basque.md new file mode 100644 index 00000000..463eb78f --- /dev/null +++ b/sections/errorhandling/returningpromises.basque.md @@ -0,0 +1,259 @@ +# Agintzak itzultzea + +
+ +### Azalpen paragrafoa + +Errore bat gertatzen denean fluxu sinkrono edo asinkrono batetik abiatuta, derrigorrezkoa da errore fluxuaren pila aztarna osoa edukitzea. Harrigarria bada ere, funtzio asinkrono batek (adibidez beste funtzio asinkrono bat deitzen duena) itxaron gabe (await) promesak itzultzen dituenean, errore bat gertatuko litzateke eta jatorrizko funtzio horren izena ez litzateke pilaren aztarnan agertu beharko. Horrek informazio partziala emango dio errorea diagnostikatzen duenari, are gehiago errorearen zergatiak jatorrizko funtzioan badu oinarria. Badago "zero-kostuko pila aztarna asinkronoak" deitzen den v8 funtzionalitate bat, pila aztarnak azken gertatu berri den `await`ean moztuak ez izatea ahalbidetzen duena. Garrantzirik gabeko inplementazio xehetasunak direla eta, horrek ez du funtzionatuko funtzioak bueltatzen duen balioa (sinkronoa edo asinkronoa), promesa bat baldin bada. Promesak deusezten direnean pilaren aztarnan zuloak egotea ekiditeoko, promesak beti esplizituki ebatzi behar ditugu `await` erabiliz beraiek funtzioetatik bueltatu baino lehen + +
+ +### Anti ereduaren kode adibidea: funtzio asinkronoak deitu itxaron gabe + +
Javascript +

+ +```javascript +async function asyncJaurti(mezua) { + await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua) + throw Error(mezua) +} + +async function bueltatuItxaronGabe () { + return asyncJaurti('bueltatuItxaronGabe falta da pilaren aztarnan') +} + +// 👎 EZ du edukiko bueltatuItxaronGabe pilaren aztarnan +bueltatuItxaronGabe().catch(console.log) +``` + +erregistratuko du + +``` +Errorea: bueltatuItxaronGabe falta da pilaren aztarnan + asyncJaurti-ren barruan ([...]) +``` +

+
+ +### Kode adibidea: zuzenean deitu eta itxaron + +
Javascript +

+ +```javascript +async function asyncJaurti(mezua) { + await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua) + throw Error(mezua) +} + +async function bueltatuItxaronda() { + return await asyncJaurti('zati guztiak edukiz') +} + +// 👍bueltatuItxaronda edukiko du pilaren aztarnan +bueltatuItxaronda().catch(console.log) +``` + +erregistratuko du + +``` +Error: zati guztiak edukiz + asyncJaurti-ren barruan ([...]) + bueltatuItxaronda-ren barruan ([...]) +``` + +

+
+ +
+ +### Anti ereduaren kode adibidea: itzuli promesak funtzioak asinkronotzat etiketatu gabe + +
Javascript +

+ +```javascript +async function asyncJaurti () { + await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua) + throw Error('syncFn falta da pilaren aztarnan') +} + +function syncFn () { + return asyncJaurti() +} + +async function asyncFn () { + return await syncFn() +} + +// 👎 ez dut edukiko syncFn pilaren aztarnan promesak itzultzen dituelako sinkronizatzen den ari den bitartean +asyncFn().catch(console.log) +``` + +erregistratuko du + +``` +Error: syncFn falta da pilaren aztarnan + asyncJaurti-ren barruan ([...]) + async asyncFn-en barruan ([...]) +``` + +

+
+ +### Kode adibidea: etiketatu promesak asinkrono gisa itzultzen dituen funtzioa + +
Javascript +

+ +```javascript +async function asyncJaurti () { + await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua) + throw Error('zati guztiak edukiz') +} + +async function syncEtikAsyncFnraAldatua() { + return await asyncJaurti() +} + +async function asyncFn () { + return await syncEtikAsyncFnraAldatua() +} + +// 👍 orain syncEtikAsyncFnraAldatua pilaren aztarnan agertuko da +asyncFn().catch(console.log) +``` + +erregistratuko du + +``` +Error: zati guztiak edukiz + asyncJaurti-ren barruan ([...]) + syncEtikAsyncFnraAldatua-ren barruan ([...]) + async asyncFn-en barruan ([...]) +``` + +

+
+ +
+ +### Kode adibidea, anti eredua #3: callback asinkronoen erabilera zuzena callback sinkronoa espero zen lekuan + +
Javascript +

+ +```javascript +async function berreskuratuErabiltzailea (id) { + await null + if (!id) throw Error('pilaren aztarna falta da berreskuratuErabiltzailea deitu den lekuan') + return {id} +} + +const erabiltzaileIdak = [1, 2, 0, 3] + +// 👎 pilaren aztarnak berreskuratuErabiltzailea funtzioa edukiko du baina ez du zehaztuko non izan den deitua +Promise.all(erabiltzaileIdak.map(berreskuratuErabiltzailea)).catch(console.log) +``` + +erregistratuko du + +``` +Error: pilaren aztarna falta da berreskuratuErabiltzailea deitu den lekuan + berreskuratuErabiltzailea-en barruan ([...]) + async Promise.all-en barruan (index 2) +``` + +*Apunte bat*: pentsa liteke `Promise.all (index 2)`ek `berreskuratuErabiltzailea` deitua izan den lekua ulertzen lagundu dezakela, baina [guztiz ezberdina den v8ko akatsa](https://bugs.chromium.org/p/v8/issues/detail?id=9023) dela eta, `(index 2)` v8 barneko lerro bat da + +

+
+ +### Kode adibidea: bildu callback asinkronoa funtzio asinkrono faltsu batean callback sinkrono gisa bidali aurretik + +
Javascript +

+ +*1.oharra*: callbacka deituko duen funtzioaren kodea kontrolatuz gero, soilik aldatu funtzio hau asinkronora eta gehitu `await` callback deiaren aurretik. Callbacka deitzen duen kodearen ardurandu ez zarela kontsideratu dut behean (edo honen aldaketa onartezina da adibidez atzeranzko-konpatibilitatea dela eta) + +*2.oharra*: sarri, callback sinrkono bat espero den lekuetan callback asinkronoak erabiltzeak ez du inola ere funtzionatuko. Hau ez da funtzionatzen ez duen kodea nola konpontzeari buruz, kodea behar bezala funtzionatzen ari denean pilaren aztarna nola konpontzeari buruz baizik + +```javascript +async function berreskuratuErabiltzailea (id) { + await null + if (!id) throw Error('zati guztiak edukiz') + return {id} +} + +const erabiltzaileIdak = [1, 2, 0, 3] + +// 👍 orain azpiko lerroa pilaren aztarnan dago +Promise.all(erabiltzaileIdak.map(async id => await berreskuratuErabiltzailea(id))).catch(console.log) +``` + +erregistratuko du + +``` +Error: zati guztiak edukiz + berreskuratuErabiltzailea-ren barruan ([...]) + async-en barruan ([...]) + async Promise.all-en barruan (index 2) +``` + +`map` barruko `await` explizituari esker, `async-ren barruan ([...])` lerroaren bukaerak `berreskuratuErabiltzailea` deitua izan den puntu zehatza adieraziko du + +*Apunte bat*: `berreskuratuErabiltzailea` biltzen duen funtzio asinkrono batek `await` ahazten badu zerbait bueltatu aurretik (anti-eredua #1 + anti-eredua #3), zati bat bakarrik izango da mantendua pilaren aztarnan: + + +```javascript +[...] + +// 👎 anti-pattern 1 + anti-pattern 3 - only one frame left in stacktrace +Promise.all(erabiltzaileIdak.map(async id => berreskuratuErabiltzailea(id))).catch(console.log) +``` + +erregistratuko du + +``` +Error: [...] + berreskuratuErabiltzailea-ren barruan ([...]) +``` + +

+
+ +
+ +Zero kostuko pila aztarna asinkronoak" deitzen den v8 funtzionalitate bat + +## Azalpen aurreratua + +Oso ezberdinak dira funtzio sinkronoen pila aztarnen eta funtzio asinkronoen pila aztarnen mekanismoak v8ren ezarpenetan: pila aztarna asinkronoa oinarritua dago Node.js martxan dagoen sistema eragileak emandako **pila**n (programazio lengoaia gehienak bezala). Funtzio asinkrono bat exekutatzen ari denean, sistema eragileko **pila** agerian jartzen da funtzioa bere lehen `await`era iristen den momentuan. Beraz, pilaren aztarna nahasketa bat da, hain zuzen, sistema eragilearen pilaren eta baztertutako **promesa ebazpen katea**rena. Zero kostuko pila aztarna asinkronoen ezarpenak **promesa ebazpen katea** luzatzen du bakarrik promesa `itxaroten` [¹](#1) ari den bitartean. Funtzio asinkronoek bakarrik (`async`) itxaron (`await`) ahal dutenez, beti galduko da funtzio asinkronoa pilaren aztarna asinkrono batean, operazio asinkronoren bat izan bada funtzioa deitu eta gero [²](#2) + +### The tradeoff (sektorea) + +`await` bakoitzak mikro ataza berri bat sortzen du gertaeraren begiztan. Beraz `await` gehiago gehitzeak errendimendu zigorra ekarriko luke. Hala ere, sareak edota datu baseak sortutako errendimendu isuna [ikaragarri handiagoa](https://colin-scott.github.io/personal_website/research/interactive_latency.html) da, eta, beraz gehitutako `await`aren zigorra ez da zerbitzariak edo CLIak garatzeko orduan kontutan hartu beharreko zerbait, eskaera edo komando bakoitzeko oso kode beroa izan ezean behintzat. Orduan, `await` ezabatzeak `return await`etan errendimendu bultzada nabarmena bilatzeko azken lekua izan beharko luke eta, zalantzarik gabe, inoiz ez litzateke aldez aurretik egin beharko + + +### Zergatik jotzen zen await bueltatzea anti eredutzat iraganean + +[Artikulu bikain](https://jakearchibald.com/2017/await-vs-return-vs-return-await/) ugari daude azaltzen dutenak zergatik `return await`ak ez diren inoiz `try` bloketik kanpo erabili behar, bai eta [ESLint arau](https://eslint.org/docs/rules/no-return-await) arau bat ere hori debekatzen duena. Horren arrazoia da async/await Node.js 0.10ko transpilagailuekin erabilgarri bihurtu izana (eta jatorrizko laguntza lortu dutela Node.js 7.6 bertsioan) eta "zero kostuko pila aztarna asinkronoak" Node.js 10en gehitua izana eta ondoren Node.js 12tik kendua, `return await` eta `return` guztiz parekoak ziren, edozein `try` kode bloketik kanpo. Oraindik ere berdina izaten jarraituko du seguraski ES motoreentzat. Horregatik, Node.jsentzat jardunbide egokiena da promesak kalkulatzea beraiek bueltatu aurretik. EcmaScriptentzat, ordea, hori ez jardunbide egokiena. + +### Oharrak: + +1. Pila aztarna asinkronoak halako ezarpen korapilatsua izatearen beste arrazoi bat da pila aztarna beti modu sinkronoan eraiki behar dela, gertaeraren begiztaren [¹](#1) momentu berean + +2. `throwAsync` barruan `await` gabe, gertaera begiztaren fase berean exekutatuko litzateke kodea. Hori, degeneratutako kasua da: sistema eragilearen **pila** ez litzateke hustuko, eta pila aztarna beteko litzateke funtzioaren emaitzari berariaz itxaron gabe ere. Normalean, promesen erabilerak operazio asinkrono batzuk edukitzen dituenez, pilaren aztarnaren zati batzuk galdu egingo lirateke + +3. Zero kostuko pila aztarna asinkronoek ez lukete funtzionatuko promesa erabileren kasu korapilatsuetan: promesa bakar bati hainbat aldiz eta leku ezberdinetan itxaron beharra dagoenean, adibidez. + + +### Erreferentziak: + 1. [v8ko zero kostuko pila aztarna asinkronoak blog argitarapena](https://v8.dev/blog/fast-async) +
+ + 2. [zero kostuko pila aztarna asinkronoei inguruko dokumentazioa ezarpen xehetasunekin hemen]( + https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit + ) +
diff --git a/sections/errorhandling/returningpromises.md b/sections/errorhandling/returningpromises.md new file mode 100644 index 00000000..7ba1861c --- /dev/null +++ b/sections/errorhandling/returningpromises.md @@ -0,0 +1,285 @@ +# Returning promises + +
+ +### One Paragraph Explainer + +When an error occurs, whether from a synchronous or asynchronous flow, it's imperative to have a full stacktrace of the error flow. Surprisingly, if an async function returns a promise (e.g., calls other async function) without awaiting, should an error occur then the caller function won't appear in the stacktrace. This will leave the person who diagnoses the error with partial information - All the more if the error cause lies within that caller function. There is a feature v8 called "zero-cost async stacktraces" that allow stacktraces not to be cut on the most recent `await`. But due to non-trivial implementation details, it will not work if the return value of a function (sync or async) is a promise. So, to avoid holes in stacktraces when returned promises would be rejected, we must always explicitly resolve promises with `await` before returning them from functions + +
+ +### Code example Anti-Pattern: Calling async function without awaiting + +
Javascript +

+ +```javascript +async function throwAsync(msg) { + await null // need to await at least something to be truly async (see note #2) + throw Error(msg) +} + +async function returnWithoutAwait () { + return throwAsync('missing returnWithoutAwait in the stacktrace') +} + +// 👎 will NOT have returnWithoutAwait in the stacktrace +returnWithoutAwait().catch(console.log) +``` + +would log + +``` +Error: missing returnWithoutAwait in the stacktrace + at throwAsync ([...]) +``` +

+
+ +### Code example: Calling and awaiting as appropriate + +
Javascript +

+ +```javascript +async function throwAsync(msg) { + await null // need to await at least something to be truly async (see note #2) + throw Error(msg) +} + +async function returnWithAwait() { + return await throwAsync('with all frames present') +} + +// 👍 will have returnWithAwait in the stacktrace +returnWithAwait().catch(console.log) +``` + +would log + +``` +Error: with all frames present + at throwAsync ([...]) + at async returnWithAwait ([...]) +``` + +

+
+ +
+ +### Code example Anti-Pattern: Returning a promise without tagging the function as async + +
Javascript +

+ +```javascript +async function throwAsync () { + await null // need to await at least something to be truly async (see note #2) + throw Error('missing syncFn in the stacktrace') +} + +function syncFn () { + return throwAsync() +} + +async function asyncFn () { + return await syncFn() +} + +// 👎 syncFn would be missing in the stacktrace because it returns a promise while been sync +asyncFn().catch(console.log) +``` + +would log + +``` +Error: missing syncFn in the stacktrace + at throwAsync ([...]) + at async asyncFn ([...]) +``` + +

+
+ +### Code example: Tagging the function that returns a promise as async + +
Javascript +

+ +```javascript +async function throwAsync () { + await null // need to await at least something to be truly async (see note #2) + throw Error('with all frames present') +} + +async function changedFromSyncToAsyncFn () { + return await throwAsync() +} + +async function asyncFn () { + return await changedFromSyncToAsyncFn() +} + +// 👍 now changedFromSyncToAsyncFn would present in the stacktrace +asyncFn().catch(console.log) +``` + +would log + +``` +Error: with all frames present + at throwAsync ([...]) + at changedFromSyncToAsyncFn ([...]) + at async asyncFn ([...]) +``` + +

+
+ +
+ +### Code Example Anti-pattern #3: direct usage of async callback where sync callback is expected + +
Javascript +

+ +```javascript +async function getUser (id) { + await null + if (!id) throw Error('stacktrace is missing the place where getUser has been called') + return {id} +} + +const userIds = [1, 2, 0, 3] + +// 👎 the stacktrace would include getUser function but would give no clue on where it has been called +Promise.all(userIds.map(getUser)).catch(console.log) +``` + +would log + +``` +Error: stacktrace is missing the place where getUser has been called + at getUser ([...]) + at async Promise.all (index 2) +``` + +*Side-note*: it may looks like `Promise.all (index 2)` can help understanding the place where `getUser` has been called, +but due to a [completely different bug in v8](https://bugs.chromium.org/p/v8/issues/detail?id=9023), `(index 2)` is +a line from internals of v8 + +

+
+ +### Code example: wrap async callback in a dummy async function before passing it as a sync callback + +
Javascript +

+ +*Note 1*: in case if you control the code of the function that would call the callback - just change that function to +async and add `await` before the callback call. Below I assume that you are not in charge of the code that is calling +the callback (or it's change is unacceptable for example because of backward compatibility) + +*Note 2*: quite often usage of async callback in places where sync one is expected would not work at all. This is not about +how to fix the code that is not working - it's about how to fix stacktrace in case if code is already working as +expected + +```javascript +async function getUser (id) { + await null + if (!id) throw Error('with all frames present') + return {id} +} + +const userIds = [1, 2, 0, 3] + +// 👍 now the line below is in the stacktrace +Promise.all(userIds.map(async id => await getUser(id))).catch(console.log) +``` + +would log + +``` +Error: with all frames present + at getUser ([...]) + at async ([...]) + at async Promise.all (index 2) +``` + +where thanks to explicit `await` in `map`, the end of the line `at async ([...])` would point to the exact place where +`getUser` has been called + +*Side-note*: if async function that wrap `getUser` would miss `await` before return (anti-pattern #1 + anti-pattern #3) +then only one frame would left in the stacktrace: + +```javascript +[...] + +// 👎 anti-pattern 1 + anti-pattern 3 - only one frame left in stacktrace +Promise.all(userIds.map(async id => getUser(id))).catch(console.log) +``` + +would log + +``` +Error: [...] + at getUser ([...]) +``` + +

+
+ +
+ +## Advanced explanation + +The mechanisms behind sync functions stacktraces and async functions stacktraces in v8 implementation are quite different: +sync stacktrace is based on **stack** provided by operating system Node.js is running on (just like in most programming +languages). When an async function is executing, the **stack** of operating system is popping it out as soon as the +function is getting to it's first `await`. So async stacktrace is a mix of operating system **stack** and a rejected +**promise resolution chain**. Zero-cost async stacktraces implementation is extending the **promise resolution chain** +only when the promise is getting `awaited` [¹](#1). Because only `async` functions may `await`, +sync function would always be missed in async stacktrace if any async operation has been performed after the function +has been called [²](#2) + +### The tradeoff + +Every `await` creates a new microtask in the event loop, so adding more `await`s to the code would +introduce some performance penalty. Nevertheless, the performance penalty introduced by network or +database is [tremendously larger](https://colin-scott.github.io/personal_website/research/interactive_latency.html) +so additional `await`s penalty is not something that should be considered during web servers or CLI +development unless for a very hot code per request or command. So removing `await`s in +`return await`s should be one of the last places to search for noticeable performance boost and +definitely should never be done up-front + + +### Why return await was considered as anti-pattern in the past + +There is a number of [excellent articles](https://jakearchibald.com/2017/await-vs-return-vs-return-await/) explained +why `return await` should never be used outside of `try` block and even an +[ESLint rule](https://eslint.org/docs/rules/no-return-await) that disallows it. The reason for that is the fact that +since async/await become available with transpilers in Node.js 0.10 (and got native support in Node.js 7.6) and until +"zero-cost async stacktraces" was introduced in Node.js 10 and unflagged in Node.js 12, `return await` was absolutely +equivalent to `return` for any code outside of `try` block. It may still be the same for some other ES engines. This +is why resolving promises before returning them is the best practice for Node.js and not for the EcmaScript in general + +### Notes: + +1. One another reason why async stacktrace has such tricky implementation is the limitation that stacktrace +must always be built synchronously, on the same tick of event loop [¹](#1) +2. Without `await` in `throwAsync` the code would be executed in the same phase of event loop. This is a +degenerated case when OS **stack** would not get empty and stacktrace be full even without explicitly +awaiting the function result. Usually usage of promises include some async operations and so parts of +the stacktrace would get lost +3. Zero-cost async stacktraces still would not work for complicated promise usages e.g. single promise +awaited many times in different places + +### References: + 1. [Blog post on zero-cost async stacktraces in v8](https://v8.dev/blog/fast-async) +
+ + 2. [Document on zero-cost async stacktraces with mentioned here implementation details]( + https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit + ) +
diff --git a/sections/errorhandling/returningpromises.russian.md b/sections/errorhandling/returningpromises.russian.md new file mode 100644 index 00000000..ed58d69f --- /dev/null +++ b/sections/errorhandling/returningpromises.russian.md @@ -0,0 +1,289 @@ +# Возвращение промисов + +
+ +### Короткое объяснение + +У v8 есть особая способность, называемая "бесплатные асинхронные стектрейсы", которая позволяет стектрейсам не +обрываться на самом позднем `await`. Но, из-за нетривиальных нюансов реализации, она не сработает если возвращаемое +значение функции (синхронной или асинхронной) является промис. По этому, для того чтобы избежать дыр в стектрейсах +после отказа (rejection) возвращаемого промиса, следует всегда явно разрешать (resolve) промисы при помощи `await` +перед тем как возвращать их из функций + +
+ +### Анти-паттерн №1: return \ + +
Javascript +

+ +```javascript +async function throwAsync(msg) { + await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2) + throw Error(msg) +} + +async function returnWithoutAwait () { + return throwAsync('missing returnWithoutAwait in the stacktrace') +} + +// 👎 returnWithoutAwait будет отсутствовать в стектрейсе +returnWithoutAwait().catch(console.log) +``` + +выведет в лог + +``` +Error: missing returnWithoutAwait in the stacktrace + at throwAsync ([...]) +``` + +

+
+ +### Как правильно: return await \ + +
Javascript +

+ +```javascript +async function throwAsync(msg) { + await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2) + throw Error(msg) +} + +async function returnWithAwait() { + return await throwAsync('with all frames present') +} + +// 👍 returnWithAwait будет присутствовать в стектрейсе +returnWithAwait().catch(console.log) +``` + +выведет в лог + +``` +Error: with all frames present + at throwAsync ([...]) + at async returnWithAwait ([...]) +``` + +

+
+ +
+ +### Анти-паттерн №2: синхронная функция возвращающая промис + +
Javascript +

+ +```javascript +async function throwAsync () { + await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2) + throw Error('missing syncFn in the stacktrace') +} + +function syncFn () { + return throwAsync() +} + +async function asyncFn () { + return await syncFn() +} + +// 👎 syncFn будет отсутствовать в стектрейсе так как она синхронная и возвращает промис +asyncFn().catch(console.log) +``` + +would log + +``` +Error: missing syncFn in the stacktrace + at throwAsync ([...]) + at async asyncFn ([...]) +``` + +

+
+ +### Как правильо: объявить функцию возвращающую промис как асинхронную + +
Javascript +

+ +```javascript +async function throwAsync () { + await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2) + throw Error('with all frames present') +} + +async function changedFromSyncToAsyncFn () { + return await throwAsync() +} + +async function asyncFn () { + return await changedFromSyncToAsyncFn() +} + +// 👍 теперь changedFromSyncToAsyncFn будет присутствовать в стектрейсе +asyncFn().catch(console.log) +``` + +would log + +``` +Error: with all frames present + at throwAsync ([...]) + at changedFromSyncToAsyncFn ([...]) + at async asyncFn ([...]) +``` + +

+
+ +
+ +### Анти-паттерн №3: прямая передача асинхронного коллбэка в месте где ожидается синхронный коллбек + +
Javascript +

+ +```javascript +async function getUser (id) { + await null + if (!id) throw Error('stacktrace is missing the place where getUser has been called') + return {id} +} + +const userIds = [1, 2, 0, 3] + +// 👎 хотя в стектрейсе будет присутствовать функция getUser, в нем не будет места где она была вызвана +Promise.all(userIds.map(getUser)).catch(console.log) +``` + +выведет в лог + +``` +Error: stacktrace is missing the place where getUser has been called + at getUser ([...]) + at async Promise.all (index 2) +``` + +*Между прочим*: может показаться что `Promise.all (index 2)` может помоч понять где `getUser` была вызвана, но из-за +[совершенно другого бага в v8](https://bugs.chromium.org/p/v8/issues/detail?id=9023), `(index 2)` является строкой из +внутреннего кода v8 + +

+
+ +### Как правильно: обернуть асинхронный коллбэк в асинхронную функция перед тем как передать его как синхронный коллбэк + +
Javascript +

+ +*Заметка 1*: в случае если вы отвечаете за код функции которая в итоге вызовет коллбэк - просто сделаете ее асинхронной и +добавьте `await` перед вызовом коллбэка. Далее я предполагаю что вы не имеете контроля над кодом функции которая +вызывает коллбэк (или ее изменение таким образом недопустимо, например, из соображений обратной совместимости) + +*Заметка 2*: Имейте ввиду, часто передача асинхронного коллбэка в место где ожидается синхронный коллбэк вообще не будет работать. +Тут описывается не как починить такой код а лишь как починить стектрейсы если код уже работает как ожидается + +```javascript +async function getUser (id) { + await null + if (!id) throw Error('with all frames present') + return {id} +} + +const userIds = [1, 2, 0, 3] + +// 👍 теперь строка вызова getUser присутствует в стектрейсе +Promise.all(userIds.map(async id => await getUser(id))).catch(console.log) +``` + +выведет в лог + +``` +Error: with all frames present + at getUser ([...]) + at async ([...]) + at async Promise.all (index 2) +``` + +где, благодаря явному `await` в `map`, конец строки `at async ([...])` указывает на место где `getUser` была вызвана + +*Между прочим*: если оберточная асинхронная функция для `getUser` не сделает явный `await` перед возвратом (то есть +комбинация анти-паттерн 1 + анти-паттерн 3), то стектрейс останется вообще всегда с одним кадром: + +```javascript +[...] + +// 👎 анти-паттерн 1 + анти-паттерн 3 - в стектрейсе осталась только getUser +Promise.all(userIds.map(async id => getUser(id))).catch(console.log) +``` + +выведет в лог + +``` +Error: [...] + at getUser ([...]) +``` + +

+
+ +
+ +### Углубленное объяснение + +Механизмы стоящие за построением синхронных и асинхронных стектрейсов в v8 довольно сильно отличаются: синхронные +стектрейсы основаны на **стеке** операционной системы на которой запущен Node.js (как и для многих других языков +программирования). Во время выполнения асинхронной функции, **стек** операционной системы выталкивает функцию как +только та доходит до первого-же `await`. По этому асинхронные стектрейсы представляют собой смесь **стека** +операционной системы и **цепочки разрешения отказанного (rejected) промиса**. "Бесплатные асинхронные стектрейсы" +реализованны таким образом что **цепочка разрешения промиса** расширяется только когда на промисе исполняется `await` +[¹](#1). По сколько только асинхронные функции могут использовать `await`, синхронные функции +всегда будут упущены из асинхронного стектрейса если любая асинхронная операция была исполнена после момента вызова +этой синхронной функции [²](#2) + +### Компромисc + +Каждый `await` создает дополнительную микрозадачу (microtask) в цикле событий (event loop), по +этому дополнительные `await`-ы в коде создадут определенную дополнительную нагрузку. Тем ни менее, +задержки создаваемые сетью и базой данных [несоизмеримо выше](https://colin-scott.github.io/personal_website/research/interactive_latency.html) +по этому нагрузка создаваемая дополнительными `await`-ами не является чем-то что стоит принимать во +внимание при разработке веб-серверов или интерфейсов командной строки (CLI), разве что для очень +горячих участков кода на запрос или команду. По этому убирание `await`-ов из `return await` должно +быть одним из последних мест для поиска значимых улучшений производительности приложения и точно не +должно выполняться наперед + +### Почему return await раньше считалось анти-паттерном + +Существует ряд [отличных статей](https://jakearchibald.com/2017/await-vs-return-vs-return-await/) объясняющих почему +`return await` никогда не должен быть использован за пределами `try` блока и даже +[правело ESLint](https://eslint.org/docs/rules/no-return-await) которое такое использование запрещает. Причина +заключается в том что с момента когда async/await стали доступны с помощью транспайлеров в Node.js 0.10 (и получил +встроенную поддержку с Node.js 7.6) и до момента пока не появились "бесплатные асинхронные стектрейсы", `return await` +было абсолютно эквивалентно `await` для любого кода за пределами `try` блока. Для каких-то ES движков это все так-же +может оставаться правдой. По этой причине разрешение (resolve) промисов перед возвращением является лучшей практикой +для Node.js, а не для EcmaScript в целом + +### Заметки: +1. Одной из причин почему асинхронные сетктрейсы имеют столь нетривиальную реализация является требование к +стектрейсу быть созданными синхронно, в пределах одного цикла петли событий (event loop) [¹](#1) +2. без `await` в `throwAsync` весь код выполнится в одной фазе петли событий (event loop). Это вырожденный случай +когда **стек** операционной системы не успеет опустошиться и стектрейс будет полным даже без явного `await` результата +вызова функции. Обычно использование промисов подразумевает исполнение асинхронных операций, а значит части стектрейса +все-же будут утрачены +3. "Бесплатные асинхронные стектрейсы" не работают для особо сложных потоков промисов, например когда `await` +выполняется для одного и того-же промиса в разных местах + +### References: + 1. [Блогпост о бесплатных асинхронных стектрейсах в v8](https://v8.dev/blog/fast-async) +
+ + 2. [Документ о бесплатных асинхронных стектрейсах в v8 с упомянутыми тут деталями реализации]( + https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit + ) +
diff --git a/sections/errorhandling/shuttingtheprocess.basque.md b/sections/errorhandling/shuttingtheprocess.basque.md new file mode 100644 index 00000000..835b3494 --- /dev/null +++ b/sections/errorhandling/shuttingtheprocess.basque.md @@ -0,0 +1,99 @@ +# Irten prozesutik elegantziarekin kanpoko norbait iristen denean hirira + +### Azalpen paragrafoa + +Zure kodearen lekuren batean, erroreren bat gertatzen denean erroreen kudeaketa objektuaren ardura da erabakitzea nola jokatu, eta, errorea konfiantzazkoa bada, nahikoa izango da erregistro fitxategian idaztea; errorea operazionala bada, berriz, irakurri azalpen osatuagoa #3 jarraibide egokian). Gauzak okertzen dira errorea ezezaguna denean, horrek osagairen bat egoera txarrean dagoela eta hurrengo eskaera guztiek huts egiteko aukera handia dutela esan nahi du eta. Adibidez, eman dezagun, singleton bat edukita, token batek salbuespen bat igorri duela eta ondoren bere egoera galdu duen zerbitzu batekin arazoa duela; hortik aurrera ustekabean joka dezake eta eskaera guztiek huts egitea eragin. Egoera horren aurrean, prozesua gelditu eta 'Berrekite tresna' erabili (Forever, PM2, etab. bezalakoak) egoera garbi batekin berriz hasteko. + +### Kode adibidea: huts eragin ala ez erabakitzen + +
+Javascript + +```javascript +// Garatzaileek operazio erroreak errorea.operazioErroreaDa=true zehazten dutela ziurtzat joz, irakur ezazu #3 jarraibide egokia +process.on('uncaughtException', (errorea) => { + erroreKudeaketa.kudeatzailea.kudeatuErrorea(errorea); + if(!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea)) + process.exit(1) +}); + +// errore kudeatzaile zentralizatuak errore-kudeaketa logika kapsulatzen du +function erroreKudeatzailea() { + this.kudeatuErrorea = (errorea) => { + return logger.erroreaErregistratu(errorea) + .then(kritikoaBadaAdministrariariPostaElektronikoaBidali) + .then(kritikoaBadaOperazioZerrendanGorde) + .then(erabakiIaOperazioErroreaDen); + } + + this.erroreFidagarriaDa = (errorea) => { + return errorea.operazioErroreaDa; + } +} +``` +
+ +
+Typescript + +```typescript +// Garatzaileek operazio erroreak errorea.operazioErroreaDa=true zehazten dutela ziurtzat joz, irakur ezazu #3 jarraibide egokia +process.on('uncaughtException', (errorea: Error) => { + erroreKudeaketa.kudeatzailea.kudeatuErrorea(errorea); + if(!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea)) + process.exit(1) +}); + +// Nodeko Erroretik datorren errore objektu zentralizatua +export class AppErrorea extends Error { + public readonly operazioErroreaDa: boolean; + + constructor(deskribapena: string, operazioErroreaDa: boolean) { + super(deskribapena); + Object.setPrototypeOf(this, new.target.prototype); // prototipo katea berreskuratu + this.operazioErroreaDa = operazioErroreaDa; + Error.captureStackTrace(this); + } +} + +// errore kudeatzaile zentralizatuak errore-kudeaketa logika kapsulatzen du +class ErroreKudeatzailea { + public async kudeatuErrorea(errorea: Error): Promise { + await logger.erroreaErregistratu(errorea); + await kritikoaBadaAdministrariariPostaElektronikoaBidali(); + await kritikoaBadaOperazioZerrendanGorde(); + await erabakiIaOperazioErroreaDen(); + }; + + public erroreFidagarriaDa(errorea: Error) { + if (errorea instanceof AppErrorea) { + return errorea.operazioErroreaDa; + } + return false; + } +} + +export const kudeatzailea = new ErroreKudeatzailea(); +``` +
+ +### Blogeko aipua: "Irtenbiderik hoberena huts egitea da" + +Joyent blogetik hartua + +> …Programatzaileen erroreak konpontzeko modurik hoberena berehala krak egitea da. Programaren batek huts eginez gero, berrabiarazle bat erabiliz exekutatu beharko zenuke, automatikoki berrabiaraziko baitu. Berrabiarazlea dagoenean, huts egitea da programa fidagarria berreskuratzeko biderik azkarrena programatzailearen errore iragankor baten aurrean ... + +### Blogeko aipua: "Errore kudeaketaren inguruko hiru ideia eskola daude" + +JS Recipes blogetik hartua + +> …Errore kudeaketaren inguruko hiru ideia eskola nagusi daude: +1. Utzi aplikazioari huts egiten eta ondoren berrabiarazi +2. Errore posible guztiak kudeatu eta inoiz ez huts egin +3. Bien arteko planteamendu bat + +### Blogeko aipua: "Ez dago modu segururik irteteko zehaztugabeko egoera hauskorrik sortu gabe" + +Node.js dokumentazio ofizialetik hartua + +> …JavaScripten lanak nola exekutatzen diren kontuan izanda, ez dago ia inoiz lan bati ziurtasunez jarraipena emateko biderik utzitako puntuan hasita, erreferentziak galdu gabe edota bestelako zehaztugabeko egoera hauskorrik sortu gabe. Jaurtitako errore bati erantzuteko modurik seguruena prozesua itzaltzea da. Jakina, web zerbitzari arruntetan, konekxio ugari eduki ahal dituzu irekita, eta ez da zentzuzkoa tupustean haiek ixtea beste batek eragindako errore batengatik. Planteamendu hoberena da bidaltzea errore erantzun bat errorea bidali duen eskariari, besteei beren atazak bukatzeko denbora utziz, eta eskari berriei kasu egiteari uztea prozesu horretan. diff --git a/sections/errorhandling/testingerrorflows.basque.md b/sections/errorhandling/testingerrorflows.basque.md new file mode 100644 index 00000000..8d53e46a --- /dev/null +++ b/sections/errorhandling/testingerrorflows.basque.md @@ -0,0 +1,94 @@ +# Testeatu erroreen fluxua zure test framework gustukoena erabiliz + +### Azalpen paragrafoa + +Bide ‘alaiak’ probatzea ez da hutsegiteak probatzea baino hobea. Probako kodeen estaldura ona da salbuespenezko bideak probatzeko. Bestela, ez dago inolako konfidantzarik salbuespenak zuzen kudeatuta dauden. Unitateen azterketa esparru guztiek, [Mocha](https://mochajs.org/) edo [Chai](http://chaijs.com/) bezala, onartzen dituzte salbuespen probak (kode adibideak beherago). Gogaikarria iruditzen bazaizu funtzio eta salbuespen bakoitza probatzea, REST APIen HTTP erroreak bakarrik probatzea erabaki zenezake. + + +### Kode adibidea: ziurtatu salbuespen egokia jaurtitzen dela Mocha eta Chai erabiliz + +
+Javascript + +```javascript +describe("Facebooken txata", () => { + it("Jakinarazi txateko mezu berria iristean", () => { + const txatZerbitzua = new txatZerbitzua(); + txatZerbitzua.parteHartzaileak = eskuratuDeskonektatutakoParteHartzaileak(); + expect(txatZerbitzua.mezuaBidali.bind({ mezua: "Aupa" })).to.throw( + KonexioErrorea + ); + }); +}); +``` + +
+ +
+Typescript + +```typescript +describe("Facebooken txata", () => { + it("Jakinarazi txateko mezu berria iristean", () => { + const txatZerbitzua = new txatZerbitzua(); + txatZerbitzua.parteHartzaileak = eskuratuDeskonektatutakoParteHartzaileak(); + expect(txatZerbitzua.mezuaBidali.bind({ mezua: "Aupa" })).to.throw( + KonexioErrorea + ); + }); +}); +``` + +
+ +### Kodearen adibidea: APIak HTTP errore kode zuzena bueltatzen duela ziurtatu + +
+Javascript + +```javascript +it("Facebookeko talde berria sortu", () => { + const taldeOkerrarenInformazioa = {}; + return httpRequest({ + method: "POST", + uri: "facebook.com/api/groups", + resolveWithFullResponse: true, + body: taldeOkerrarenInformazioa, + json: true, + }) + .then((response) => { + expect.fail( + "kodea bloke honetan exekutatu nahi bagenu, goiko operazioan errorerik ez da izan" + ); + }) + .catch((response) => { + expect(400).to.equal(response.statusCode); + }); +}); +``` + +
+ +
+Typescript + +```typescript +it("Facebookeko talde berria sortu", async () => { + let taldeOkerrarenInformazioa = {}; + try { + const response = await httpRequest({ + method: "POST", + uri: "facebook.com/api/groups", + resolveWithFullResponse: true, + body: taldeOkerrarenInformazioa, + json: true, + }); + // kodea bloke honetan exekutatu nahi bagenu, goiko operazioan errorerik ez da izan + expect.fail("Eskaerak huts egin behar izango luke"); + } catch (response) { + expect(400).to.equal(response.statusCode); + } +}); +``` + +
diff --git a/sections/errorhandling/usematurelogger.basque.md b/sections/errorhandling/usematurelogger.basque.md new file mode 100644 index 00000000..d0fbd865 --- /dev/null +++ b/sections/errorhandling/usematurelogger.basque.md @@ -0,0 +1,43 @@ +# Erabili erregistratze tresna heldu bat erroreen ikusgaitasuna handitzeko + +### Azalpen paragrafoa + + +Gustuko dugu console.log, baina [Pino][pino] bezalako erregistratzaile tresna ospetsu eta iraunkorra (errendimenduan zentratutako aukera berriagoa) ezinbestekoa da proiektu serioetarako. Errendimendu handiko erregistratze tresnek erroreak eta arazo posibleak identifikatzen laguntzen dute. Erregistratze aholkuen artean: + +1. Maiz erregistratu maila ezberdinak erabiliz (debug, info, error) +2. Erregistratzerako orduan, eman testuinguruaren informazioa JSON objektu eran +3. Monitorizatu erregistro kontsultak API batekin (erregistro sistema ezberdinetarako erabilgarria) edota erregistro ikustailearen software batekin +4. Erakutsi erregistroen informazioa [Splunk][splunk] bezalako operazio inteligentzia tresnekin + +[pino]: https://www.npmjs.com/package/pino +[splunk]: https://www.splunk.com/ + +### Kode adibidea + +```JavaScript +const pino = require('pino'); + +// zure erregistro objektu zentralizatua +const erregistratzailea = pino(); + +// erregistratzailea erabiltzen duen zure kode propioa +erregistratzailea.info({ anything: 'Hau metadatua da' }, 'Frogatu Erregistro Mezua %s parametroren batekin', 'parametroren bat'); +``` + +### Blogeko aipua: "Erregistratzailearen betebeharrak" + +StrongLoop blogetik hartua ("Winston eta Bunyanen Node.js Erregistratzaile sistemak konparatzen" Alex Corbatcheven eskutik, 2014ko ekainaren 24a): + +> Identifika ditzagun betebehar gutxi batzuk (erregistratzaile batentzat): +> +> 1. Denboran seilatu erregistro ilara bakoitza. Nahiko argi dago, erregistroko sarrera bakoitza noiz gertatu den esateko gai izan behar duzu +> 2. Erregistro formatua ulergarria izan behar da bai gizakientzat eta baita makinentzat ere +> 3. Korronte ezberdin ugari onartu behar ditu. Adibidez, errore erregistroak fitxategi batean idazten ari den unean errorereb bat atzemanez gero, fitxategi beraren barruan idatzi, errorearen fitxategian ere idatzi, eta posta elektronikoa bidali, dena aldi berean, egiteko aukera eman behar du + +### Non dago Winston? + +Zergatik ohiko faboritoak (adibidez, Winston) ez dauden aholkatutako jardunbide +onenen egungo zerrendan jakiteko, begiratu [#684][#684]an + +[#684]: https://github.com/goldbergyoni/nodebestpractices/issues/684 diff --git a/sections/errorhandling/usematurelogger.md b/sections/errorhandling/usematurelogger.md index 237de530..68fd3de6 100644 --- a/sections/errorhandling/usematurelogger.md +++ b/sections/errorhandling/usematurelogger.md @@ -1,50 +1,42 @@ -# Use a mature logger to increase errors visibility +# Use a mature logger to increase error visibility ### One Paragraph Explainer -We all love console.log but obviously, a reputable and persistent logger like [Winston][winston] (highly popular) or [Pino][pino] (the new kid in town which is focused on performance) is mandatory for serious projects. A set of practices and tools will help to reason about errors much quicker – (1) log frequently using different levels (debug, info, error), (2) when logging, provide contextual information as JSON objects, see example below. (3) Watch and filter logs using a log querying API (built-in in most loggers) or a log viewer software. (4) Expose and curate log statement for the operation team using operational intelligence tools like Splunk. +We love console.log but a reputable and persistent logger like [Pino][pino] (a newer option focused on performance) is mandatory for serious projects. +High-performance logging tools help identify errors and possible issues. Logging recommendations include: + +1. Log frequently using different levels (debug, info, error). +2. When logging, provide contextual information as JSON objects. +3. Monitor and filter logs with a log querying API (built-in to many loggers) or log viewer software. +4. Expose and curate log statements with operational intelligence tools such as [Splunk][splunk]. -[winston]: https://www.npmjs.com/package/winston [pino]: https://www.npmjs.com/package/pino +[splunk]: https://www.splunk.com/ -### Code Example – Winston Logger in action +### Code Example + +```JavaScript +const pino = require('pino'); -```javascript // your centralized logger object -const logger = new winston.Logger({ - level: 'info', - transports: [ - new (winston.transports.Console)() - ] -}); +const logger = pino(); // custom code somewhere using the logger -logger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' }); -``` - -### Code Example – Querying the log folder (searching for entries) - -```javascript -const options = { - from: Date.now() - 24 * 60 * 60 * 1000, - until: new Date(), - limit: 10, - start: 0, - order: 'desc', - fields: ['message'] -}; - -// Find items logged between today and yesterday. -winston.query(options, (err, results) => { - // execute callback with results -}); +logger.info({ anything: 'This is metadata' }, 'Test Log Message with some parameter %s', 'some parameter'); ``` ### Blog Quote: "Logger Requirements" - From the blog Strong Loop + From the StrongLoop blog ("Comparing Winston and Bunyan Node.js Logging" by Alex Corbatchev, Jun 24, 2014): + +> Let's identify a few requirements (for a logger): +> 1. Timestamp each log line. This one is pretty self-explanatory – you should be able to tell when each log entry occurred. +> 2. Logging format should be easily digestible by humans as well as machines. +> 3. Allows for multiple configurable destination streams. For example, you might be writing trace logs to one file but when an error is encountered, write to the same file, then into error file and send an email at the same time. + +### Where's Winston? + +For more information on why traditional favorites (e.g., Winston) may not be included in the current list of recommended best practices, please see [#684][#684]. + +[#684]: https://github.com/goldbergyoni/nodebestpractices/issues/684 -> Lets identify a few requirements (for a logger): -1. Timestamp each log line. This one is pretty self-explanatory – you should be able to tell when each log entry occurred. -2. Logging format should be easily digestible by humans as well as machines. -3. Allows for multiple configurable destination streams. For example, you might be writing trace logs to one file but when an error is encountered, write to the same file, then into error file and send an email at the same time… diff --git a/sections/errorhandling/useonlythebuiltinerror.basque.md b/sections/errorhandling/useonlythebuiltinerror.basque.md new file mode 100644 index 00000000..407c7ea6 --- /dev/null +++ b/sections/errorhandling/useonlythebuiltinerror.basque.md @@ -0,0 +1,136 @@ +# Erabili soilik “Errorea” objektu kapsulatua + +### Azalpen paragrafoa + +JavaScriptek berezko permisibitatea du, eta, bere kode fluxuaren aukera ugariarekin (adibidez EventEmitter, Callbackak, Promesak ...), garatzaileek erroreak kudeatzeko modu anitzak edukitzea eragiten du: batzuek stringak erabiltzen dituzte, besteek beren mota pertsonalizatuak zehazten dituzte. Node.jsen "Errorea" objektu kapsulatua erabiltzeak zure kodearen eta bestelako liburutegien arteko uniformetasuna gordetzen laguntzen du, eta gainera StracTracea bezalako informazio esanguratsua gordetzen du. Salbuespen bat jaurtitzean, jarraibide egokia da errorearen izena edo erlazionatutako HTTP errore kodea bezalako testuinguru ezaugarriekin osatzea. Uniformetasun eta praktika hau lortzeko, saiatu "Errorea" objektua beharrezko ezaugarriekin osatzen, baina kontu izan gehiegitan ez egiten. Orokorrean ideia ona da "Errorea" objektu kapsulatua behin bakarrik osatzea AppErrore batekin aplikazioaren maila guztietako erroreentzat, eta beharrezko duzun informazioa argumentu gisa pasatuz errore klase ezberdinak ezberdintzeko. Ez da beharrezkoa "Errorea" objektua askotan osatzea (errore kasu bakoitzerako behin, adibidez DbError, HttpError...). Begiratu ondorengo kode adibideak + +### Kode adibidea: era zuzenean egin + +```javascript +// ohizko funtzio batean Error objektua jaurti, sinkronoa dela edo asinkronoa dela (sync async) +if (!gehitzekoProduktua) + throw new Error("Nola gehi dezaket produktu bat baliorik ez duenean?"); + +// Error objektua jaurti EventEmitteretik +const myEmitter = new MyEmitter(); +nireEmitter.emit("error", new Error("whoops!")); + +// Error objektua jaurti Promesa batetik +const gehituProduktua = async (gehitzekoProduktua) => { + try { + const existitzenDenProduktua = await DAL.eskuratuProduktua( + gehitzekoProduktua.id + ); + if (existitzenDenProduktua !== null) { + throw new Error("Produktua iada existitzen da!"); + } + } catch (err) { + // ... + } +}; +``` + +### Anti jarraibidearen kode adibidea + +```javascript +// string baten jaurtiketak edozein pila informazio eta datu ezaugarri garrantzitsu falta ditu +if (!gehitzekoProduktua) + throw "Nola gehi dezaket produktu bat baliorik ez duenean?"; +``` + +### Kode adibidea: oraindik ere era zuzenagoan egin + +
+Javascript + +```javascript +// Noderen Error objektutik eratortzen den errore objektu zentralizatua +function AppErrorea(izena, httpKodea, deskribapena, funtzionatzenDu) { + Error.call(this); + Error.captureStackTrace(this); + this.izena = izena; + //...hemen zehaztuta beste ezaugarri batzuk +} + +AppErrorea.prototype = Object.create(Error.prototype); +AppErrorea.prototype.constructor = AppErrorea; + +module.exports.AppErrorea = AppErrorea; + +// erabiltzailea exzepzio bat jaurtitzen +if (erabiltzailea == null) + throw new AppErrorea( + commonErrors.resourceNotFound, + commonHTTPErrors.notFound, + "azalpen osatuagoa", + true + ); +``` + +
+ +
+Typescript + +```typescript +// Noderen Error objektutik eratortzen den errore objektu zentralizatua +export class AppErrorea extends Error { + public readonly izena: string; + public readonly httpKodea: HttpCode; + public readonly funtzionatzenDu: boolean; + + constructor( + izena: string, + httpKodea: HttpCode, + deskribapena: string, + funtzionatzenDu: boolean + ) { + super(deskribapena); + + Object.setPrototypeOf(this, new.target.prototype); // prototipo katea berrezarri + + this.izena = izena; + this.httpKodea = httpKodea; + this.funtzionatzenDu = funtzionatzenDu; + + Error.captureStackTrace(this); + } +} + +// erabiltzailea exzepzio bat jaurtitzen +if (erabiltzailea == null) + throw new AppErrorea( + commonErrors.resourceNotFound, + commonHTTPErrors.notFound, + "azalpen osatuagoa", + true + ); +``` + +
+ +_`Object.setPrototypeOf`ri buruzko azalpena Typescripten: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget_ + +### Blogeko aipua: "Ez diot interesik ikusten mota ezberdin ugari edukitzeari" + +Ben Nadel blogeko “Node.js errore objektua” 5 hitz gakori esker sailkatua + +> …”Nik neuk, ez diot interesik ikusten errore objektu klase ezberdin ugari edukitzeari [bakarra edukitzearekin alderatuz]. Ez dirudi JavaScriptek, lengoaia gisa, eraikitzailez oinarritutako errore harrapaketa hornitzen duenik. Horrela, objektu baten ezaugarriak bereizteak Eraikitzaile klaseak bereiztea baino errazagoa dirudi… + +### Blogeko aipua: "String bat ez da errore bat" + +devthought.com blogeko “Node.js errore objektua” 6 hitz gakori esker sailkatua + +> …String baten ordez errore bat pasatzeak moduluen arteko elkarreragintasuna murrizten du. instanceof errore egiaztapen arrakastatsuak izan litezken kontratuak apurtzen ditu APIekin. Ikusiko dugun bezala, errore objektuek, eraikitzaileari pasatutako mezua kontserbatzeaz gain, Javascript motore modernoetan ezaugarri interesgarriak dituzte… + +### Blogeko aipua: "Erroretik jaraunsteak ez du balio askorik gehitzen" + +machadogj blogetik hartua + +> …Errore klasea jaraunsteko erraza ez izatea arazo bat da. Noski, klasea jaraunts dezakezu eta zure HttpError, DbError, etab. bezalako Error klase propioak sortu. Hala ere, horrek denbora eskatzen du, eta ez du balio askorik gehitzen [AppError batentzat behin bakarrik jaraunsteaz alderatuz], baldin eta klaseekin zerbait egiten ez bazabiltza. Batzuetan, soilik mezu bat gehitu nahi duzu eta barruko errorea mantendu; beste batzuetan, ordea, errorea parametroekin edo bestelako informazioekin osatu nahi zenezake… + +### Blogeko aipua: "Node.jsek jaurtitako JavaScript eta System errore guztiak "Error" objektutik datoz" + +Node.js dokumentazio ofizialetik hartua + +> …Node.jsek jaurtitako JavaScript eta System errore guztiak JavaScripten "Error" klase estandarretik datoz edo "Error" objektuaren instantziak dira, eta gutxienez horrelako ezaugarri erabilgarriak hornitzea bermatzen dute. JavaScript Error objektu generiko bat da, errorea zergatik gertatu den inolako berariazko baldintzarik adierazten ez duena. Error objektuek "pila aztarna" bat atzematen dute, Error instantziatua izan den kodearen lekua zehaztuz, eta errorearen testu deskribapena eduki dezakete. Node.jsek sortutako errore guztiak, System eta JavaScript erroreak barne, Error klasetik eratorritakoak edo Error motaren instantziak izango dira… diff --git a/sections/errorhandling/useonlythebuiltinerror.korean.md b/sections/errorhandling/useonlythebuiltinerror.korean.md index f2ec0cdd..8420e4ef 100644 --- a/sections/errorhandling/useonlythebuiltinerror.korean.md +++ b/sections/errorhandling/useonlythebuiltinerror.korean.md @@ -1,10 +1,10 @@ -# Use only the built-in Error object +# 내장된 Error 객체만 사용하라 -### One Paragraph Explainer +### 한문단 설명 -The permissive nature of JS along with its variety code-flow options (e.g. EventEmitter, Callbacks, Promises, etc) pushes to great variance in how developers raise errors – some use strings, other define their own custom types. Using Node.js built-in Error object helps to keep uniformity within your code and with 3rd party libraries, it also preserves significant information like the StackTrace. When raising the exception, it’s usually a good practice to fill it with additional contextual properties like the error name and the associated HTTP error code. To achieve this uniformity and practices, consider extending the Error object with additional properties, see code example below +다양한 코드 흐름 옵션(예:EventEmitter, Callbacks, Promises 등)과 함께 JS의 허용 가능한 특성은 개발자가 오류를 발생시키는 방법에 큰 차이를 둔다. – 일부 개발자들은 문자열을 사용하고, 일부는 그들만의 커스텀 타입을 정의한다. Node.js 내장 Error 객체를 사용하면 당신의 코드와 제 3자 라이브러리의 균일성을 유지할 수 있도록 도와주며, 또한 스택정보(StrackTrace)와 같은 중요한 정보도 보존할 수 있다. 예외가 발생할 때, 일반적으로 오류 이름이나 관련 HTTP 오류 코드같은 상황별로 추가적인 속성으로 채우는 것이 좋은 방법이다. 이 균일성과 관행을 얻을려면, Error 객체를 추가 속성으로 확장하라, 아래 코드 예 참조 -### Code Example – doing it right +### 코드 예시 – 제대로 하기 ```javascript // throwing an Error from typical function, whether sync or async @@ -28,7 +28,7 @@ const addProduct = async (productToAdd) => { } ``` -### Code example – Anti Pattern +### 코드 예시 - 좋지않은 패턴 ```javascript // throwing a string lacks any stack trace information and other important data properties @@ -36,7 +36,7 @@ if(!productToAdd) throw ("How can I add new product when no value provided?"); ``` -### Code example – doing it even better +### 코드 예시 - 훨씬 더 좋다 ```javascript // centralized error object that derives from Node’s Error @@ -57,26 +57,26 @@ if(user == null) throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, "further explanation", true) ``` -### Blog Quote: "I don’t see the value in having lots of different types" +### 블로그 인용: "여러 가지 유형이 있다는 것은 가치가 없다고 본다" -From the blog, Ben Nadel ranked 5 for the keywords “Node.js error object” +Ben Nadel 블로그에서 "Node.js error 객체" 키워드 5위에 위치했다. ->…”Personally, I don’t see the value in having lots of different types of error objects – JavaScript, as a language, doesn’t seem to cater to Constructor-based error-catching. As such, differentiating on an object property seems far easier than differentiating on a Constructor type… +>…”개인적으로, 여러 가지 유형이 있다는 것은 가치가 없다고 본다 – 언어로서의 자바스크립트는 생성자 기반의 오류 파악에 적합하지 않은 것 같다. 따라서, 객체 속성에서 구별하는 것이 생성자 유형에서 구분하는 것보다 훨씬 쉬운 것 같다… -### Blog Quote: "A string is not an error" +### 블로그 인용: "문자열은 오류가 아니다" -From the blog, devthought.com ranked 6 for the keywords “Node.js error object” +devthought.com 블로그에서 "Node.js error 객체" 키워드 6위에 위치했다. -> …passing a string instead of an error results in reduced interoperability between modules. It breaks contracts with APIs that might be performing `instanceof` Error checks, or that want to know more about the error. Error objects, as we’ll see, have very interesting properties in modern JavaScript engines besides holding the message passed to the constructor… +> …오류 대신 문자열을 전달함으로써 모듈 간의 상호운용성이 줄어들었다. 문자열을 사용하면 `instanceof` 에러로 검사하는 API 계약을 깨뜨리는 데다가 오류의 자세한 정보도 알기 어렵다. 뒤에서 설명하겠지만, 최신 자바스크립트 엔진의 Error 객체에는 유용한 속성을 많이 있으며 생성자에 전달된 메시지도 포함된다… -### Blog Quote: "Inheriting from Error doesn’t add too much value" +### 블로그 인용: "에러로 부터 상속해도 많은 값을 추가하지 않는다" -From the blog machadogj +machadogj 블로그에서 -> …One problem that I have with the Error class is that is not so simple to extend. Of course, you can inherit the class and create your own Error classes like HttpError, DbError, etc. However, that takes time and doesn’t add too much value unless you are doing something with types. Sometimes, you just want to add a message and keep the inner error, and sometimes you might want to extend the error with parameters, and such… +> …Error 클래스와 관련된 한 가지 문제는 확장하기가 그리 간단하지 않다는 것이다. 물론 클래스를 상속하고 HttpError, DbError 등 자신만의 에러 클래스를 만들 수 있다. 그러나, 당신이 타입으로 무엇인가를 하지 않는 한 이것은 시간이 걸리며 많은 값을 추가하지 않는다. 때로 당신은 메시지 추가와 내부 에러를 유지하길 원하고 때로는 매개 변수를 사용하여 에러를 확장하길 원할 것이다, 등등… -### Blog Quote: "All JavaScript and System errors raised by Node.js inherit from Error" +### 블로그 인용: "모든 자바스크립트와 시스템 에러들은 node.js이 상속한 에러로 부터 발생한다" -From Node.js official documentation +Node.js 공식문서에서 -> …All JavaScript and System errors raised by Node.js inherit from, or are instances of, the standard JavaScript Error class and are guaranteed to provide at least the properties available on that class. A generic JavaScript Error object that does not denote any specific circumstance of why the error occurred. Error objects capture a “stack trace” detailing the point in the code at which the Error was instantiated, and may provide a text description of the error. All errors generated by Node.js, including all System and JavaScript errors, will either be instances of or inherit from, the Error class… +> …Node.js에 의해 발생된 모든 자바스크립트 및 시스템 에러는 표준 자바스크립트 에러 클래스에서 상속되거나 표준 자바스크립트 에러 클래스의 인스턴스이며 최소한 그 클래스에서 사용할 수 있는 속성을 제공할 수 있도록 보장된다. 에러가 발생한 이유에 대한 특정 상황을 나타내지 않는 일반 자바스크립트 에러 객체. 에러 객체는 에러가 인스턴스화된 코드에서 포인트를 자세히 설명하는 "스택 추적"을 캡처(capture)하며, 에러에 대한 텍스트 설명을 제공할 수도 있다. 모든 시스템과 자바스크립트 에러를 포함한 Node.js에 의해, 생성된 모든 에러는, 에러 클래스의 인스턴스이거나, 상속 받은 것이다.… diff --git a/sections/errorhandling/useonlythebuiltinerror.russian.md b/sections/errorhandling/useonlythebuiltinerror.russian.md index dfb32d46..4688bbcf 100644 --- a/sections/errorhandling/useonlythebuiltinerror.russian.md +++ b/sections/errorhandling/useonlythebuiltinerror.russian.md @@ -2,20 +2,20 @@ ### Объяснение в один абзац -Всепозволяющая природа JavaScript наряду с его разнообразием параметров потока кода (например, EventEmitter, Callbacks, Promises и т.д.) приводит к значительному расхождению в том, как разработчики выдают ошибки - некоторые используют строки, другие определяют свои собственные пользовательские типы. Использование встроенного объекта Error в Node.js помогает сохранить единообразие в вашем коде, а с помощью сторонних библиотек он также сохраняет важную информацию, такую ​​как StackTrace. При возникновении исключения обычно рекомендуется заполнить его дополнительными контекстными свойствами, такими как имя ошибки и связанный код ошибки HTTP. Чтобы добиться этого единообразия и практики, рассмотрите возможность расширения объекта Error дополнительными свойствами, см. пример кода ниже. +Гибкая природа JavaScript наряду с его разнообразием вариантов потока кода (например, EventEmitter, Callbacks, Promises и т.д.) приводит к значительному расхождению в том, как разработчики выдают ошибки - некоторые используют строки, другие определяют свои собственные пользовательские типы. Использование встроенного объекта Error в Node.js помогает сохранить единообразие в вашем коде, а с помощью сторонних библиотек он также сохраняет важную информацию, такую ​​как StackTrace. При возникновении исключения обычно рекомендуется заполнить его дополнительными контекстными свойствами, такими как имя ошибки и связанный код ошибки HTTP. Чтобы добиться этого единообразия и практики, рассмотрите возможность расширения объекта Error дополнительными свойствами, см. пример кода ниже. ### Пример кода - делай все правильно ```javascript -// throwing an Error from typical function, whether sync or async +// пробрасываем Error из типичной async или sync функции if(!productToAdd) throw new Error('How can I add new product when no value provided?'); -// 'throwing' an Error from EventEmitter +// пробрасываем Error из EventEmitter const myEmitter = new MyEmitter(); myEmitter.emit('error', new Error('whoops!')); -// 'throwing' an Error from a Promise +// пробрасываем Error из Promise const addProduct = async (productToAdd) => { try { const existingProduct = await DAL.getProduct(productToAdd.id); @@ -31,23 +31,23 @@ const addProduct = async (productToAdd) => { ### Пример кода - антипаттерн ```javascript -// throwing a string lacks any stack trace information and other important data properties +// пробрасывая строку, теряем информацию о stack trace и другие важные параметры if(!productToAdd) throw ('How can I add new product when no value provided?'); ``` -### Пример кода - делаем это еще лучше +### Пример кода - делаем еще лучше
Javascript ```javascript -// centralized error object that derives from Node’s Error +// главные объект ошибки производный от нодовского Error function AppError(name, httpCode, description, isOperational) { Error.call(this); Error.captureStackTrace(this); this.name = name; - //...other properties assigned here + //... другие параметры тут }; AppError.prototype = Object.create(Error.prototype); @@ -55,7 +55,7 @@ AppError.prototype.constructor = AppError; module.exports.AppError = AppError; -// client throwing an exception +// клиент пробрасывает исключение if(user == null) throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true) ``` @@ -65,7 +65,7 @@ if(user == null) Typescript ```typescript -// centralized error object that derives from Node’s Error +// главные объект ошибки производный от нодовского Error export class AppError extends Error { public readonly name: string; public readonly httpCode: HttpCode; @@ -74,7 +74,7 @@ export class AppError extends Error { constructor(name: string, httpCode: HttpCode, description: string, isOperational: boolean) { super(description); - Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain + Object.setPrototypeOf(this, new.target.prototype); // восстанавливаем цепочку прототипов this.name = name; this.httpCode = httpCode; @@ -84,7 +84,7 @@ export class AppError extends Error { } } -// client throwing an exception +// клиент пробрасывает исключение if(user == null) throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true) ``` @@ -96,22 +96,22 @@ if(user == null) Из блога Бен Надель, занял 5 место по ключевым словам "объект ошибки Node.js" -> … Лично я не вижу смысла в том, чтобы иметь множество различных типов объектов ошибок - JavaScript, как язык, похоже, не предназначен для поиска ошибок на основе конструктора. Таким образом, дифференцирование по свойству объекта кажется гораздо проще, чем по типу Constructor … +> … Лично я не вижу смысла в том, чтобы иметь множество различных типов объектов ошибок - JavaScript, как язык, похоже, не предназначен для поиска ошибок на основе конструктора. Таким образом, определение по свойству объекта кажется гораздо проще, чем по типу Constructor … ### Цитата блога: "Строка не является ошибкой" Из блога devthought.com, занял 6 место по ключевым словам "Объект ошибки Node.js" -> … передача строки вместо ошибки приводит к снижению совместимости между модулями. Он нарушает контракты с API, которые могут выполнять проверки ошибок instanceof или хотят узнать больше об ошибке. Объекты ошибок, как мы увидим, обладают очень интересными свойствами в современных механизмах JavaScript, помимо хранения сообщения, переданного конструктору … +> … передача строки вместо ошибки приводит к снижению совместимости между модулями. Это нарушает контракты с API, которые могут выполнять проверки ошибок с помощью instanceof или хотят узнать больше об ошибке. Объекты ошибок, как мы увидим, обладают очень интересными свойствами в современных механизмах JavaScript, помимо хранения сообщения, переданного конструктору … -### Цитата из блога: "Наследование от ошибки не увеличивает ценность" +### Цитата из блога: "Наследование от ошибки не увеличивает их ценность" Из блога Machadogj > … Одна проблема, которую я имею с классом Error, заключается в том, что его не так просто расширить. Конечно, вы можете наследовать класс и создавать свои собственные классы ошибок, такие как HttpError, DbError и т.д. Однако это занимает время и не добавляет слишком много значения, если вы не делаете что-то с типами. Иногда вам просто нужно добавить сообщение и сохранить внутреннюю ошибку, а иногда вам может понадобиться расширить ошибку с помощью параметров, и так далее … -### Цитата из блога: "Все ошибки JavaScript и системы, возникающие в Node.js, наследуются от ошибок" +### Цитата из блога: "Все ошибки JavaScript и системы, возникающие в Node.js, наследуются от Error" Из официальной документации Node.js -> … Все ошибки JavaScript и System, возникающие в Node.js, наследуются или являются экземплярами стандартного класса JavaScript Error и гарантированно предоставляют как минимум свойства, доступные в этом классе. Общий объект JavaScript Error, который не обозначает каких-либо конкретных обстоятельств, по которым произошла ошибка. Объекты ошибок фиксируют "трассировку стека", детализирующую точку в коде, в которой был создан экземпляр ошибки, и могут предоставлять текстовое описание ошибки. Все ошибки, сгенерированные Node.js, включая все системные ошибки и ошибки JavaScript, будут либо экземплярами класса Error, либо наследоваться от него … +> … Все ошибки JavaScript и System, возникающие в Node.js, наследуются или являются экземплярами стандартного класса JavaScript Error и гарантированно предоставляют как минимум свойства, доступные в этом классе. Общий объект JavaScript Error, который не обозначает каких-либо конкретных обстоятельств, по которым произошла ошибка. Объекты ошибок фиксируют "трассировку стека", детализирующую точку в коде, в которой был создан экземпляр ошибки, и могут предоставлять текстовое описание ошибки. Все ошибки, сгенерированные Node.js, включая все системные ошибки и ошибки JavaScript, будут либо экземплярами класса Error, либо наследоваться от него … \ No newline at end of file diff --git a/sections/performance/block-loop.md b/sections/performance/block-loop.md index 531de7fe..16d7e192 100644 --- a/sections/performance/block-loop.md +++ b/sections/performance/block-loop.md @@ -28,7 +28,7 @@ while loop. ### The results ``` -─────────┬────────┬────────┬────────┬────────┬───────────┬──────────┬───────────┐ +┌─────────┬────────┬────────┬────────┬────────┬───────────┬──────────┬───────────┐ │ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ ├─────────┼────────┼────────┼────────┼────────┼───────────┼──────────┼───────────┤ │ Latency │ 270 ms │ 300 ms │ 328 ms │ 331 ms │ 300.56 ms │ 38.55 ms │ 577.05 ms │ diff --git a/sections/projectstructre/breakintcomponents.basque.md b/sections/projectstructre/breakintcomponents.basque.md new file mode 100644 index 00000000..0b3124a4 --- /dev/null +++ b/sections/projectstructre/breakintcomponents.basque.md @@ -0,0 +1,35 @@ +# Antolatu zure proiektua atal eta osagai txikiagotan + +

+ +### Azalpen paragrafoa + +Tamaina ertaineko nahiz handiko aplikazioetarako, monolitoak benetan kaltegarriak dira. Menpekotasun asko dituen software handi bat edukitzea zaila da hausnartzeko eta maiz espageti kodea eragiten du. Arkitektu azkarrek ere, piztia mantsotzeko eta zatikatzeko haina gaitasun dituztenek, diseinuan esfortzu mental handiak egiten dituzte, eta aldaketa bakoitzak menpeko beste objektuekiko eragina arretaz aztertzea eskatzen du. Azken irtebidea software txikia garatzean datza: banandu kode pila osoa fitxategiak beste inorekin partekatzen ez dituzten aparteko osagaietan, bakoitza fitxategi gutxi batzuekin osatua egonik (APIa, zerbitzuak, datuen sarbidea, egiaztatzeak, etab.) oso erraza da hausnartzeko. Askok 'mikrozerbitzu' egitura deitzen diote horri, garrantzitsua da ulertzea mikrozerbitzuak oinarri sorta bat direla eta ez derrigorrez jarraitu beharreko zehaztapenak. Printzipio ugari erabil ditzakezu mikrozerbitzudun egitura handi batean edota gutxi batzuk soilik. Biak dira zuzenak zure softwarearen konplexutasuna baxua den bitartean. Gutxienez, egin zenezakeen beste zerbait da osagaien artean oinarrizko mugak sortzea, zure proiektuaren erroan karpeta bat egokitzea osagai logiko bakoitzarentzat eta autonono bihurtzea: beste osagaiek haren funtzionalitatea erabili ahal izango dute soilik bere interfaze publikotik edo APItik pasatuz. Hau oinarrizkoa da zure osagaiak sinpleak izateko, menpekotasunen korapiloa ekiditeko eta zure aplikazioa mikrozerbitzu egitura handietarako prestatzeko. +

+ +### Blogeko aipua: "Eskalatzeak aplikazio osoaren eskalatzea eskatzen du" + +MartinFowler.com blogetik hartua + +> Aplikazio monolitikoak arrakastatsuak izan daitezke, baina jendeak gero eta frustrazio gehiago ditu beraiekin, batez ere gero eta aplikazio gehiago inplementatzen direlako lainoan. Aldaketa zikloak elkarrekin lotuta daude: aplikazioaren zati txiki batean egindako aldaketak monolito osoa bersortzea eta inplementatzea eskatzen du. Askotan zaila da denbora aurrera joan ahala moduluzko egitura egokia mantentzea, modulu batean bakarrik eragina izango dituzten aldaketak mantentzea. Eskalatzeak aplikazio osoaren eskalatzea eskatzen du +

+ +### Blogeko aipua: "Zergatik egiten du garrasi zure aplikazioaren egiturak?" + +[uncle-bob](https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html) blogetik hartua + +> ...Liburutegi baten egitura begiratuko bazenu, ziurrenik sarrera handi batekin aurkituko zinateke, erregistro bulego lekuekin, irakurketa lekuekin, biltzar toki txikiekin, eta liburutegiko liburu guztiak edukitzeko beste apal dituzten galeria ugarirekin. Egitura horrek honakoa oihukatu beharko luke: Liburutegia.
+ +Beraz, zer oihukatzen du zure aplikazioaren egiturak? Zure direktorioko egituraren maila altuena eta maila altueneko paketeko iturburu fitxategiak begiratzen dituzunean, zer oihukatzen dute: Osasun Sistema, Kontabilitate Sistema edo Inbentarioa Kudeatzeko Sistema? Edo zera oihukatzen al dute: Rails, Spring/Hibernate edo ASP? + +

+ +### Zuzena: antolatu zure proiektua aparteko osagaietan + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Antolatu proiektua osagaietan") + +

+ +### Okerra: taldekatu zure fitxategiak rol teknikoen arabera + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebyroles.PNG "Antolatu proiektua rol teknikoen arabera") diff --git a/sections/projectstructre/configguide.basque.md b/sections/projectstructre/configguide.basque.md new file mode 100644 index 00000000..086bd2b7 --- /dev/null +++ b/sections/projectstructre/configguide.basque.md @@ -0,0 +1,43 @@ +# Erabili ingurunea errespetatzen duen konfigurazio seguru eta hierarkiko bat + +

+ +### Azalpen paragrafoa + +Konfigurazio datuekin jardutean, hainbat gauza gogaikarri eta moteltzaile aurki genitzake: + +1. prozesuaren inguruneko aldagaiak erabiliz giltza guztiak ezartzea benetan gogaikarria bihurtzen da 100 giltza injektatu behar ditugunean (haiek soilik konfigurazio fitxategi batean argitaratu partez), hala ere, fitxategiekin jardutean, soilik DevOps administrariak dira gai jokaera aldatzeko, kodea aldatu gabe. Konfigurazio sistema fidagarri batek konfigurazio fitxategiak eta prozesu aldagaien berridazketa konbinatu beharko lituzke + +2. giltza guztiak JSON batean zehaztean, balioak aurkitu eta aldatzea frustragarria da zerrenda handitzen doan heinean. Ataletan antolatuta dagoen JSON fitxategi hierarkiko batek arazo hau konpondu dezake. Gainera, konfigurazio liburutegi gutxi batzuek konfigurazioa hainbat fitxategitan gordetzea ahalbidetzen dute eta guztiak exekuzio garaian bateratzea. Begiratu beheko adibidea + +3. jakina da ez dela gomendagarria datu baseko pasahitza bezalako informazio garrantzitsua gordetzea, baina ez da irtenbide azkar eta praktikorik existitze erronka honetarako. Konfigurazio liburutegi batzuek fitxategiak enkriptatzeko aukera ematen dute, beste batzuek GIT argitarapen prozesuen bitartean enkriptatzen dituzte balio horiek edota ez dituzte balio errealak gordetzen, baizik eta ingurune aldagaien bidez zehazten dituzte inplementazio prozesuaren bitartean + +4. konfigurazio egoera aurreratu batzuek konfigurazio giltzak komando sarrera bidez (vargs) injektatzea eskatzen dute, edota konfigurazio informazioa sinkronizatzea Redis bezalako cache memoria erabiliz, zerbitzari ugarik konfigurazio datu berak erabiltzea ahalbidetuz + +5. aplikazioak ahalik eta azkarren huts egin behar du eta berehalako erantzuna eman aplikazioaren abiaraztean, beharrezko ingurune aldagaiak zehaztuta ez badaude. Konfigurazioa balioztatzeko [convict](https://www.npmjs.com/package/convict) erabiliz lor daiteke hori + +Konfigurazio liburutegi batzuek aipatutako funtzionalitate gehienak dohainik eskaintzen dituzte. Eman begirada bat [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config), eta [convict](https://www.npmjs.com/package/convict) bezalako npm liburutegiei, non aipatutako ezaugarri gehienak betetzen dituzten + +

+ +### Kode adibidea: konfigurazio hierarkikoak balioak aurkitzen eta konfigurazio fitxategi handiak mantentzen laguntzen du + +```json5 +{ + // Bezeroen konfigurazio modulua + Bezeroa: { + dbConfig: { + host: "localhost", + port: 5984, + dbName: "bezeroak", + }, + credit: { + initialLimit: 100, + // Set low for development + initialDays: 1, + }, + }, +} +``` + +

diff --git a/sections/projectstructre/createlayers.basque.md b/sections/projectstructre/createlayers.basque.md new file mode 100644 index 00000000..c8f5aa63 --- /dev/null +++ b/sections/projectstructre/createlayers.basque.md @@ -0,0 +1,13 @@ +# Antolatu zure aplikazioa geruzatan, mantendu Express bere esparruaren barruan + +

+ +### Osagaien kodea geruzatan banandu: web, zerbitzuak, eta Datuen Sarbide Geruza (DSG) (Ingelesez Data Access Layer, DAL) + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Osagaien kodea geruzatan banandu") + +

+ +### Minutu bateko azalpena: geruzak nahastearen eragozpena + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/keepexpressinweb.gif "Geruzak nahastearen eragozpena") diff --git a/sections/projectstructre/createlayers.md b/sections/projectstructre/createlayers.md index f6f860c1..802452b2 100644 --- a/sections/projectstructre/createlayers.md +++ b/sections/projectstructre/createlayers.md @@ -2,7 +2,7 @@

- ### Separate component code into layers: web, services, and DAL + ### Separate component code into layers: web, services, and Data Access Layer (DAL) ![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/structurebycomponents.PNG "Separate component code into layers") diff --git a/sections/projectstructre/createlayers.russian.md b/sections/projectstructre/createlayers.russian.md index 7579e046..00d5e69b 100644 --- a/sections/projectstructre/createlayers.russian.md +++ b/sections/projectstructre/createlayers.russian.md @@ -1,4 +1,4 @@ -# Выделяйте ваши компоненты в отдельный слой, держите Express в его граница +# Выделяйте ваши компоненты в отдельный слой, держите Express в его границах

diff --git a/sections/projectstructre/separateexpress.basque.md b/sections/projectstructre/separateexpress.basque.md new file mode 100644 index 00000000..ed404e84 --- /dev/null +++ b/sections/projectstructre/separateexpress.basque.md @@ -0,0 +1,102 @@ +# Banandu Express 'aplikazioa' eta 'zerbitzaria' + +

+ +### Azalpen paragrafoa + +Azken Express sorgailuak mantentzea merezi duen sekulako jardunbide bikain bat du. Izan ere, APIaren deklarazioa sarearekin erlazionatutako ezarpenetatik (portua, protokoloa, etab.) banandua dago. Horrek APIa prozesua martxan den bitartean egiaztatzea ahalbidetzen du, sare deirik egin gabe eta horrek dakartzan onura guztiekin: egiaztatze azkarren exekuzioa eta estalduraren metrikak eskuratzea. API bera sare baldintza malgu eta ezberdinetan inplementatzea ere ahalbidetzen du. Gehigarria: arduren bereizte hobea eta kode garbiagoa + +

+ +### Kode adibidea: APIaren deklarazioak app.js/app.ts-en barruan egon beharko luke + +```javascript +const app = express(); +app.use(bodyParser.json()); +app.use("/api/events", events.API); +app.use("/api/forms", forms); +``` + +### Kode adibidea: zerbitzari sarearen deklarazioak /bin/www-en barruan egon beharko luke + +
+Javascript + +```javascript +const app = require("../app"); +const http = require("http"); + +// Ingurunearen portua eskuratu eta Expressen gorde. +const port = normalizePort(process.env.PORT || "3000"); +app.set("port", port); + +// Sortu HTTP zerbitzaria. +const server = http.createServer(app); +``` + +
+ +
+Typescript + +```typescript +import app from "../app"; +import http from "http"; + +// Ingurunearen portua eskuratu eta Expressen gorde. +const port = normalizePort(process.env.PORT || "3000"); +app.set("port", port); + +// Sortu HTTP zerbitzaria. +const server = http.createServer(app); +``` + +
+ +### Kode adibidea: zure APIa prozesua martxan den bitartean probatu supertest (frogentzako pakete ospetsua) erabiliz + +
+Javascript + +```javascript +const request = require("supertest"); +const app = express(); + +app.get("/user", (req, res) => { + res.status(200).json({ name: "tobi" }); +}); + +request(app) + .get("/user") + .expect("Content-Type", /json/) + .expect("Content-Length", "15") + .expect(200) + .end((err, res) => { + if (err) throw err; + }); +``` + +
+ +
+Typescript + +```typescript +import * as request from "supertest"; +const app = express(); + +app.get("/user", (req: Request, res: Response) => { + res.status(200).json({ name: "tobi" }); +}); + +request(app) + .get("/user") + .expect("Content-Type", /json/) + .expect("Content-Length", "15") + .expect(200) + .end((err: Error) => { + if (err) throw err; + }); +``` + +
diff --git a/sections/projectstructre/wraputilities.basque.md b/sections/projectstructre/wraputilities.basque.md new file mode 100644 index 00000000..7a225073 --- /dev/null +++ b/sections/projectstructre/wraputilities.basque.md @@ -0,0 +1,16 @@ +# Antolatu baliabide komunak npm paketetan + +

+ +### Azalpen paragrafoa + +Hazten hasi eta zerbitzari ezberdinetan antzeko baliabideak erabiltzen dituzten gero eta osagai ezberdin gehiago dituzun heinean, menpekotasunak kudeatzen hasi beharko zenuke. Nola gorde zenezake zure baliabidearen iturburu kodearen kopia bat eta beste osagaiei hura erabiltzen eta inplementatzen utzi? Bada, npm izeneko tresna bat badago horretarako... Hasi baliabide paketeetan zure kodea jartzen, etorkizunean kodearen ordezkapena errazteko eta argitaratu zure kode propioa npm pakete pribatu gisa. Horrela, zure kodeak beste kode hori inportatu ahal izango du, debaldeko menpekotasun kudeaketa tresnari esker. Posible da zure erabilera pribaturako npm paketeak argitaratzea,haiek publikoki partekatu gabe, [modulu pribatuak](https://docs.npmjs.com/private-modules/intro), [erregistro pribatua](https://npme.npmjs.com/docs/tutorials/npm-enterprise-with-nexus.html) edo [npm pakete lokalak](https://medium.com/@arnaudrinquin/build-modular-application-with-npm-local-modules-dfc5ff047bcc) erabiliz + + +

+ + + +### Partekatu zure baliabide propioak ingurune eta osagaietan + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/Privatenpm.png "Antolatu proiektua osagaietan") diff --git a/sections/security/bcryptpasswords.md b/sections/security/bcryptpasswords.md deleted file mode 100644 index 03a73a3c..00000000 --- a/sections/security/bcryptpasswords.md +++ /dev/null @@ -1,32 +0,0 @@ -# Avoid using the Node.js Crypto library for passwords, use Bcrypt - -### One Paragraph Explainer - -When storing user passwords, using an adaptive hashing algorithm such as bcrypt, offered by the [bcrypt npm module](https://www.npmjs.com/package/bcrypt) is recommended as opposed to using the native Node.js crypto module. `Math.random()` should also never be used as part of any password or token generation due to its predictability. - -The `bcrypt` module or similar should be used as opposed to the JavaScript implementation, as when using `bcrypt`, a number of 'rounds' can be specified in order to provide a secure hash. This sets the work factor or the number of 'rounds' the data is processed for, and more hashing rounds leads to more secure hash (although this at the cost of CPU time). The introduction of hashing rounds means that the brute force factor is significantly reduced, as password crackers are slowed down increasing the time required to generate one attempt. - -### Code example - -```javascript -try { -// asynchronously generate a secure password using 10 hashing rounds - const hash = await bcrypt.hash('myPassword', 10); - // Store secure hash in user record - - // compare a provided password input with saved hash - const match = await bcrypt.compare('somePassword', hash); - if (match) { - // Passwords match - } else { - // Passwords don't match - } -} catch { - logger.error('could not hash password.') -} -``` - -### What other bloggers say - -From the blog by [Max McCarty](https://dzone.com/articles/nodejs-and-password-storage-with-bcrypt): -> ... it’s not just using the right hashing algorithm. I’ve talked extensively about how the right tool also includes the necessary ingredient of “time” as part of the password hashing algorithm and what it means for the attacker who’s trying to crack passwords through brute-force. diff --git a/sections/security/commonsecuritybestpractices.brazilian-portuguese.md b/sections/security/commonsecuritybestpractices.brazilian-portuguese.md index 3bd0c692..764e3481 100644 --- a/sections/security/commonsecuritybestpractices.brazilian-portuguese.md +++ b/sections/security/commonsecuritybestpractices.brazilian-portuguese.md @@ -24,7 +24,7 @@ A seção de boas práticas comuns de segurança contém as práticas recomendad ## ![✔] Gerando strings aleatórias usando Node.js -**TL;DR:** Usar uma função personalizada que gera sequências pseudo-aleatórias para tokens e outros casos de uso sensíveis à segurança pode não ser tão aleatório quanto você pensa, tornando seu aplicativo vulnerável a ataques criptográficos. Quando você precisar gerar strings aleatórias seguras, use a função [`crypto.RandomBytes(size, [callback])`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_randombytes_size_callback) usando a entropia disponível fornecida pelo sistema. +**TL;DR:** Usar uma função personalizada que gera sequências pseudo-aleatórias para tokens e outros casos de uso sensíveis à segurança pode não ser tão aleatório quanto você pensa, tornando seu aplicativo vulnerável a ataques criptográficos. Quando você precisar gerar strings aleatórias seguras, use a função [`crypto.randomBytes(size, [callback])`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) usando a entropia disponível fornecida pelo sistema. **Caso contrário:** Ao gerar strings pseudo-aleatórias sem métodos criptograficamente seguros, os invasores podem prever e reproduzir os resultados gerados, tornando seu aplicativo inseguro. diff --git a/sections/security/commonsecuritybestpractices.md b/sections/security/commonsecuritybestpractices.md index 0e2e6f55..1ba97c5f 100644 --- a/sections/security/commonsecuritybestpractices.md +++ b/sections/security/commonsecuritybestpractices.md @@ -24,7 +24,7 @@ The common security guidelines section contains best practices that are standard ## ![✔] Generating random strings using Node.js -**TL;DR:** Using a custom-built function generating pseudo-random strings for tokens and other security-sensitive use cases might actually not be as random as you think, rendering your application vulnerable to cryptographic attacks. When you have to generate secure random strings, use the [`crypto.RandomBytes(size, [callback])`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_randombytes_size_callback) function using available entropy provided by the system. +**TL;DR:** Using a custom-built function generating pseudo-random strings for tokens and other security-sensitive use cases might actually not be as random as you think, rendering your application vulnerable to cryptographic attacks. When you have to generate secure random strings, use the [`crypto.randomBytes(size, [callback])`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) function using available entropy provided by the system. **Otherwise:** When generating pseudo-random strings without cryptographically secure methods, attackers might predict and reproduce the generated results, rendering your application insecure @@ -99,14 +99,10 @@ Going on, below we've listed some important bits of advice from the OWASP projec - Personally identifiable information (PII) is any data that can be used to identify a specific individual - Protect Personally Identifyable Information in the Applications by encrypting them -- Follow the data privacy laws of the land - - -- Reference laws: - -- European Union: GDPR - https://ec.europa.eu/info/law/law-topic/data-protection_en -- India: https://meity.gov.in/writereaddata/files/Personal_Data_Protection_Bill,2018.pdf -- Singapore: https://www.pdpc.gov.sg/Legislation-and-Guidelines/Personal-Data-Protection-Act-Overview +- Follow the data privacy laws of the land. Reference laws: + - European Union: GDPR - https://ec.europa.eu/info/law/law-topic/data-protection_en + - India: https://meity.gov.in/writereaddata/files/Personal_Data_Protection_Bill,2018.pdf + - Singapore: https://www.pdpc.gov.sg/Legislation-and-Guidelines/Personal-Data-Protection-Act-Overview ## ![✔] Have a security.txt File [PRODUCTION] diff --git a/sections/security/commonsecuritybestpractices.polish.md b/sections/security/commonsecuritybestpractices.polish.md index ab6b7304..5bc707f7 100644 --- a/sections/security/commonsecuritybestpractices.polish.md +++ b/sections/security/commonsecuritybestpractices.polish.md @@ -24,7 +24,7 @@ Sekcja wspólnych wskazówek bezpieczeństwa zawiera najlepsze praktyki, które ## ![✔] Generowanie losowych ciągów za pomocą Node.js -**TL;DR:** Korzystanie z niestandardowej funkcji generującej pseudolosowe ciągi znaków dla tokenów i innych wrażliwych na bezpieczeństwo przypadków użycia może nie być tak losowe, jak myślisz, co może narazić Twoją aplikację na ataki kryptograficzne. Gdy musisz wygenerować bezpieczne losowe ciągi, użyj [`crypto.RandomBytes(size,[callback])`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html# crypto_crypto_randombytes_size_callback) przy użyciu dostępnej entropii dostarczonej przez system. +**TL;DR:** Korzystanie z niestandardowej funkcji generującej pseudolosowe ciągi znaków dla tokenów i innych wrażliwych na bezpieczeństwo przypadków użycia może nie być tak losowe, jak myślisz, co może narazić Twoją aplikację na ataki kryptograficzne. Gdy musisz wygenerować bezpieczne losowe ciągi, użyj [`crypto.randomBytes(size,[callback])`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) przy użyciu dostępnej entropii dostarczonej przez system. **W przeciwnym razie:** Podczas generowania pseudolosowych ciągów bez metod kryptograficznych osoby atakujące mogą przewidywać i odtwarzać wygenerowane wyniki, co powoduje, że aplikacja nie jest bezpieczna diff --git a/sections/security/commonsecuritybestpractices.russian.md b/sections/security/commonsecuritybestpractices.russian.md index f62035c5..a69db38f 100644 --- a/sections/security/commonsecuritybestpractices.russian.md +++ b/sections/security/commonsecuritybestpractices.russian.md @@ -24,7 +24,7 @@ ## ![✔] Генерация случайных строк с использованием Node.js -**TL;DR:** Использование специально созданной функции, генерирующей псевдослучайные строки для токенов и других чувствительных к безопасности случаев использования, на самом деле может быть не таким случайным, как вы думаете, что делает ваше приложение уязвимым для криптографических атак. Когда вам нужно создать безопасные случайные строки, используйте [`crypto.RandomBytes(size, [callback])`](https://nodejs.org/dist/latest-v9.x/docs/api/crypto.html#crypto_crypto_randombytes_size_callback), используя доступную энтропию, предоставляемую системой. +**TL;DR:** Использование специально созданной функции, генерирующей псевдослучайные строки для токенов и других чувствительных к безопасности случаев использования, на самом деле может быть не таким случайным, как вы думаете, что делает ваше приложение уязвимым для криптографических атак. Когда вам нужно создать безопасные случайные строки, используйте [`crypto.randomBytes(size, [callback])`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback), используя доступную энтропию, предоставляемую системой. **Иначе:** При создании псевдослучайных строк без криптографически безопасных методов злоумышленники могут прогнозировать и воспроизводить сгенерированные результаты, делая ваше приложение небезопасным diff --git a/sections/security/dependencysecurity.md b/sections/security/dependencysecurity.md index 33d52ad9..1108409c 100644 --- a/sections/security/dependencysecurity.md +++ b/sections/security/dependencysecurity.md @@ -11,6 +11,7 @@ There is a number of tools available to help identify third-party packages in No - [NPM audit](#npm-audit) - [Snyk](#snyk) - [Greenkeeper](#greenkeeper) +- [Additional Resources](#additional-resources) ### NPM Audit @@ -28,8 +29,8 @@ Snyk offers a feature-rich CLI, as well as GitHub integration. Snyk goes further Snyk's feature rich website also allows for ad-hoc assessment of dependencies when provided with a GitHub repository or npm module url. You can also search for npm packages which have vulnerabilities directly. -An example of the output of the Synk GitHub integration automatically created pull request: -![synk GitHub example](/assets/images/snyk.png) +An example of the output of the Snyk GitHub integration automatically created pull request: +![snyk GitHub example](/assets/images/snyk.png) 🔗 [Read on: Snyk website](https://snyk.io/) diff --git a/sections/security/regex.md b/sections/security/regex.md index 36fe5faf..0d03e8da 100644 --- a/sections/security/regex.md +++ b/sections/security/regex.md @@ -11,7 +11,7 @@ Some [OWASP examples](https://www.owasp.org/index.php/Regular_expression_Denial_

-### Code Example – Enabling SSL/TLS using the Express framework +### Code Example – Validating exponential time RegEx and using validators instead of RegEx ```javascript const saferegex = require('safe-regex'); diff --git a/sections/security/saferedirects.chinese.md b/sections/security/saferedirects.chinese.md new file mode 100644 index 00000000..5dd68766 --- /dev/null +++ b/sections/security/saferedirects.chinese.md @@ -0,0 +1,59 @@ +# 避免不安全的重定向 + +### 一段解释 + +当我们在 Node.js 或者 Express 中实现重定向时,在服务器端进行输入校验非常重要。当攻击者发现你没有校验用户提供的外部输入时,他们会在论坛、社交媒体以和其他公共场合发布他们精心制作的链接来诱使用户点击,以此达到漏洞利用的目的。 + +案例: express 使用用户输入的不安全的重定向 + +```javascript +const express = require('express'); +const app = express(); + +app.get('/login', (req, res, next) => { + + if (req.session.isAuthenticated()) { + res.redirect(req.query.url); + } + +}); +``` + +建议的避免不安全重定向的方案是,避免依赖用户输入的内容来进行重定向。如果一定要使用用户输入的内容,可以通过使用白名单重定向的方式来避免暴露漏洞。 + +案例:使用白名单实现安全的重定向 + +```javascript +const whitelist = { + 'https://google.com': 1 +}; + +function getValidRedirect(url) { + // 检查url是否以/开头 + if (url.match(/^\/(?!\/)/)) { + // 前置我们的域名来确保(安全) + return 'https://example.com' + url; + } + + // 否则对照白名单列表 + return whitelist[url] ? url : '/'; +} + +app.get('/login', (req, res, next) => { + + if (req.session.isAuthenticated()) { + res.redirect(getValidRedirect(req.query.url)); + } + +}); +``` + +### 其他博主的看法 + +来自博客[NodeSwat](https://blog.nodeswat.com/unvalidated-redirects-b0a2885720db): + +> 幸运的是,缓解此漏洞的方法非常简单-不要使用未经验证的用户输入作为重定向的基础。 + +来自博客[Hailstone](https://blog.hailstone.io/how-to-prevent-unsafe-redirects-in-node-js/): + +> 但是,如果服务器端的重定向逻辑没有对url参数的数据进行校验的话,则你的用户可能最终访问的地址跟你的地址看起来几乎完全一致(examp1e.com),但这最终满足了犯罪黑客们的需求。 diff --git a/sections/security/secureheaders.md b/sections/security/secureheaders.md index 8edf4b66..9e9aca5e 100644 --- a/sections/security/secureheaders.md +++ b/sections/security/secureheaders.md @@ -5,7 +5,7 @@ ### One Paragraph Explainer -There are security-related headers used to secure your application further. The most important headers are listed below. You can also visit the sites linked at the bottom of this page to get more information on this topic. You can easily set these headers using the [Helmet](https://www.npmjs.com/package/helmet) module for express ([Helmet for koa](https://www.npmjs.com/package/koa-helmet)). +There are security-related headers used to secure your application further. The most important headers are listed below. You can also visit the sites linked at the bottom of this page to get more information on this topic. You can easily set these headers using the [Helmet](https://www.npmjs.com/package/helmet) module for Express ([Helmet for koa](https://www.npmjs.com/package/koa-helmet)).

@@ -18,7 +18,7 @@ There are security-related headers used to secure your application further. The - [Referrer-Policy](#referrer-policy) - [Expect-CT](#expect-ct) - [Content-Security-Policy](#content-security-policy) -- [Additional Resource](#additional-resources) +- [Additional Resources](#additional-resources)

diff --git a/sections/security/userpasswords.md b/sections/security/userpasswords.md new file mode 100644 index 00000000..350965cb --- /dev/null +++ b/sections/security/userpasswords.md @@ -0,0 +1,130 @@ +# Secure Your Users' Passwords + +### One Paragraph Explainer + +**Always** hash users' passwords as opposed to storing them as text; there are three options that depend on your use case for hashing user passwords. All the below functions need to be implemented properly to provide any security. (Reference the minimums or see the [IETF's recommendations](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations) for what parameters to use for each) You should use the recommended properties as a minimum, using higher parameters and a combination that's unique to your program can help mitigate some of the damage if someone ever runs off with your password hashes. Also, always add a [salt](https://auth0.com/blog/adding-salt-to-hashing-a-better-way-to-store-passwords/) (reproducible data, unique to the user and your system) to your passwords before you hash. + + - For the majority of use cases, the popular library [`bcrypt`](https://www.npmjs.com/package/bcrypt) can be used. (minimum: `cost:12`, password lengths must be <64) + - For a slightly harder native solution, or for unlimited size passwords, use the [`scrypt`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_scrypt_password_salt_keylen_options_callback) function. (minimums: `N:32768, r:8, p:1`) + - For FIPS/Government compliance use the older [`PBKDF2`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_digest_callback) function included in the native crypto module. (minimums: `iterations: 10000, length:{salt: 16, password: 32}`) + +(NOTE: `Math.random()` should **never** be used as part of any password or token generation due to its predictability. See [the advanced section](#randomness) for more info) + +### Code example - Bcrypt + +```javascript +const iterations = 12; +try { +// asynchronously generate a secure password + const hash = await bcrypt.hash('myPassword', iterations); + // Store secure hash in user record + + // compare a provided password input with saved hash + const match = await bcrypt.compare('somePassword', hash); + if (match) { + // Passwords match + } else { + // Passwords don't match + } +} catch { + logger.error('could not hash password.') +} +``` + +### Code example - SCrypt + +```javascript + const outSize = 64; + const hash = crypto.scryptSync('myUnlimitedPassword','someUniqueUserValueForSalt',outSize).toString('hex'); + + // Store secure hash in user record + + // compare a provided password input with saved hash + const match = hash === crypto.scryptSync('someUnlimitedPassword','derivedSalt',outSize).toString('hex'); + + if (match) { + // Passwords match + } else { + // Passwords don't match + } +``` + +### Code example - PBKDF2 (Password-Based Key Derivation Function, Crypto Spec v2.1) + +```javascript +try { + const outSize = 64; + const digest = 'blake2b512'; + const iterations = 12; + const hash = crypto.pbkdf2Sync('myPassword','someUniqueUserValueForSalt', iterations * 1000, digest, outSize).toString('hex'); + + // Store secure hash in user record + + // compare a provided password input with saved hash + const match = hash === crypto.pbkdf2Sync('somePassword','derivedSalt', iterations * 1000, digest, outSize).toString('hex'); + + if (match) { + // Passwords match + } else { + // Passwords don't match + } +} catch { + logger.error('could not hash password.') +} +``` + +### What other bloggers say + +From the blog by [Max McCarty](https://dzone.com/articles/nodejs-and-password-storage-with-bcrypt): +> ... it’s not just using the right hashing algorithm. I’ve talked extensively about how the right tool also includes the necessary ingredient of “time” as part of the password hashing algorithm and what it means for the attacker who’s trying to crack passwords through brute-force. + +From the blog [Troy Hunt - Creator of HaveIBeenPwned.com](https://www.troyhunt.com/we-didnt-encrypt-your-password-we-hashed-it-heres-what-that-means/): +> Saying that passwords are “encrypted” over and over again doesn’t make it so. They’re bcrypt hashes so good job there, but the fact they’re suggesting everyone changes their password illustrates that even good hashing has its risks. + +### Advanced & References + +#### Algorithms + +When storing user passwords, there are a few options to consider based on what the priority is. + +All of the below algorithms/functions need to be implemented properly to provide any security. Please see the [IETF's recommendations](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations) for what parameters to use for each. You should use the recommended properties as a minimum, using higher parameters and a combination that's unique to your program can differentiate the hash of the exact same password and salt from someone elses implementation to yours, mitigating some of the risk if someone ever runs off with your password hashes. + +The external dependency, [`bcrypt`](https://www.npmjs.com/package/bcrypt) is the most widely supported and should be used when possible, as when using `bcrypt`, a number of 'rounds' can be specified in order to provide a secure hash. This sets the work factor or the number of 'rounds' the data is processed for, and more hashing rounds leads to more secure hash (although this at the cost of CPU time). The introduction of hashing rounds means that the brute force factor is significantly reduced, as password crackers are slowed down increasing the time required to generate one attempt. + +The [`scrypt`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_scrypt_password_salt_keylen_options_callback) function included in the native crypto module can be used as it is a slight improvement over `bcrypt`, allowing for unlimited length passwords, and does not add a dependency, though it needs more configuration and is newer and thus less scrutinized. `scrypt` uses cost (to increase CPU/memory cost), blockSize (to increase memory cost), and parallelization (to increase the cost of breaking it up into separate operations) together to define how secure it is, how long it will take, and what it's most secure against. + +If FIPS or other compliance is absolutely necessary, the older [`PBKDF2`](https://nodejs.org/dist/latest-v14.x/docs/api/crypto.html#crypto_crypto_pbkdf2_password_salt_iterations_keylen_digest_callback) function included in the native crypto module should be used. `PBKDF2` has a similar api to `bcrypt` in that it uses an iteration count to define the strength and time to spend. + +On track to be added sometime in 2021 (Through addition to OpenSSL) the `Argon2` function is the winner of the [Password Hashing Competition](https://password-hashing.net/) and top recommended by [OWASP](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Password_Storage_Cheat_Sheet.md#modern-algorithms) and the [IETF](https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html#name-kdf-recommendations). Once added to the native crypto module, `Argon2` should be stable and take precedence. + +#### Salting + +No matter what the algorithm/function, always include some string that's unique to your system and the specific user. Some examples might be a combination of username/userID and your app name or the user's email and your business email. However this should also be considered when choosing your hashing algorithm/function since BCrypt limits you to 64 characters, whereas the more complicated SCrypt lets you use as much salt and password as you want. + +##### Why use salt? + +Adding salt changes the hash and thus makes it different from a hash of the same password in someone elses +system. If someone uses the same password for multiple sites, and a hash of their password is obtained from someone elses data breach, they won't be able to match it to the hash in your database. When everyone uses hashes, it becomes nearly impossible for attackers to identify patterns of password reuse. + +#### Password Length + +If your password plus salt has to come in under a limit, and if you use good salt, your users passwords will be even more limited. One way around this, which can be also be good generally, is to pre-hash the passwords. It can create administrative burden, but if you can commit to consistently using a single, simple, hash on the font-end you can set the pre-hash to generate hex strings of an exact length from the password before transmitting it to your server. This means you can have strong checks on your API; for example, only allowing hex characters of exactly 256 characters in length, but still giving users the ability to use passwords of any length with any characters. (You still need to use a good enough hashing that you don't accidentally create collisions where two different passwords create the same hash, it doesn't hurt to use more secure hashing for this, it just takes longer) + +Example Browser code would be `const hash = crypto.subtle.digest('sha-256', password)`; + +#### Randomness + +Whenever possible, leave the generation of randomness to the algorithms you choose. Notice, no mention of an alternative to `Math.random()` was provided, that's because you should even avoid using `crypto.random()` yourself, as *Randomness* is a special kind of limited resource on a computer, and abusing it can cause problems for your program and even other programs on the machine. + +#### How BCrypt/SCrypt Work + +Both BCrypt/SCrypt use iterations since their premise is that if it takes you X amount of time and resources to hash once, and the attacker X^some-big-number to break the hash with brute force, then if you hash the hash of a hash etc. then you're greatly increasing the magnitude of resources an attacker would have to expend to break your hash. SCrypt also has parameters for block/chunk size and parallelism to try and add "hardness" for attackers that try to assume they only need a certain amount of RAM or CPU cores, though the effectiveness of these parameters is hotly debated. + +#### References + + - IETF - Password Storage Reccomendations: https://tools.ietf.org/id/draft-whited-kitten-password-storage-00.html + - OWASP - Password Storage CheatSheet: https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Password_Storage_Cheat_Sheet.md + - auth0 - What is Password Salt: https://auth0.com/blog/adding-salt-to-hashing-a-better-way-to-store-passwords/ + - Troy Hunt - What's the difference between Hashing and Encryption: https://www.troyhunt.com/we-didnt-encrypt-your-password-we-hashed-it-heres-what-that-means/ + - Password Hashing Competition: https://password-hashing.net/ + diff --git a/sections/template.basque.md b/sections/template.basque.md new file mode 100644 index 00000000..2f8e0be7 --- /dev/null +++ b/sections/template.basque.md @@ -0,0 +1,47 @@ +# Izenburua hemen + +

+ +### Azalpen paragrafo bat + +Testua + +

+ +### Kode Adibidea: azalpena + +```javascript +kodea hemen +``` + +

+ +### Kode Adibidea: beste azalpen bat + +```javascript +kodea hemen +``` + +

+ +### Blogeko aipua: "Izenburua" + +Blogean, pouchdb.comek “Node Promesak hitz gakoarentzat 11.posizioa du + +> …testua hemen + +

+ +### Adibidea: CodeClimaterekin funtzio konplexuen analisia (iragarkia) + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-complex-methods.PNG "Funtzio konplexuen analisia") + +### Adibidea: CodeClimaterekin kode analisi joerak eta historia (iragarkia) + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-history.PNG "Kode analisiaren historia") + +### Adibidea: SonarQuberekin kode analisiaren laburpena eta joerak (iragarkia) + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-sonarqube-dashboard.PNG "Kode analisiaren historia") + +

diff --git a/sections/testingandquality/3-parts-in-name.basque.md b/sections/testingandquality/3-parts-in-name.basque.md new file mode 100644 index 00000000..110394f8 --- /dev/null +++ b/sections/testingandquality/3-parts-in-name.basque.md @@ -0,0 +1,55 @@ +# Erabili 3 zati proba izen bakoitzean + +

+ +### Azalpen Paragrafoa + +Proben txostenak esan behar du aplikazioaren berrikuspenak erantzuten dien kodea nahitaez ezagutzen ez duten pertsonen beharrei: probatzailea, inplementazioa egiten ari den DevOps injinaria eta zu zeu hemendik bi urtera. Hori errazago lortuko duzu probak eskatutako baldintzak kontuan hartzen baditu eta hiru zatiz osatua badago: + +(1) Zer ari gara probatzen? Adibidez, ProduktuZerbitzua.gehituProduktuBerria funtzioa + +(2) Zein egoera eta agertokitan? Adibidez, ez zaio preziorik pasatzen funtzioari + +(3) Zein da espero den emaitza? Adibidez, produktu berria ez dago onartua + +

+ +### Kode adibidea: 3 zati dituen proba izena + +```javascript +//1. unitatea frogapean +describe('Produktu Zerbitzua', () => { + describe('Produktu berria gehitu', () => { + //2. kasua eta 3. esperotakoa + it('Prezioa zehaztuta ez dagoenean, produktuaren egoera baieztapenaren zai dago', () => { + const produktuBerria = new ProduktuZerbitzua().gehitu(...); + expect(produktuBerria.egoera).to.equal('baieztapenarenZai'); + }); + }); +}); +``` + +

+ +### Kode adibidea, anti eredua: norberak proba osoaren kodea irakurri behar du eta asmoa ulertu +```javascript +describe('Produktu Zerbitzua', () => { + describe('Produktu berria gehitu', () => { + it('Egoera zuzena itzuli behar du', () => { + //mmm, zer egiaztatzen ari da proba hau? zein da kasua eta espero dena? + const produktuBerria = new ProduktuZerbitzua().gehitu(...); + expect(produktuBerria.egoera).to.equal('baieztapenarenZai'); + }); + }); +}); +``` + +

+ +### "Zuzen egiteko adibidea: proben txostenak dokumentuaren baldintzak biltzen ditu" + +["30 Node.jsen proba jardunbide egokiak" blogetik hartua, Yoni Goldbergen eskutik](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347) + +![Proba txostenaren adibidea](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/test-report-like-requirements.jpeg "Proba txostenaren adibidea") + +

diff --git a/sections/testingandquality/aaa.basque.md b/sections/testingandquality/aaa.basque.md new file mode 100644 index 00000000..a981f29b --- /dev/null +++ b/sections/testingandquality/aaa.basque.md @@ -0,0 +1,69 @@ +# Egitura probak AAA ereduaren arabera + +

+ +### Azalpen Paragrafoa + +Probak egiterakoan daukagun erronka handiena memoriako espazio falta da, dagoeneko ekoizpen kodeak oso lanpetuta gauzka. Horregatik, proben kodeak sinplea eta ulergarria izan behar du. Probak irakurtzean, ez luke eman beharko kode inperatiboa irakurtzen ari zarela (begiztak, oinordetza), HTML moduan, esperientzia deklaratibo bat baizik. Hori lortzeko, erabili AAA eredua, irakurtzaileek probaren asmoa esfortzu gabe uler dezaten. Badaude hori bezalako beste eredu batzuk ere, adibidez: XUnit 'Prestatu, Aritu, Egiaztatu eta Eraitsi' ('Setup, Excercise, Verify, Teardown'). Hauek dira hiru Ak: + +Lehenengo A, prestatu (Arrange): hau da, prestatu kodea lortzeko sistema jartzea probak simulatu nahi duen egoeran. Horrek, besteak beste, eraikitzailearen unitate proba egitea eska lezake, datu basean erregistroak gehitzea, objektuak mock/stub eta beste edozein prestakuntza kode eranstea + +Bigarren A, jokatu: exekutatu zure unitate proba. Normalean kode ilara bat izaten da + +Hirugarren A, baieztatu: ziurtatu jasotako balioak espero ziren modukoak direla. Normalean kode ilara bat izaten da +

+ +### Kode adibidea: AAA ereduaz egituratutako proba bat + +```javascript +describe.skip("Bezero klasifikatzailea", () => { + test("Bezeroak 500$ baino gehiago gastatzen dituenean, premium gisa kasifikatua izan behar da", () => { + //Prestatu + const klasifikatzekoBezeroa = { gastatuak: 505, sortua: new Date(), id: 1 }; + const DBAntzeratua = sinon + .stub(dataAccess, "berreskuratuBezeroa") + .reply({ id: 1, klasifikazioa: "arrunta" }); + + //Jokatu + const jasotakoKlasifikazioa = bezeroKlasifikatzailea.klasifikatuBezeroa( + klasifikatzekoBezeroa + ); + + //Baieztatu + expect(jasotakoKlasifikazioa).toMatch("premium"); + }); +}); +``` + +

+ +### Kode adibidea, anti eredua: bereizketarik ez, bloke bakarra, ulertzeko zailagoa + +```javascript +test("Premium gisa klasifikatua izan beharko litzateke", () => { + const klasifikatzekoBezeroa = { gastatuak: 505, sortua: new Date(), id: 1 }; + const DBAntzeratua = sinon + .stub(dataAccess, "berreskuratuBezeroa") + .reply({ id: 1, klasifikazioa: "arrunta" }); + const jasotakoKlasifikazioa = bezeroKlasifikatzailea.klasifikatuBezeroa( + klasifikatzekoBezeroa + ); + expect(jasotakoKlasifikazioa).toMatch("premium"); +}); +``` + +

+ +### "Erabili 6 zati proba bakoitzean" + +["30 Node.jsen proba jarraibide egokiak" blogetik hartua, Yoni Goldbergen eskutik](https://medium.com/@me_37286/yoni-goldberg-javascript-nodejs-testing-best-practices-2b98924c9347) + +![Proba txostenaren adibidea](/assets/images/6-parts-in-test.jpg "Proba txostenaren adibidea") + +

+ +### "Garrantzitsua da proba irakurtzen duen pertsonarentzat, probak zein jokaera egiaztatzen duen errez jakitea" + +[XUnit Patterns](http://xunitpatterns.com/Four%20Phase%20Test.html) liburutik: + +> Garrantzitsua da proba irakurtzen duen pertsonarentzat, proba zein jokaera egiaztatzen ari den azkar jakiteko gai izatea. Oso nahasgarria izan daiteke jokaera ugari probaren barruan (SUT) deituak izatea, batzuk SUTaren proba aurreko egoera prestatzeko (instalazioa), beste batzuk SUTa jokatzeko eta beste batzuk SUTaren proba ondorengo egoera egiaztatzeko. Lau faseak modu argian identifikatzeak probaren asmoa ikustea askoz errazago egiten dute diff --git a/sections/testingandquality/avoid-global-test-fixture.basque.md b/sections/testingandquality/avoid-global-test-fixture.basque.md new file mode 100644 index 00000000..3510936a --- /dev/null +++ b/sections/testingandquality/avoid-global-test-fixture.basque.md @@ -0,0 +1,47 @@ +# Saihestu datu globalak, gehitu datuak proba bakoitzeko + +

+ +### Azalpen paragrafoa + +Urrezko proba arauari jarraituz egin proba kasu/eredu sinpleak: proba bakoitzak bere datu baseko ilarak sortu eta erabili behar ditu menpekotasunak ekiditeko eta probaren fluxua ondo ulertzeko. Egia esan, garatzaileek askotan urratzen dute hori, datu baseak betez probak exekutatu aurretik (‘test instalazioa‘ bezala ere ezagutuak), errendimendua hobetzeko xedearekin. Errendimendua gai garrantzitsua izan arren, arindua izan daiteke (adibidez, begiratu Memoria Datu Baseak "Osagarrien probak" atalean), baina proben konplexutasuna da buruko min asko ematen dituen gai, kontutan hartu beharrekoa. Praktikan, sortu proba kasu bakoitza berariaz datu basean beharrezko informazioa gehitzeko eta jokatu bakarrik datu horiekin. Errendimendua arazo larria bihurtzen bada, adostasun orekatua aurki daiteke soilik datuak gehituko dituen proba bat idatziz eta ondoren hori bikoiztuz beste probentzat (adibidez queries) + +

+ +### Kode adibidea: proba bakoitzak bere datu multzoarekin bakarrik egiten du lan + +```javascript +it("Webgune baten izena eguneratzerakoan, baieztapen arrakastatsua izan", async () => { + // probak datu berriak gehitzen ditu eta horiek bakarrik ikutzen ditu + const probapeanDagoenWebgunea = await WebguneZerbitzua.webguneaGehitu({ + izena: "webgunearenEguneraketarenProba", + }); + const izenEguneraketarenEmaitza = await WebguneZerbitzua.izenaAldatu( + probapeanDagoenWebgunea, + "izenBerria" + ); + expect(izenEguneraketarenEmaitza).to.be(true); +}); +``` + +

+ +### Kode adibidea, anti eredua: probak ez dira independenteak eta aurrez konfiguratutako datuak daudela supotzen dute + +```javascript +before(() => { + //webguneak eta admnistrariak gehitu gure datu-basean. Non daude datuak? kanpoan. Kanpo jsonen edo migrazio frameworken batean + await DB.GehituDatuakJsonIturritik('iturria.json'); +}); +it('Webgune baten izena eguneratzerakoan, baieztapen arrakastatsua izan', async () => { + //Badakit 'portal' webgune izena existitzen dela, iturri fitxategietan ikusi dut + const eguneratzekoWebgunea = await WebguneZerbitzua.berreskuratuWebgunearenIzena('Portal'); + const izenEguneraketarenEmaitza = await WebguneZerbitzua.izenaAldatu(eguneratzekoWebgunea, 'izenBerria'); + expect(izenEguneraketarenEmaitza).to.be(true); +}); +it('Webgune izena erabiliaz eskaera egitean, webgune zuzena berreskuratu', async () => { + //Badakit 'portal' webgune izena existitzen dela, iturri fitxategietan ikusi dut + const egiaztatzekoWebgunea = await WebguneZerbitzua.berreskuratuWebguneaIzenarenBidez('Portal'); + expect(egiaztatzekoWebgunea.izena).to.be.equal('Portal'); //Huts egitea! Aurreko probak izena aldatu du :[ +}); +``` diff --git a/sections/testingandquality/citools.basque.md b/sections/testingandquality/citools.basque.md new file mode 100644 index 00000000..647bf29c --- /dev/null +++ b/sections/testingandquality/citools.basque.md @@ -0,0 +1,52 @@ +# Aukeratu arretaz zure IE plataforma + +

+ +### Azalpen paragrafoa + +IEaren mundua [Jenkins](https://jenkins.io/)en malgutasuna versus SaaS hornitzaileen sinpletasunaren arteko lehia izan ohi zen. Jokoa aldatzen ari da, [CircleCI](https://circleci.com/) eta [Travis](https://travis-ci.org/) bezalako SaaS hornitzaileek irtenbide sendoak eskaintzen baitituzte Docker edukiontziak barne, gutxieneko konfigurazio denborarekin Jenkins-ek "soiltasun" segmentuan ere lehiatzen saiatzen den bitartean. Hodeian edozeinek IE irtenbide aberatsa presta dezakeen arren, prozesua xehetasun handiz kontrolatu beharra izanez gero, Jenkins da oraindik ere aukeratutako plataforma. Erabakia askotan IE prozesua zenbateraino pertsonalizatu behar den zehazten du: hodeiko dohaineko hornitzaileek/ doako eta konfiguratutako doako hodei saltzaileek ahalbidetzen dute shell komando pertsonalizatuak, docker irudi pertsonalizatuak, lan fluxu doitua, matrizearen eraikuntzak exekutatzea, eta bestelako funtzionalitate aberats batzuk dituzte. Hala ere, Java bezalako programazio lengoaia formal bat erabiliz azpiegitura kontrolatu edo IE logika programatu nahi izanez gero, Jenkins izan daiteke oraindik aukera. Bestela, aukeratu dohainekoa eta sinplea den hodeko soluzioren bat. + + +

+ +### Kode adibidea: hodeiko IE ezarpen arrunta. .yml fitxategi bakarra besterik ez + +```yaml +version: 2 +jobs: + build: + docker: + - image: circleci/node:4.8.2 + - image: mongo:3.4.4 + steps: + - checkout + - run: + name: Install npm wee + command: npm install + test: + docker: + - image: circleci/node:4.8.2 + - image: mongo:3.4.4 + steps: + - checkout + - run: + name: Test + command: npm test + - run: + name: Generate code coverage + command: './node_modules/.bin/nyc report --reporter=text-lcov' + - store_artifacts: + path: coverage + prefix: coverage + +``` + +### Circle CI: ia zero prestakuntzadun hodeieko IEa + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/circleci.png "API erroreen kudeaketa") + +### Jenkins - IE sofistikatu eta sendoa + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/jenkins_dashboard.png "API erroreen kudeaketa") + +

diff --git a/sections/testingandquality/refactoring.basque.md b/sections/testingandquality/refactoring.basque.md new file mode 100644 index 00000000..608bf346 --- /dev/null +++ b/sections/testingandquality/refactoring.basque.md @@ -0,0 +1,43 @@ +# Berregituratu + +

+ +### Azalpen paragrafoa + +Garapen iteratiboaren fluxuan, berregituratzea prozesu garrantzitsua da. "Kodearen usainak" (kodetze jardunbide okerrak) ezabatzen badituzu –hala nola, Bikoiztutako Kodea, Funtzio Luzeak, Parametro Zerrenda Luzeak-, zure kodea hobetuko duzu, eta mantentzea erreztuko. Analisi estatikoko tresnak erabiltzeak kode usain horiek aurkitzen eta berregiturazio prozesu bat eraikitzen lagunduko dizu. + +Tresna horiek zure IE eraikuntzari gehitzeak kalitatea egiaztatzeko prozesua automatizatzen lagunduko dizu. Zure IEak Sonar edo Code Climate bezalako tresnak integratzen baditu, eraikuntzak huts egingo du kode usainak antzematen baditu, eta egileari arazoa nola konpondu jakinaraziko dio. Analisi estatikoko tresna hauek ESLint bezalako tresnen osagarri izango dira. Linting tresna gehienak fitxategi bakoitzeko indentazioa eta ahaztutako puntu eta komak bezalako kode estiloetan zentratuko dira (hala ere, batzuek funtzio luzeen moduko kode usainak aurkituko dituzte); analisi estatikoko tresnak, berriz, fitxategi bakarreko edo anitzetako kode usainak aurkitzen saiatuko dira (bikoiztutako kodea, analisi konplexitatea, etab.) + +

+ + +### Martin Fowler, ThoughtWorkseko zientzilari burua + + "Berregituratzen - Bizi Den Kodearen Diseinua Hobetzen" liburutik hartuta + + > Berregituratzea, bizi den kodearen diseinua hobetzeko teknika kontrolatua da + +

+ +### Evan Burchard, web garapeneko aholkulari eta idazlea + + "JavaScript Berregituratzen: Kode Okerra Kode Ona Bilakazen" liburutik hartuta + + > Berdin dio zein framework edo "JSen-konpilatzen-du" lengoaia edo liburutegi erabiltzen duzun, erroreak eta errendimendua beti izango dira arazo bat zure JavaScripta pobrea bada + +

+ + ### Adibidea: Funtzio konplexuen analisia CodeClimaterekin (komertziala) + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-complex-methods.PNG "Funtzio konplexuen analisia") + +### Adibidea: Kode analisiaren joerak eta CodeClimaterekin historia (komertziala) + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-climate-history.PNG "Kode analisiaren historia") + +### Adibidea: Kode analisiaren laburpena eta SonarQuberekin joerak (komertziala) + +![alt text](https://github.com/goldbergyoni/nodebestpractices/blob/master/assets/images/codeanalysis-sonarqube-dashboard.PNG "Kode analisiaren historia") + + +

diff --git a/sections/testingandquality/test-middlewares.basque.md b/sections/testingandquality/test-middlewares.basque.md new file mode 100644 index 00000000..71bfeda3 --- /dev/null +++ b/sections/testingandquality/test-middlewares.basque.md @@ -0,0 +1,31 @@ +# Probatu zure middlewareak eurak bakarrik + +

+ +### Azalpen paragrafoa + +Askok middlewarearen probak alde batera uzten dituzte sistemaren zati txiki bat adierazten dutelako eta zuzeneko Express zerbitzaria edukitzea behar dutelako. Bi arrazoi horiek okerrak dira: middlewareak txikiak dira, baina eskaera guztiei edo gehienei eragiten diete, eta erraz probatu daitezke {req,res} JS objektuak berreskuratzen dituzten funtzio huts gisa. Middleware funtzioak probatzeko, norberak funtzioa deitu behar du eta {req,res} objektuekin dagoen elkarrekintza espiatu (spy) ([erabili Sinon adibide gisa](https://www.npmjs.com/package/sinon)), funtzioak ekintza zuzena egin duela ziurtatzeko. [node-mock-http](https://www.npmjs.com/package/node-mocks-http) liburutegia oraindik ere urrutiago doa eta {req,res} objektuak faktorizatzen ditu beraien jokaera espiatuz. Adibidez, res objektuan zehaztutako http estatus bat espero den balioarekin bat datorren baiezta dezake (ikusi beheko adibidea) + + +

+ +### Kode adibidea: probatu zure middlewarea bera bakarrik + +```javascript +//probatu nahi dugun middlewarea +const probapeanDagoenUnitatea = require("./middleware"); +const httpMocks = require("node-mocks-http"); +//Jest sintaxisa, Mochako describe() eta it()en baliokidea +test("Autentikazio goiburu gabeko eskaera, 403 http estatus bat bueltatu beharko luke", () => { + const request = httpMocks.createRequest({ + method: "GET", + url: "/user/42", + headers: { + authentication: "" + } + }); + const erantzuna = httpMocks.createResponse(); + probapeanDagoenUnitatea(request, response); + expect(erantzuna.statusCode).toBe(403); +}); +```